Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

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