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/assign/std/vector.hpp> // for 'operator+=()'
11 #include <boost/assert.hpp>
12 #include <boost/test/unit_test.hpp>
14 // Test if a string consists entirely of null characters
15 bool is_null_key(const std::vector
<unsigned char>& key
) {
18 for (unsigned int i
= 0; i
< key
.size(); i
++)
19 isnull
&= (key
[i
] == '\x00');
24 BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests
, BasicTestingSetup
)
26 BOOST_AUTO_TEST_CASE(dbwrapper
)
28 // Perform tests both obfuscated and non-obfuscated.
29 for (int i
= 0; i
< 2; i
++) {
30 bool obfuscate
= (bool)i
;
31 boost::filesystem::path ph
= boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
32 CDBWrapper
dbw(ph
, (1 << 20), true, false, obfuscate
);
34 uint256 in
= GetRandHash();
37 // Ensure that we're doing real obfuscation when obfuscate=true
38 BOOST_CHECK(obfuscate
!= is_null_key(dbwrapper_private::GetObfuscateKey(dbw
)));
40 BOOST_CHECK(dbw
.Write(key
, in
));
41 BOOST_CHECK(dbw
.Read(key
, res
));
42 BOOST_CHECK_EQUAL(res
.ToString(), in
.ToString());
46 // Test batch operations
47 BOOST_AUTO_TEST_CASE(dbwrapper_batch
)
49 // Perform tests both obfuscated and non-obfuscated.
50 for (int i
= 0; i
< 2; i
++) {
51 bool obfuscate
= (bool)i
;
52 boost::filesystem::path ph
= boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
53 CDBWrapper
dbw(ph
, (1 << 20), true, false, obfuscate
);
56 uint256 in
= GetRandHash();
58 uint256 in2
= GetRandHash();
60 uint256 in3
= GetRandHash();
66 batch
.Write(key2
, in2
);
67 batch
.Write(key3
, in3
);
69 // Remove key3 before it's even been written
72 dbw
.WriteBatch(batch
);
74 BOOST_CHECK(dbw
.Read(key
, res
));
75 BOOST_CHECK_EQUAL(res
.ToString(), in
.ToString());
76 BOOST_CHECK(dbw
.Read(key2
, res
));
77 BOOST_CHECK_EQUAL(res
.ToString(), in2
.ToString());
79 // key3 should've never been written
80 BOOST_CHECK(dbw
.Read(key3
, res
) == false);
84 BOOST_AUTO_TEST_CASE(dbwrapper_iterator
)
86 // Perform tests both obfuscated and non-obfuscated.
87 for (int i
= 0; i
< 2; i
++) {
88 bool obfuscate
= (bool)i
;
89 boost::filesystem::path ph
= boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
90 CDBWrapper
dbw(ph
, (1 << 20), true, false, obfuscate
);
92 // The two keys are intentionally chosen for ordering
94 uint256 in
= GetRandHash();
95 BOOST_CHECK(dbw
.Write(key
, in
));
97 uint256 in2
= GetRandHash();
98 BOOST_CHECK(dbw
.Write(key2
, in2
));
100 std::unique_ptr
<CDBIterator
> it(const_cast<CDBWrapper
*>(&dbw
)->NewIterator());
102 // Be sure to seek past the obfuscation key (if it exists)
109 it
->GetValue(val_res
);
110 BOOST_CHECK_EQUAL(key_res
, key
);
111 BOOST_CHECK_EQUAL(val_res
.ToString(), in
.ToString());
116 it
->GetValue(val_res
);
117 BOOST_CHECK_EQUAL(key_res
, key2
);
118 BOOST_CHECK_EQUAL(val_res
.ToString(), in2
.ToString());
121 BOOST_CHECK_EQUAL(it
->Valid(), false);
125 // Test that we do not obfuscation if there is existing data.
126 BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate
)
128 // We're going to share this boost::filesystem::path between two wrappers
129 boost::filesystem::path ph
= boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
130 create_directories(ph
);
132 // Set up a non-obfuscated wrapper to write some initial data.
133 CDBWrapper
* dbw
= new CDBWrapper(ph
, (1 << 10), false, false, false);
135 uint256 in
= GetRandHash();
138 BOOST_CHECK(dbw
->Write(key
, in
));
139 BOOST_CHECK(dbw
->Read(key
, res
));
140 BOOST_CHECK_EQUAL(res
.ToString(), in
.ToString());
142 // Call the destructor to free leveldb LOCK
146 // Now, set up another wrapper that wants to obfuscate the same directory
147 CDBWrapper
odbw(ph
, (1 << 10), false, false, true);
149 // Check that the key/val we wrote with unobfuscated wrapper exists and
152 BOOST_CHECK(odbw
.Read(key
, res2
));
153 BOOST_CHECK_EQUAL(res2
.ToString(), in
.ToString());
155 BOOST_CHECK(!odbw
.IsEmpty()); // There should be existing data
156 BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscateKey(odbw
))); // The key should be an empty string
158 uint256 in2
= GetRandHash();
161 // Check that we can write successfully
162 BOOST_CHECK(odbw
.Write(key
, in2
));
163 BOOST_CHECK(odbw
.Read(key
, res3
));
164 BOOST_CHECK_EQUAL(res3
.ToString(), in2
.ToString());
167 // Ensure that we start obfuscating during a reindex.
168 BOOST_AUTO_TEST_CASE(existing_data_reindex
)
170 // We're going to share this boost::filesystem::path between two wrappers
171 boost::filesystem::path ph
= boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
172 create_directories(ph
);
174 // Set up a non-obfuscated wrapper to write some initial data.
175 CDBWrapper
* dbw
= new CDBWrapper(ph
, (1 << 10), false, false, false);
177 uint256 in
= GetRandHash();
180 BOOST_CHECK(dbw
->Write(key
, in
));
181 BOOST_CHECK(dbw
->Read(key
, res
));
182 BOOST_CHECK_EQUAL(res
.ToString(), in
.ToString());
184 // Call the destructor to free leveldb LOCK
188 // Simulate a -reindex by wiping the existing data store
189 CDBWrapper
odbw(ph
, (1 << 10), false, true, true);
191 // Check that the key/val we wrote with unobfuscated wrapper doesn't exist
193 BOOST_CHECK(!odbw
.Read(key
, res2
));
194 BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscateKey(odbw
)));
196 uint256 in2
= GetRandHash();
199 // Check that we can write successfully
200 BOOST_CHECK(odbw
.Write(key
, in2
));
201 BOOST_CHECK(odbw
.Read(key
, res3
));
202 BOOST_CHECK_EQUAL(res3
.ToString(), in2
.ToString());
205 BOOST_AUTO_TEST_CASE(iterator_ordering
)
207 boost::filesystem::path ph
= boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
208 CDBWrapper
dbw(ph
, (1 << 20), true, false, false);
209 for (int x
=0x00; x
<256; ++x
) {
211 uint32_t value
= x
*x
;
212 BOOST_CHECK(dbw
.Write(key
, value
));
215 std::unique_ptr
<CDBIterator
> it(const_cast<CDBWrapper
*>(&dbw
)->NewIterator());
216 for (int c
=0; c
<2; ++c
) {
222 it
->Seek((uint8_t)seek_start
);
223 for (int x
=seek_start
; x
<256; ++x
) {
226 BOOST_CHECK(it
->Valid());
227 if (!it
->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
229 BOOST_CHECK(it
->GetKey(key
));
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 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 boost::filesystem::path ph
= boost::filesystem::temp_directory_path() / boost::filesystem::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 c
=0; c
<2; ++c
) {
298 snprintf(buf
, sizeof(buf
), "%d", seek_start
);
299 StringContentsSerializer
seek_key(buf
);
301 for (int x
=seek_start
; x
<10; ++x
) {
302 for (int y
= 0; y
< 10; y
++) {
303 snprintf(buf
, sizeof(buf
), "%d", x
);
304 std::string
exp_key(buf
);
305 for (int z
= 0; z
< y
; z
++)
307 StringContentsSerializer key
;
309 BOOST_CHECK(it
->Valid());
310 if (!it
->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
312 BOOST_CHECK(it
->GetKey(key
));
313 BOOST_CHECK(it
->GetValue(value
));
314 BOOST_CHECK_EQUAL(key
.str
, exp_key
);
315 BOOST_CHECK_EQUAL(value
, x
*x
);
319 BOOST_CHECK(!it
->Valid());
325 BOOST_AUTO_TEST_SUITE_END()