Fabcoin Core  0.16.2
P2P Digital Currency
dbwrapper.cpp
Go to the documentation of this file.
1 // Copyright (c) 2012-2017 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <dbwrapper.h>
6 
7 #include <fs.h>
8 #include <util.h>
9 #include <random.h>
10 
11 #include <leveldb/cache.h>
12 #include <leveldb/env.h>
13 #include <leveldb/filter_policy.h>
14 #include <memenv.h>
15 #include <stdint.h>
16 #include <algorithm>
17 
18 class CFabcoinLevelDBLogger : public leveldb::Logger {
19 public:
20  // This code is adapted from posix_logger.h, which is why it is using vsprintf.
21  // Please do not do this in normal code
22  virtual void Logv(const char * format, va_list ap) override {
23  if (!LogAcceptCategory(BCLog::LEVELDB)) {
24  return;
25  }
26  char buffer[500];
27  for (int iter = 0; iter < 2; iter++) {
28  char* base;
29  int bufsize;
30  if (iter == 0) {
31  bufsize = sizeof(buffer);
32  base = buffer;
33  }
34  else {
35  bufsize = 30000;
36  base = new char[bufsize];
37  }
38  char* p = base;
39  char* limit = base + bufsize;
40 
41  // Print the message
42  if (p < limit) {
43  va_list backup_ap;
44  va_copy(backup_ap, ap);
45  // Do not use vsnprintf elsewhere in fabcoin source code, see above.
46  p += vsnprintf(p, limit - p, format, backup_ap);
47  va_end(backup_ap);
48  }
49 
50  // Truncate to available space if necessary
51  if (p >= limit) {
52  if (iter == 0) {
53  continue; // Try again with larger buffer
54  }
55  else {
56  p = limit - 1;
57  }
58  }
59 
60  // Add newline if necessary
61  if (p == base || p[-1] != '\n') {
62  *p++ = '\n';
63  }
64 
65  assert(p <= limit);
66  base[std::min(bufsize - 1, (int)(p - base))] = '\0';
67  LogPrintStr(base);
68  if (base != buffer) {
69  delete[] base;
70  }
71  break;
72  }
73  }
74 };
75 
76 static leveldb::Options GetOptions(size_t nCacheSize)
77 {
78  leveldb::Options options;
79  options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
80  options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously
81  options.filter_policy = leveldb::NewBloomFilterPolicy(10);
82  options.compression = leveldb::kNoCompression;
83  options.max_open_files = 64;
84  options.info_log = new CFabcoinLevelDBLogger();
85  if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
86  // LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error
87  // on corruption in later versions.
88  options.paranoid_checks = true;
89  }
90  return options;
91 }
92 
93 CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
94 {
95  penv = nullptr;
96  readoptions.verify_checksums = true;
97  iteroptions.verify_checksums = true;
98  iteroptions.fill_cache = false;
99  syncoptions.sync = true;
100  options = GetOptions(nCacheSize);
101  options.create_if_missing = true;
102  if (fMemory) {
103  penv = leveldb::NewMemEnv(leveldb::Env::Default());
104  options.env = penv;
105  } else {
106  if (fWipe) {
107  LogPrintf("Wiping LevelDB in %s\n", path.string());
108  leveldb::Status result = leveldb::DestroyDB(path.string(), options);
110  }
111  TryCreateDirectories(path);
112  LogPrintf("Opening LevelDB in %s\n", path.string());
113  }
114  leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb);
116  LogPrintf("Opened LevelDB successfully\n");
117 
118  if (gArgs.GetBoolArg("-forcecompactdb", false)) {
119  LogPrintf("Starting database compaction of %s\n", path.string());
120  pdb->CompactRange(nullptr, nullptr);
121  LogPrintf("Finished database compaction of %s\n", path.string());
122  }
123 
124  // The base-case obfuscation key, which is a noop.
125  obfuscate_key = std::vector<unsigned char>(OBFUSCATE_KEY_NUM_BYTES, '\000');
126 
127  bool key_exists = Read(OBFUSCATE_KEY_KEY, obfuscate_key);
128 
129  if (!key_exists && obfuscate && IsEmpty()) {
130  // Initialize non-degenerate obfuscation if it won't upset
131  // existing, non-obfuscated data.
132  std::vector<unsigned char> new_key = CreateObfuscateKey();
133 
134  // Write `new_key` so we don't obfuscate the key with itself
135  Write(OBFUSCATE_KEY_KEY, new_key);
136  obfuscate_key = new_key;
137 
138  LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), HexStr(obfuscate_key));
139  }
140 
141  LogPrintf("Using obfuscation key for %s: %s\n", path.string(), HexStr(obfuscate_key));
142 }
143 
145 {
146  delete pdb;
147  pdb = nullptr;
148  delete options.filter_policy;
149  options.filter_policy = nullptr;
150  delete options.info_log;
151  options.info_log = nullptr;
152  delete options.block_cache;
153  options.block_cache = nullptr;
154  delete penv;
155  options.env = nullptr;
156 }
157 
158 bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
159 {
160  leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);
162  return true;
163 }
164 
165 // Prefixed with null character to avoid collisions with other keys
166 //
167 // We must use a string constructor which specifies length so that we copy
168 // past the null-terminator.
169 const std::string CDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14);
170 
171 const unsigned int CDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8;
172 
177 std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const
178 {
179  unsigned char buff[OBFUSCATE_KEY_NUM_BYTES];
180  GetRandBytes(buff, OBFUSCATE_KEY_NUM_BYTES);
181  return std::vector<unsigned char>(&buff[0], &buff[OBFUSCATE_KEY_NUM_BYTES]);
182 
183 }
184 
186 {
187  std::unique_ptr<CDBIterator> it(NewIterator());
188  it->SeekToFirst();
189  return !(it->Valid());
190 }
191 
192 CDBIterator::~CDBIterator() { delete piter; }
193 bool CDBIterator::Valid() { return piter->Valid(); }
194 void CDBIterator::SeekToFirst() { piter->SeekToFirst(); }
195 void CDBIterator::Next() { piter->Next(); }
196 
197 namespace dbwrapper_private {
198 
199 void HandleError(const leveldb::Status& status)
200 {
201  if (status.ok())
202  return;
203  LogPrintf("%s\n", status.ToString());
204  if (status.IsCorruption())
205  throw dbwrapper_error("Database corrupted");
206  if (status.IsIOError())
207  throw dbwrapper_error("Database I/O error");
208  if (status.IsNotFound())
209  throw dbwrapper_error("Database entry missing");
210  throw dbwrapper_error("Unknown database error");
211 }
212 
213 const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w)
214 {
215  return w.obfuscate_key;
216 }
217 
218 } // namespace dbwrapper_private
These should be considered an implementation detail of the specific database.
Definition: dbwrapper.cpp:197
void SeekToFirst()
Definition: dbwrapper.cpp:194
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:47
CDBWrapper(const fs::path &path, size_t nCacheSize, bool fMemory=false, bool fWipe=false, bool obfuscate=false)
Definition: dbwrapper.cpp:93
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
bool GetBoolArg(const std::string &strArg, bool fDefault)
Return boolean argument or default value.
Definition: util.cpp:520
assert(len-trim+(2 *lenIndices)<=WIDTH)
void HandleError(const leveldb::Status &status)
Handle database error by throwing dbwrapper_error exception.
Definition: dbwrapper.cpp:199
ExecStats::duration min
Definition: ExecStats.cpp:35
leveldb::WriteBatch batch
Definition: dbwrapper.h:53
std::vector< unsigned char > CreateObfuscateKey() const
Returns a string (consisting of 8 random bytes) suitable for use as an obfuscating XOR key...
Definition: dbwrapper.cpp:177
virtual void Logv(const char *format, va_list ap) override
Definition: dbwrapper.cpp:22
#define LogPrintf(...)
Definition: util.h:153
bool Valid()
Definition: dbwrapper.cpp:193
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by Boost&#39;s create_directories if the requested directory exists...
Definition: util.cpp:730
bool IsEmpty()
Return true if the database managed by this class contains no entries.
Definition: dbwrapper.cpp:185
const std::vector< unsigned char > & GetObfuscateKey(const CDBWrapper &w)
Work around circular dependency, as well as for testing in dbwrapper_tests.
Definition: dbwrapper.cpp:213
void Next()
Definition: dbwrapper.cpp:195
static const unsigned int OBFUSCATE_KEY_NUM_BYTES
the length of the obfuscate key in number of bytes
Definition: dbwrapper.h:208
ArgsManager gArgs
Definition: util.cpp:94
static const std::string OBFUSCATE_KEY_KEY
the key under which the obfuscation key is stored
Definition: dbwrapper.h:205
int LogPrintStr(const std::string &str, bool useVMLog)
Send a string to the log output.
Definition: util.cpp:388
void GetRandBytes(unsigned char *buf, int num)
Functions to gather random data via the OpenSSL PRNG.
Definition: random.cpp:273
bool WriteBatch(CDBBatch &batch, bool fSync=false)
Definition: dbwrapper.cpp:158
uint8_t format
std::vector< unsigned char > obfuscate_key
a key used for optional XOR-obfuscation of the database
Definition: dbwrapper.h:202