Line data Source code
1 : // Copyright (c) 2012-2013 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 "clientversion.h"
6 : #include "dbwrapper.h"
7 : #include "uint256.h"
8 : #include "random.h"
9 : #include "test/test_pivx.h"
10 :
11 : #include <boost/test/unit_test.hpp>
12 :
13 : // Test if a string consists entirely of null characters
14 0 : bool is_null_key(const std::vector<unsigned char>& key) {
15 0 : bool isnull = true;
16 :
17 0 : for (unsigned int i = 0; i < key.size(); i++)
18 0 : isnull &= (key[i] == '\x00');
19 :
20 0 : return isnull;
21 : }
22 :
23 : BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup)
24 :
25 2 : BOOST_AUTO_TEST_CASE(dbwrapper)
26 : {
27 1 : {
28 1 : fs::path ph = SetDataDir(std::string("dbwrapper"));
29 2 : CDBWrapper dbw(ph, (1 << 20), true, false);
30 1 : char key = 'k';
31 1 : uint256 in = GetRandHash();
32 1 : uint256 res;
33 :
34 2 : BOOST_CHECK(dbw.Write(key, in));
35 2 : BOOST_CHECK(dbw.Read(key, res));
36 3 : BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
37 : }
38 1 : }
39 :
40 3 : BOOST_AUTO_TEST_CASE(dbwrapper_basic_data)
41 : {
42 1 : fs::path ph = SetDataDir(std::string("dbwrapper_basic_data"));
43 2 : CDBWrapper dbw(ph, (1 << 20), false, true);
44 :
45 1 : uint256 res;
46 1 : uint32_t res_uint_32;
47 1 : bool res_bool;
48 :
49 : //Simulate block raw data - "b + block hash"
50 2 : std::string key_block = "b" + InsecureRand256().ToString();
51 :
52 1 : uint256 in_block = InsecureRand256();
53 2 : BOOST_CHECK(dbw.Write(key_block, in_block));
54 2 : BOOST_CHECK(dbw.Read(key_block, res));
55 3 : BOOST_CHECK_EQUAL(res.ToString(), in_block.ToString());
56 :
57 : //Simulate file raw data - "f + file_number"
58 2 : std::string key_file = strprintf("f%04x", InsecureRand32());
59 :
60 1 : uint256 in_file_info = InsecureRand256();
61 2 : BOOST_CHECK(dbw.Write(key_file, in_file_info));
62 2 : BOOST_CHECK(dbw.Read(key_file, res));
63 3 : BOOST_CHECK_EQUAL(res.ToString(), in_file_info.ToString());
64 :
65 : //Simulate transaction raw data - "t + transaction hash"
66 2 : std::string key_transaction = "t" + InsecureRand256().ToString();
67 :
68 1 : uint256 in_transaction = InsecureRand256();
69 2 : BOOST_CHECK(dbw.Write(key_transaction, in_transaction));
70 2 : BOOST_CHECK(dbw.Read(key_transaction, res));
71 3 : BOOST_CHECK_EQUAL(res.ToString(), in_transaction.ToString());
72 :
73 : //Simulate UTXO raw data - "c + transaction hash"
74 2 : std::string key_utxo = "c" + InsecureRand256().ToString();
75 :
76 1 : uint256 in_utxo = InsecureRand256();
77 2 : BOOST_CHECK(dbw.Write(key_utxo, in_utxo));
78 2 : BOOST_CHECK(dbw.Read(key_utxo, res));
79 3 : BOOST_CHECK_EQUAL(res.ToString(), in_utxo.ToString());
80 :
81 : //Simulate last block file number - "l"
82 1 : char key_last_blockfile_number = 'l';
83 1 : uint32_t lastblockfilenumber = InsecureRand32();
84 2 : BOOST_CHECK(dbw.Write(key_last_blockfile_number, lastblockfilenumber));
85 2 : BOOST_CHECK(dbw.Read(key_last_blockfile_number, res_uint_32));
86 1 : BOOST_CHECK_EQUAL(lastblockfilenumber, res_uint_32);
87 :
88 : //Simulate Is Reindexing - "R"
89 1 : char key_IsReindexing = 'R';
90 1 : bool isInReindexing = InsecureRandBool();
91 2 : BOOST_CHECK(dbw.Write(key_IsReindexing, isInReindexing));
92 2 : BOOST_CHECK(dbw.Read(key_IsReindexing, res_bool));
93 1 : BOOST_CHECK_EQUAL(isInReindexing, res_bool);
94 :
95 : //Simulate last block hash up to which UXTO covers - 'B'
96 1 : char key_lastblockhash_uxto = 'B';
97 1 : uint256 lastblock_hash = InsecureRand256();
98 2 : BOOST_CHECK(dbw.Write(key_lastblockhash_uxto, lastblock_hash));
99 2 : BOOST_CHECK(dbw.Read(key_lastblockhash_uxto, res));
100 1 : BOOST_CHECK_EQUAL(lastblock_hash, res);
101 :
102 : //Simulate file raw data - "F + filename_number + filename"
103 2 : std::string file_option_tag = "F";
104 1 : uint8_t filename_length = InsecureRandBits(8);
105 2 : std::string filename = "randomfilename";
106 2 : std::string key_file_option = strprintf("%s%01x%s", file_option_tag,filename_length,filename);
107 :
108 1 : bool in_file_bool = InsecureRandBool();
109 2 : BOOST_CHECK(dbw.Write(key_file_option, in_file_bool));
110 2 : BOOST_CHECK(dbw.Read(key_file_option, res_bool));
111 1 : BOOST_CHECK_EQUAL(res_bool, in_file_bool);
112 1 : }
113 :
114 : // Test batch operations
115 2 : BOOST_AUTO_TEST_CASE(dbwrapper_batch)
116 : {
117 1 : {
118 1 : fs::path ph = SetDataDir(std::string("dbwrapper_batch"));
119 2 : CDBWrapper dbw(ph, (1 << 20), true, false);
120 :
121 1 : char key = 'i';
122 1 : uint256 in = GetRandHash();
123 1 : char key2 = 'j';
124 1 : uint256 in2 = GetRandHash();
125 1 : char key3 = 'k';
126 1 : uint256 in3 = GetRandHash();
127 :
128 1 : uint256 res;
129 2 : CDBBatch batch(CLIENT_VERSION);
130 :
131 1 : batch.Write(key, in);
132 1 : batch.Write(key2, in2);
133 1 : batch.Write(key3, in3);
134 :
135 : // Remove key3 before it's even been written
136 1 : batch.Erase(key3);
137 :
138 1 : dbw.WriteBatch(batch);
139 :
140 2 : BOOST_CHECK(dbw.Read(key, res));
141 3 : BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
142 2 : BOOST_CHECK(dbw.Read(key2, res));
143 3 : BOOST_CHECK_EQUAL(res.ToString(), in2.ToString());
144 :
145 : // key3 never should've been written
146 2 : BOOST_CHECK(dbw.Read(key3, res) == false);
147 : }
148 1 : }
149 :
150 2 : BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
151 : {
152 1 : {
153 1 : fs::path ph = SetDataDir(std::string("dbwrapper_iterator"));
154 2 : CDBWrapper dbw(ph, (1 << 20), true, false);
155 :
156 : // The two keys are intentionally chosen for ordering
157 1 : char key = 'j';
158 1 : uint256 in = GetRandHash();
159 2 : BOOST_CHECK(dbw.Write(key, in));
160 1 : char key2 = 'k';
161 1 : uint256 in2 = GetRandHash();
162 2 : BOOST_CHECK(dbw.Write(key2, in2));
163 :
164 2 : std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());
165 :
166 : // Be sure to seek past any earlier key (if it exists)
167 1 : it->Seek(key);
168 :
169 1 : char key_res;
170 1 : uint256 val_res;
171 :
172 1 : it->GetKey(key_res);
173 1 : it->GetValue(val_res);
174 1 : BOOST_CHECK_EQUAL(key_res, key);
175 3 : BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString());
176 :
177 1 : it->Next();
178 :
179 1 : it->GetKey(key_res);
180 1 : it->GetValue(val_res);
181 1 : BOOST_CHECK_EQUAL(key_res, key2);
182 3 : BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString());
183 :
184 1 : it->Next();
185 1 : BOOST_CHECK_EQUAL(it->Valid(), false);
186 : }
187 1 : }
188 :
189 2 : BOOST_AUTO_TEST_CASE(iterator_ordering)
190 : {
191 1 : fs::path ph = SetDataDir(std::string("iterator_ordering"));
192 2 : CDBWrapper dbw(ph, (1 << 20), true, false);
193 257 : for (int x=0x00; x<256; ++x) {
194 256 : uint8_t key = x;
195 256 : uint32_t value = x*x;
196 384 : if (!(x & 1)) BOOST_CHECK(dbw.Write(key, value));
197 : }
198 :
199 : // Check that creating an iterator creates a snapshot
200 2 : std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());
201 :
202 257 : for (int x=0x00; x<256; ++x) {
203 256 : uint8_t key = x;
204 256 : uint32_t value = x*x;
205 384 : if (x & 1) BOOST_CHECK(dbw.Write(key, value));
206 : }
207 :
208 3 : for (int seek_start : {0x00, 0x80}) {
209 2 : it->Seek((uint8_t)seek_start);
210 384 : for (int x=seek_start; x<255; ++x) {
211 382 : uint8_t key;
212 382 : uint32_t value;
213 764 : BOOST_CHECK(it->Valid());
214 382 : if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
215 : break;
216 764 : BOOST_CHECK(it->GetKey(key));
217 382 : if (x & 1) {
218 190 : BOOST_CHECK_EQUAL(key, x + 1);
219 190 : continue;
220 : }
221 384 : BOOST_CHECK(it->GetValue(value));
222 192 : BOOST_CHECK_EQUAL(key, x);
223 192 : BOOST_CHECK_EQUAL(value, x*x);
224 192 : it->Next();
225 : }
226 4 : BOOST_CHECK(!it->Valid());
227 : }
228 1 : }
229 :
230 252 : struct StringContentsSerializer {
231 : // Used to make two serialized objects the same while letting them have a different lengths
232 : // This is a terrible idea
233 : std::string str;
234 150 : StringContentsSerializer() {}
235 102 : explicit StringContentsSerializer(const std::string& inp) : str(inp) {}
236 :
237 450 : StringContentsSerializer& operator+=(const std::string& s) {
238 900 : str += s;
239 450 : return *this;
240 : }
241 900 : StringContentsSerializer& operator+=(const StringContentsSerializer& s) { return *this += s.str; }
242 :
243 : template<typename Stream>
244 102 : void Serialize(Stream& s) const
245 : {
246 10334 : for (size_t i = 0; i < str.size(); i++) {
247 10232 : s << str[i];
248 : }
249 102 : }
250 :
251 : template<typename Stream>
252 150 : void Unserialize(Stream& s)
253 : {
254 150 : str.clear();
255 150 : char c = 0;
256 : while (true) {
257 : try {
258 15345 : s >> c;
259 15345 : str.push_back(c);
260 150 : } catch (const std::ios_base::failure&) {
261 : break;
262 : }
263 : }
264 150 : }
265 : };
266 :
267 2 : BOOST_AUTO_TEST_CASE(iterator_string_ordering)
268 : {
269 1 : char buf[10];
270 :
271 1 : fs::path ph = SetDataDir(std::string("iterator_string_ordering"));
272 2 : CDBWrapper dbw(ph, (1 << 20), true, false);
273 11 : for (int x=0x00; x<10; ++x) {
274 110 : for (int y = 0; y < 10; y++) {
275 100 : snprintf(buf, sizeof(buf), "%d", x);
276 300 : StringContentsSerializer key(buf);
277 550 : for (int z = 0; z < y; z++)
278 450 : key += key;
279 100 : uint32_t value = x*x;
280 200 : BOOST_CHECK(dbw.Write(key, value));
281 : }
282 : }
283 :
284 2 : boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
285 3 : for (int c=0; c<2; ++c) {
286 2 : int seek_start;
287 2 : if (c == 0)
288 : seek_start = 0;
289 : else
290 1 : seek_start = 5;
291 2 : snprintf(buf, sizeof(buf), "%d", seek_start);
292 6 : StringContentsSerializer seek_key(buf);
293 2 : it->Seek(seek_key);
294 17 : for (int x=seek_start; x<10; ++x) {
295 165 : for (int y = 0; y < 10; y++) {
296 150 : snprintf(buf, sizeof(buf), "%d", x);
297 300 : std::string exp_key(buf);
298 825 : for (int z = 0; z < y; z++)
299 675 : exp_key += exp_key;
300 300 : StringContentsSerializer key;
301 150 : uint32_t value;
302 300 : BOOST_CHECK(it->Valid());
303 150 : if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
304 : break;
305 300 : BOOST_CHECK(it->GetKey(key));
306 300 : BOOST_CHECK(it->GetValue(value));
307 150 : BOOST_CHECK_EQUAL(key.str, exp_key);
308 150 : BOOST_CHECK_EQUAL(value, x*x);
309 150 : it->Next();
310 : }
311 : }
312 4 : BOOST_CHECK(!it->Valid());
313 : }
314 1 : }
315 :
316 :
317 :
318 : BOOST_AUTO_TEST_SUITE_END()
|