Bitcoin Core  22.99.0
P2P Digital Currency
dbwrapper_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2012-2020 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>
7 #include <uint256.h>
8 
9 #include <memory>
10 
11 #include <boost/test/unit_test.hpp>
12 
13 // Test if a string consists entirely of null characters
14 static bool is_null_key(const std::vector<unsigned char>& key) {
15  bool isnull = true;
16 
17  for (unsigned int i = 0; i < key.size(); i++)
18  isnull &= (key[i] == '\x00');
19 
20  return isnull;
21 }
22 
24 
26 {
27  // Perform tests both obfuscated and non-obfuscated.
28  for (const bool obfuscate : {false, true}) {
29  fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false");
30  CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
31  uint8_t key{'k'};
32  uint256 in = InsecureRand256();
33  uint256 res;
34 
35  // Ensure that we're doing real obfuscation when obfuscate=true
37 
38  BOOST_CHECK(dbw.Write(key, in));
39  BOOST_CHECK(dbw.Read(key, res));
40  BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
41  }
42 }
43 
44 BOOST_AUTO_TEST_CASE(dbwrapper_basic_data)
45 {
46  // Perform tests both obfuscated and non-obfuscated.
47  for (bool obfuscate : {false, true}) {
48  fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_1_obfuscate_true" : "dbwrapper_1_obfuscate_false");
49  CDBWrapper dbw(ph, (1 << 20), false, true, obfuscate);
50 
51  uint256 res;
52  uint32_t res_uint_32;
53  bool res_bool;
54 
55  // Ensure that we're doing real obfuscation when obfuscate=true
57 
58  //Simulate block raw data - "b + block hash"
59  std::string key_block = "b" + InsecureRand256().ToString();
60 
61  uint256 in_block = InsecureRand256();
62  BOOST_CHECK(dbw.Write(key_block, in_block));
63  BOOST_CHECK(dbw.Read(key_block, res));
64  BOOST_CHECK_EQUAL(res.ToString(), in_block.ToString());
65 
66  //Simulate file raw data - "f + file_number"
67  std::string key_file = strprintf("f%04x", InsecureRand32());
68 
69  uint256 in_file_info = InsecureRand256();
70  BOOST_CHECK(dbw.Write(key_file, in_file_info));
71  BOOST_CHECK(dbw.Read(key_file, res));
72  BOOST_CHECK_EQUAL(res.ToString(), in_file_info.ToString());
73 
74  //Simulate transaction raw data - "t + transaction hash"
75  std::string key_transaction = "t" + InsecureRand256().ToString();
76 
77  uint256 in_transaction = InsecureRand256();
78  BOOST_CHECK(dbw.Write(key_transaction, in_transaction));
79  BOOST_CHECK(dbw.Read(key_transaction, res));
80  BOOST_CHECK_EQUAL(res.ToString(), in_transaction.ToString());
81 
82  //Simulate UTXO raw data - "c + transaction hash"
83  std::string key_utxo = "c" + InsecureRand256().ToString();
84 
85  uint256 in_utxo = InsecureRand256();
86  BOOST_CHECK(dbw.Write(key_utxo, in_utxo));
87  BOOST_CHECK(dbw.Read(key_utxo, res));
88  BOOST_CHECK_EQUAL(res.ToString(), in_utxo.ToString());
89 
90  //Simulate last block file number - "l"
91  uint8_t key_last_blockfile_number{'l'};
92  uint32_t lastblockfilenumber = InsecureRand32();
93  BOOST_CHECK(dbw.Write(key_last_blockfile_number, lastblockfilenumber));
94  BOOST_CHECK(dbw.Read(key_last_blockfile_number, res_uint_32));
95  BOOST_CHECK_EQUAL(lastblockfilenumber, res_uint_32);
96 
97  //Simulate Is Reindexing - "R"
98  uint8_t key_IsReindexing{'R'};
99  bool isInReindexing = InsecureRandBool();
100  BOOST_CHECK(dbw.Write(key_IsReindexing, isInReindexing));
101  BOOST_CHECK(dbw.Read(key_IsReindexing, res_bool));
102  BOOST_CHECK_EQUAL(isInReindexing, res_bool);
103 
104  //Simulate last block hash up to which UXTO covers - 'B'
105  uint8_t key_lastblockhash_uxto{'B'};
106  uint256 lastblock_hash = InsecureRand256();
107  BOOST_CHECK(dbw.Write(key_lastblockhash_uxto, lastblock_hash));
108  BOOST_CHECK(dbw.Read(key_lastblockhash_uxto, res));
109  BOOST_CHECK_EQUAL(lastblock_hash, res);
110 
111  //Simulate file raw data - "F + filename_number + filename"
112  std::string file_option_tag = "F";
113  uint8_t filename_length = InsecureRandBits(8);
114  std::string filename = "randomfilename";
115  std::string key_file_option = strprintf("%s%01x%s", file_option_tag,filename_length,filename);
116 
117  bool in_file_bool = InsecureRandBool();
118  BOOST_CHECK(dbw.Write(key_file_option, in_file_bool));
119  BOOST_CHECK(dbw.Read(key_file_option, res_bool));
120  BOOST_CHECK_EQUAL(res_bool, in_file_bool);
121  }
122 }
123 
124 // Test batch operations
125 BOOST_AUTO_TEST_CASE(dbwrapper_batch)
126 {
127  // Perform tests both obfuscated and non-obfuscated.
128  for (const bool obfuscate : {false, true}) {
129  fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_batch_obfuscate_true" : "dbwrapper_batch_obfuscate_false");
130  CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
131 
132  uint8_t key{'i'};
133  uint256 in = InsecureRand256();
134  uint8_t key2{'j'};
135  uint256 in2 = InsecureRand256();
136  uint8_t key3{'k'};
137  uint256 in3 = InsecureRand256();
138 
139  uint256 res;
140  CDBBatch batch(dbw);
141 
142  batch.Write(key, in);
143  batch.Write(key2, in2);
144  batch.Write(key3, in3);
145 
146  // Remove key3 before it's even been written
147  batch.Erase(key3);
148 
149  BOOST_CHECK(dbw.WriteBatch(batch));
150 
151  BOOST_CHECK(dbw.Read(key, res));
152  BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
153  BOOST_CHECK(dbw.Read(key2, res));
154  BOOST_CHECK_EQUAL(res.ToString(), in2.ToString());
155 
156  // key3 should've never been written
157  BOOST_CHECK(dbw.Read(key3, res) == false);
158  }
159 }
160 
161 BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
162 {
163  // Perform tests both obfuscated and non-obfuscated.
164  for (const bool obfuscate : {false, true}) {
165  fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false");
166  CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
167 
168  // The two keys are intentionally chosen for ordering
169  uint8_t key{'j'};
170  uint256 in = InsecureRand256();
171  BOOST_CHECK(dbw.Write(key, in));
172  uint8_t key2{'k'};
173  uint256 in2 = InsecureRand256();
174  BOOST_CHECK(dbw.Write(key2, in2));
175 
176  std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());
177 
178  // Be sure to seek past the obfuscation key (if it exists)
179  it->Seek(key);
180 
181  uint8_t key_res;
182  uint256 val_res;
183 
184  BOOST_REQUIRE(it->GetKey(key_res));
185  BOOST_REQUIRE(it->GetValue(val_res));
186  BOOST_CHECK_EQUAL(key_res, key);
187  BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString());
188 
189  it->Next();
190 
191  BOOST_REQUIRE(it->GetKey(key_res));
192  BOOST_REQUIRE(it->GetValue(val_res));
193  BOOST_CHECK_EQUAL(key_res, key2);
194  BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString());
195 
196  it->Next();
197  BOOST_CHECK_EQUAL(it->Valid(), false);
198  }
199 }
200 
201 // Test that we do not obfuscation if there is existing data.
202 BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
203 {
204  // We're going to share this fs::path between two wrappers
205  fs::path ph = m_args.GetDataDirBase() / "existing_data_no_obfuscate";
206  create_directories(ph);
207 
208  // Set up a non-obfuscated wrapper to write some initial data.
209  std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(ph, (1 << 10), false, false, false);
210  uint8_t key{'k'};
211  uint256 in = InsecureRand256();
212  uint256 res;
213 
214  BOOST_CHECK(dbw->Write(key, in));
215  BOOST_CHECK(dbw->Read(key, res));
216  BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
217 
218  // Call the destructor to free leveldb LOCK
219  dbw.reset();
220 
221  // Now, set up another wrapper that wants to obfuscate the same directory
222  CDBWrapper odbw(ph, (1 << 10), false, false, true);
223 
224  // Check that the key/val we wrote with unobfuscated wrapper exists and
225  // is readable.
226  uint256 res2;
227  BOOST_CHECK(odbw.Read(key, res2));
228  BOOST_CHECK_EQUAL(res2.ToString(), in.ToString());
229 
230  BOOST_CHECK(!odbw.IsEmpty()); // There should be existing data
231  BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); // The key should be an empty string
232 
233  uint256 in2 = InsecureRand256();
234  uint256 res3;
235 
236  // Check that we can write successfully
237  BOOST_CHECK(odbw.Write(key, in2));
238  BOOST_CHECK(odbw.Read(key, res3));
239  BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString());
240 }
241 
242 // Ensure that we start obfuscating during a reindex.
243 BOOST_AUTO_TEST_CASE(existing_data_reindex)
244 {
245  // We're going to share this fs::path between two wrappers
246  fs::path ph = m_args.GetDataDirBase() / "existing_data_reindex";
247  create_directories(ph);
248 
249  // Set up a non-obfuscated wrapper to write some initial data.
250  std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(ph, (1 << 10), false, false, false);
251  uint8_t key{'k'};
252  uint256 in = InsecureRand256();
253  uint256 res;
254 
255  BOOST_CHECK(dbw->Write(key, in));
256  BOOST_CHECK(dbw->Read(key, res));
257  BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
258 
259  // Call the destructor to free leveldb LOCK
260  dbw.reset();
261 
262  // Simulate a -reindex by wiping the existing data store
263  CDBWrapper odbw(ph, (1 << 10), false, true, true);
264 
265  // Check that the key/val we wrote with unobfuscated wrapper doesn't exist
266  uint256 res2;
267  BOOST_CHECK(!odbw.Read(key, res2));
269 
270  uint256 in2 = InsecureRand256();
271  uint256 res3;
272 
273  // Check that we can write successfully
274  BOOST_CHECK(odbw.Write(key, in2));
275  BOOST_CHECK(odbw.Read(key, res3));
276  BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString());
277 }
278 
279 BOOST_AUTO_TEST_CASE(iterator_ordering)
280 {
281  fs::path ph = m_args.GetDataDirBase() / "iterator_ordering";
282  CDBWrapper dbw(ph, (1 << 20), true, false, false);
283  for (int x=0x00; x<256; ++x) {
284  uint8_t key = x;
285  uint32_t value = x*x;
286  if (!(x & 1)) BOOST_CHECK(dbw.Write(key, value));
287  }
288 
289  // Check that creating an iterator creates a snapshot
290  std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());
291 
292  for (unsigned int x=0x00; x<256; ++x) {
293  uint8_t key = x;
294  uint32_t value = x*x;
295  if (x & 1) BOOST_CHECK(dbw.Write(key, value));
296  }
297 
298  for (const int seek_start : {0x00, 0x80}) {
299  it->Seek((uint8_t)seek_start);
300  for (unsigned int x=seek_start; x<255; ++x) {
301  uint8_t key;
302  uint32_t value;
303  BOOST_CHECK(it->Valid());
304  if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
305  break;
306  BOOST_CHECK(it->GetKey(key));
307  if (x & 1) {
308  BOOST_CHECK_EQUAL(key, x + 1);
309  continue;
310  }
311  BOOST_CHECK(it->GetValue(value));
312  BOOST_CHECK_EQUAL(key, x);
313  BOOST_CHECK_EQUAL(value, x*x);
314  it->Next();
315  }
316  BOOST_CHECK(!it->Valid());
317  }
318 }
319 
321  // Used to make two serialized objects the same while letting them have different lengths
322  // This is a terrible idea
323  std::string str;
325  explicit StringContentsSerializer(const std::string& inp) : str(inp) {}
326 
327  StringContentsSerializer& operator+=(const std::string& s) {
328  str += s;
329  return *this;
330  }
332 
333  template<typename Stream>
334  void Serialize(Stream& s) const
335  {
336  for (size_t i = 0; i < str.size(); i++) {
337  s << uint8_t(str[i]);
338  }
339  }
340 
341  template<typename Stream>
342  void Unserialize(Stream& s)
343  {
344  str.clear();
345  uint8_t c{0};
346  while (true) {
347  try {
348  s >> c;
349  str.push_back(c);
350  } catch (const std::ios_base::failure&) {
351  break;
352  }
353  }
354  }
355 };
356 
357 BOOST_AUTO_TEST_CASE(iterator_string_ordering)
358 {
359  char buf[10];
360 
361  fs::path ph = m_args.GetDataDirBase() / "iterator_string_ordering";
362  CDBWrapper dbw(ph, (1 << 20), true, false, false);
363  for (int x=0x00; x<10; ++x) {
364  for (int y = 0; y < 10; y++) {
365  snprintf(buf, sizeof(buf), "%d", x);
366  StringContentsSerializer key(buf);
367  for (int z = 0; z < y; z++)
368  key += key;
369  uint32_t value = x*x;
370  BOOST_CHECK(dbw.Write(key, value));
371  }
372  }
373 
374  std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());
375  for (const int seek_start : {0, 5}) {
376  snprintf(buf, sizeof(buf), "%d", seek_start);
377  StringContentsSerializer seek_key(buf);
378  it->Seek(seek_key);
379  for (unsigned int x=seek_start; x<10; ++x) {
380  for (int y = 0; y < 10; y++) {
381  snprintf(buf, sizeof(buf), "%d", x);
382  std::string exp_key(buf);
383  for (int z = 0; z < y; z++)
384  exp_key += exp_key;
386  uint32_t value;
387  BOOST_CHECK(it->Valid());
388  if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
389  break;
390  BOOST_CHECK(it->GetKey(key));
391  BOOST_CHECK(it->GetValue(value));
392  BOOST_CHECK_EQUAL(key.str, exp_key);
393  BOOST_CHECK_EQUAL(value, x*x);
394  it->Next();
395  }
396  }
397  BOOST_CHECK(!it->Valid());
398  }
399 }
400 
402 {
403  // Attempt to create a database with a UTF8 character in the path.
404  // On Windows this test will fail if the directory is created using
405  // the ANSI CreateDirectoryA call and the code page isn't UTF8.
406  // It will succeed if created with CreateDirectoryW.
407  fs::path ph = m_args.GetDataDirBase() / "test_runner_₿_🏃_20191128_104644";
408  CDBWrapper dbw(ph, (1 << 20));
409 
410  fs::path lockPath = ph / "LOCK";
411  BOOST_CHECK(fs::exists(lockPath));
412 }
413 
414 
StringContentsSerializer::operator+=
StringContentsSerializer & operator+=(const std::string &s)
Definition: dbwrapper_tests.cpp:327
StringContentsSerializer::Serialize
void Serialize(Stream &s) const
Definition: dbwrapper_tests.cpp:334
dbwrapper.h
InsecureRandBool
static bool InsecureRandBool()
Definition: setup_common.h:69
CDBBatch
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:47
setup_common.h
uint256.h
InsecureRand256
static uint256 InsecureRand256()
Definition: setup_common.h:66
InsecureRand32
static uint32_t InsecureRand32()
Definition: setup_common.h:65
StringContentsSerializer::StringContentsSerializer
StringContentsSerializer()
Definition: dbwrapper_tests.cpp:324
CDBWrapper::Read
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:231
BOOST_FIXTURE_TEST_SUITE
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
BOOST_AUTO_TEST_SUITE_END
BOOST_AUTO_TEST_SUITE_END()
CDBBatch::Write
void Write(const K &key, const V &value)
Definition: dbwrapper.h:73
StringContentsSerializer::Unserialize
void Unserialize(Stream &s)
Definition: dbwrapper_tests.cpp:342
BOOST_AUTO_TEST_CASE
BOOST_AUTO_TEST_CASE(dbwrapper)
Definition: dbwrapper_tests.cpp:25
BasicTestingSetup
Basic testing setup.
Definition: setup_common.h:76
base_blob::ToString
std::string ToString() const
Definition: uint256.cpp:64
StringContentsSerializer::str
std::string str
Definition: dbwrapper_tests.cpp:323
uint256
256-bit opaque blob.
Definition: uint256.h:124
StringContentsSerializer::operator+=
StringContentsSerializer & operator+=(const StringContentsSerializer &s)
Definition: dbwrapper_tests.cpp:331
CDBWrapper
Definition: dbwrapper.h:176
strprintf
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
StringContentsSerializer
Definition: dbwrapper_tests.cpp:320
CDBBatch::Erase
void Erase(const K &key)
Definition: dbwrapper.h:98
dbwrapper_private::GetObfuscateKey
const std::vector< unsigned char > & GetObfuscateKey(const CDBWrapper &w)
Work around circular dependency, as well as for testing in dbwrapper_tests.
Definition: dbwrapper.cpp:252
CDBWrapper::IsEmpty
bool IsEmpty()
Return true if the database managed by this class contains no entries.
Definition: dbwrapper.cpp:228
StringContentsSerializer::StringContentsSerializer
StringContentsSerializer(const std::string &inp)
Definition: dbwrapper_tests.cpp:325
is_null_key
static bool is_null_key(const std::vector< unsigned char > &key)
Definition: dbwrapper_tests.cpp:14
InsecureRandBits
static uint64_t InsecureRandBits(int bits)
Definition: setup_common.h:67
CDBWrapper::Write
bool Write(const K &key, const V &value, bool fSync=false)
Definition: dbwrapper.h:257
CDBWrapper::WriteBatch
bool WriteBatch(CDBBatch &batch, bool fSync=false)
Definition: dbwrapper.cpp:183
BOOST_CHECK
#define BOOST_CHECK(expr)
Definition: object.cpp:17
BOOST_CHECK_EQUAL
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18