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 never should've 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
145 // Now, set up another wrapper that wants to obfuscate the same directory
146 CDBWrapper
odbw(ph
, (1 << 10), false, false, true);
148 // Check that the key/val we wrote with unobfuscated wrapper exists and
151 BOOST_CHECK(odbw
.Read(key
, res2
));
152 BOOST_CHECK_EQUAL(res2
.ToString(), in
.ToString());
154 BOOST_CHECK(!odbw
.IsEmpty()); // There should be existing data
155 BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscateKey(odbw
))); // The key should be an empty string
157 uint256 in2
= GetRandHash();
160 // Check that we can write successfully
161 BOOST_CHECK(odbw
.Write(key
, in2
));
162 BOOST_CHECK(odbw
.Read(key
, res3
));
163 BOOST_CHECK_EQUAL(res3
.ToString(), in2
.ToString());
166 // Ensure that we start obfuscating during a reindex.
167 BOOST_AUTO_TEST_CASE(existing_data_reindex
)
169 // We're going to share this boost::filesystem::path between two wrappers
170 boost::filesystem::path ph
= boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
171 create_directories(ph
);
173 // Set up a non-obfuscated wrapper to write some initial data.
174 CDBWrapper
* dbw
= new CDBWrapper(ph
, (1 << 10), false, false, false);
176 uint256 in
= GetRandHash();
179 BOOST_CHECK(dbw
->Write(key
, in
));
180 BOOST_CHECK(dbw
->Read(key
, res
));
181 BOOST_CHECK_EQUAL(res
.ToString(), in
.ToString());
183 // Call the destructor to free leveldb LOCK
186 // Simulate a -reindex by wiping the existing data store
187 CDBWrapper
odbw(ph
, (1 << 10), false, true, true);
189 // Check that the key/val we wrote with unobfuscated wrapper doesn't exist
191 BOOST_CHECK(!odbw
.Read(key
, res2
));
192 BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscateKey(odbw
)));
194 uint256 in2
= GetRandHash();
197 // Check that we can write successfully
198 BOOST_CHECK(odbw
.Write(key
, in2
));
199 BOOST_CHECK(odbw
.Read(key
, res3
));
200 BOOST_CHECK_EQUAL(res3
.ToString(), in2
.ToString());
203 BOOST_AUTO_TEST_CASE(iterator_ordering
)
205 boost::filesystem::path ph
= boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
206 CDBWrapper
dbw(ph
, (1 << 20), true, false, false);
207 for (int x
=0x00; x
<256; ++x
) {
209 uint32_t value
= x
*x
;
210 BOOST_CHECK(dbw
.Write(key
, value
));
213 std::unique_ptr
<CDBIterator
> it(const_cast<CDBWrapper
*>(&dbw
)->NewIterator());
214 for (int c
=0; c
<2; ++c
) {
220 it
->Seek((uint8_t)seek_start
);
221 for (int x
=seek_start
; x
<256; ++x
) {
224 BOOST_CHECK(it
->Valid());
225 if (!it
->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
227 BOOST_CHECK(it
->GetKey(key
));
228 BOOST_CHECK(it
->GetValue(value
));
229 BOOST_CHECK_EQUAL(key
, x
);
230 BOOST_CHECK_EQUAL(value
, x
*x
);
233 BOOST_CHECK(!it
->Valid());
237 struct StringContentsSerializer
{
238 // Used to make two serialized objects the same while letting them have a different lengths
239 // This is a terrible idea
241 StringContentsSerializer() {}
242 StringContentsSerializer(const std::string
& inp
) : str(inp
) {}
244 StringContentsSerializer
& operator+=(const std::string
& s
) {
248 StringContentsSerializer
& operator+=(const StringContentsSerializer
& s
) { return *this += s
.str
; }
250 ADD_SERIALIZE_METHODS
;
252 template <typename Stream
, typename Operation
>
253 inline void SerializationOp(Stream
& s
, Operation ser_action
) {
254 if (ser_action
.ForRead()) {
261 } catch (const std::ios_base::failure
& e
) {
266 for (size_t i
= 0; i
< str
.size(); i
++)
272 BOOST_AUTO_TEST_CASE(iterator_string_ordering
)
276 boost::filesystem::path ph
= boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
277 CDBWrapper
dbw(ph
, (1 << 20), true, false, false);
278 for (int x
=0x00; x
<10; ++x
) {
279 for (int y
= 0; y
< 10; y
++) {
280 sprintf(buf
, "%d", x
);
281 StringContentsSerializer
key(buf
);
282 for (int z
= 0; z
< y
; z
++)
284 uint32_t value
= x
*x
;
285 BOOST_CHECK(dbw
.Write(key
, value
));
289 std::unique_ptr
<CDBIterator
> it(const_cast<CDBWrapper
*>(&dbw
)->NewIterator());
290 for (int c
=0; c
<2; ++c
) {
296 sprintf(buf
, "%d", seek_start
);
297 StringContentsSerializer
seek_key(buf
);
299 for (int x
=seek_start
; x
<10; ++x
) {
300 for (int y
= 0; y
< 10; y
++) {
301 sprintf(buf
, "%d", x
);
302 std::string
exp_key(buf
);
303 for (int z
= 0; z
< y
; z
++)
305 StringContentsSerializer key
;
307 BOOST_CHECK(it
->Valid());
308 if (!it
->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
310 BOOST_CHECK(it
->GetKey(key
));
311 BOOST_CHECK(it
->GetValue(value
));
312 BOOST_CHECK_EQUAL(key
.str
, exp_key
);
313 BOOST_CHECK_EQUAL(value
, x
*x
);
317 BOOST_CHECK(!it
->Valid());
323 BOOST_AUTO_TEST_SUITE_END()