1 // Copyright (c) 2012-2016 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.
8 #include <test/test_bitcoin.h>
10 #include <boost/test/unit_test.hpp>
12 // Test if a string consists entirely of null characters
13 bool is_null_key(const std::vector
<unsigned char>& key
) {
16 for (unsigned int i
= 0; i
< key
.size(); i
++)
17 isnull
&= (key
[i
] == '\x00');
22 BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests
, BasicTestingSetup
)
24 BOOST_AUTO_TEST_CASE(dbwrapper
)
26 // Perform tests both obfuscated and non-obfuscated.
27 for (bool obfuscate
: {false, true}) {
28 fs::path ph
= fs::temp_directory_path() / fs::unique_path();
29 CDBWrapper
dbw(ph
, (1 << 20), true, false, obfuscate
);
31 uint256 in
= InsecureRand256();
34 // Ensure that we're doing real obfuscation when obfuscate=true
35 BOOST_CHECK(obfuscate
!= is_null_key(dbwrapper_private::GetObfuscateKey(dbw
)));
37 BOOST_CHECK(dbw
.Write(key
, in
));
38 BOOST_CHECK(dbw
.Read(key
, res
));
39 BOOST_CHECK_EQUAL(res
.ToString(), in
.ToString());
43 // Test batch operations
44 BOOST_AUTO_TEST_CASE(dbwrapper_batch
)
46 // Perform tests both obfuscated and non-obfuscated.
47 for (bool obfuscate
: {false, true}) {
48 fs::path ph
= fs::temp_directory_path() / fs::unique_path();
49 CDBWrapper
dbw(ph
, (1 << 20), true, false, obfuscate
);
52 uint256 in
= InsecureRand256();
54 uint256 in2
= InsecureRand256();
56 uint256 in3
= InsecureRand256();
62 batch
.Write(key2
, in2
);
63 batch
.Write(key3
, in3
);
65 // Remove key3 before it's even been written
68 dbw
.WriteBatch(batch
);
70 BOOST_CHECK(dbw
.Read(key
, res
));
71 BOOST_CHECK_EQUAL(res
.ToString(), in
.ToString());
72 BOOST_CHECK(dbw
.Read(key2
, res
));
73 BOOST_CHECK_EQUAL(res
.ToString(), in2
.ToString());
75 // key3 should've never been written
76 BOOST_CHECK(dbw
.Read(key3
, res
) == false);
80 BOOST_AUTO_TEST_CASE(dbwrapper_iterator
)
82 // Perform tests both obfuscated and non-obfuscated.
83 for (bool obfuscate
: {false, true}) {
84 fs::path ph
= fs::temp_directory_path() / fs::unique_path();
85 CDBWrapper
dbw(ph
, (1 << 20), true, false, obfuscate
);
87 // The two keys are intentionally chosen for ordering
89 uint256 in
= InsecureRand256();
90 BOOST_CHECK(dbw
.Write(key
, in
));
92 uint256 in2
= InsecureRand256();
93 BOOST_CHECK(dbw
.Write(key2
, in2
));
95 std::unique_ptr
<CDBIterator
> it(const_cast<CDBWrapper
&>(dbw
).NewIterator());
97 // Be sure to seek past the obfuscation key (if it exists)
104 it
->GetValue(val_res
);
105 BOOST_CHECK_EQUAL(key_res
, key
);
106 BOOST_CHECK_EQUAL(val_res
.ToString(), in
.ToString());
111 it
->GetValue(val_res
);
112 BOOST_CHECK_EQUAL(key_res
, key2
);
113 BOOST_CHECK_EQUAL(val_res
.ToString(), in2
.ToString());
116 BOOST_CHECK_EQUAL(it
->Valid(), false);
120 // Test that we do not obfuscation if there is existing data.
121 BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate
)
123 // We're going to share this fs::path between two wrappers
124 fs::path ph
= fs::temp_directory_path() / fs::unique_path();
125 create_directories(ph
);
127 // Set up a non-obfuscated wrapper to write some initial data.
128 std::unique_ptr
<CDBWrapper
> dbw
= MakeUnique
<CDBWrapper
>(ph
, (1 << 10), false, false, false);
130 uint256 in
= InsecureRand256();
133 BOOST_CHECK(dbw
->Write(key
, in
));
134 BOOST_CHECK(dbw
->Read(key
, res
));
135 BOOST_CHECK_EQUAL(res
.ToString(), in
.ToString());
137 // Call the destructor to free leveldb LOCK
140 // Now, set up another wrapper that wants to obfuscate the same directory
141 CDBWrapper
odbw(ph
, (1 << 10), false, false, true);
143 // Check that the key/val we wrote with unobfuscated wrapper exists and
146 BOOST_CHECK(odbw
.Read(key
, res2
));
147 BOOST_CHECK_EQUAL(res2
.ToString(), in
.ToString());
149 BOOST_CHECK(!odbw
.IsEmpty()); // There should be existing data
150 BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscateKey(odbw
))); // The key should be an empty string
152 uint256 in2
= InsecureRand256();
155 // Check that we can write successfully
156 BOOST_CHECK(odbw
.Write(key
, in2
));
157 BOOST_CHECK(odbw
.Read(key
, res3
));
158 BOOST_CHECK_EQUAL(res3
.ToString(), in2
.ToString());
161 // Ensure that we start obfuscating during a reindex.
162 BOOST_AUTO_TEST_CASE(existing_data_reindex
)
164 // We're going to share this fs::path between two wrappers
165 fs::path ph
= fs::temp_directory_path() / fs::unique_path();
166 create_directories(ph
);
168 // Set up a non-obfuscated wrapper to write some initial data.
169 std::unique_ptr
<CDBWrapper
> dbw
= MakeUnique
<CDBWrapper
>(ph
, (1 << 10), false, false, false);
171 uint256 in
= InsecureRand256();
174 BOOST_CHECK(dbw
->Write(key
, in
));
175 BOOST_CHECK(dbw
->Read(key
, res
));
176 BOOST_CHECK_EQUAL(res
.ToString(), in
.ToString());
178 // Call the destructor to free leveldb LOCK
181 // Simulate a -reindex by wiping the existing data store
182 CDBWrapper
odbw(ph
, (1 << 10), false, true, true);
184 // Check that the key/val we wrote with unobfuscated wrapper doesn't exist
186 BOOST_CHECK(!odbw
.Read(key
, res2
));
187 BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscateKey(odbw
)));
189 uint256 in2
= InsecureRand256();
192 // Check that we can write successfully
193 BOOST_CHECK(odbw
.Write(key
, in2
));
194 BOOST_CHECK(odbw
.Read(key
, res3
));
195 BOOST_CHECK_EQUAL(res3
.ToString(), in2
.ToString());
198 BOOST_AUTO_TEST_CASE(iterator_ordering
)
200 fs::path ph
= fs::temp_directory_path() / fs::unique_path();
201 CDBWrapper
dbw(ph
, (1 << 20), true, false, false);
202 for (int x
=0x00; x
<256; ++x
) {
204 uint32_t value
= x
*x
;
205 if (!(x
& 1)) BOOST_CHECK(dbw
.Write(key
, value
));
208 // Check that creating an iterator creates a snapshot
209 std::unique_ptr
<CDBIterator
> it(const_cast<CDBWrapper
&>(dbw
).NewIterator());
211 for (int x
=0x00; x
<256; ++x
) {
213 uint32_t value
= x
*x
;
214 if (x
& 1) BOOST_CHECK(dbw
.Write(key
, value
));
217 for (int seek_start
: {0x00, 0x80}) {
218 it
->Seek((uint8_t)seek_start
);
219 for (int x
=seek_start
; x
<255; ++x
) {
222 BOOST_CHECK(it
->Valid());
223 if (!it
->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
225 BOOST_CHECK(it
->GetKey(key
));
227 BOOST_CHECK_EQUAL(key
, x
+ 1);
230 BOOST_CHECK(it
->GetValue(value
));
231 BOOST_CHECK_EQUAL(key
, x
);
232 BOOST_CHECK_EQUAL(value
, x
*x
);
235 BOOST_CHECK(!it
->Valid());
239 struct StringContentsSerializer
{
240 // Used to make two serialized objects the same while letting them have a different lengths
241 // This is a terrible idea
243 StringContentsSerializer() {}
244 explicit StringContentsSerializer(const std::string
& inp
) : str(inp
) {}
246 StringContentsSerializer
& operator+=(const std::string
& s
) {
250 StringContentsSerializer
& operator+=(const StringContentsSerializer
& s
) { return *this += s
.str
; }
252 ADD_SERIALIZE_METHODS
;
254 template <typename Stream
, typename Operation
>
255 inline void SerializationOp(Stream
& s
, Operation ser_action
) {
256 if (ser_action
.ForRead()) {
263 } catch (const std::ios_base::failure
& e
) {
268 for (size_t i
= 0; i
< str
.size(); i
++)
274 BOOST_AUTO_TEST_CASE(iterator_string_ordering
)
278 fs::path ph
= fs::temp_directory_path() / fs::unique_path();
279 CDBWrapper
dbw(ph
, (1 << 20), true, false, false);
280 for (int x
=0x00; x
<10; ++x
) {
281 for (int y
= 0; y
< 10; y
++) {
282 snprintf(buf
, sizeof(buf
), "%d", x
);
283 StringContentsSerializer
key(buf
);
284 for (int z
= 0; z
< y
; z
++)
286 uint32_t value
= x
*x
;
287 BOOST_CHECK(dbw
.Write(key
, value
));
291 std::unique_ptr
<CDBIterator
> it(const_cast<CDBWrapper
&>(dbw
).NewIterator());
292 for (int seek_start
: {0, 5}) {
293 snprintf(buf
, sizeof(buf
), "%d", seek_start
);
294 StringContentsSerializer
seek_key(buf
);
296 for (int x
=seek_start
; x
<10; ++x
) {
297 for (int y
= 0; y
< 10; y
++) {
298 snprintf(buf
, sizeof(buf
), "%d", x
);
299 std::string
exp_key(buf
);
300 for (int z
= 0; z
< y
; z
++)
302 StringContentsSerializer key
;
304 BOOST_CHECK(it
->Valid());
305 if (!it
->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
307 BOOST_CHECK(it
->GetKey(key
));
308 BOOST_CHECK(it
->GetValue(value
));
309 BOOST_CHECK_EQUAL(key
.str
, exp_key
);
310 BOOST_CHECK_EQUAL(value
, x
*x
);
314 BOOST_CHECK(!it
->Valid());
320 BOOST_AUTO_TEST_SUITE_END()