Line data Source code
1 : // Copyright (c) 2012-2014 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 "leveldbwrapper.h"
6 :
7 : #include "util.h"
8 : #include "random.h"
9 :
10 : #include <boost/filesystem.hpp>
11 :
12 : #include <leveldb/cache.h>
13 : #include <leveldb/env.h>
14 : #include <leveldb/filter_policy.h>
15 : #include <memenv.h>
16 : #include <stdint.h>
17 :
18 798 : void HandleError(const leveldb::Status& status) throw(leveldb_error)
19 : {
20 798 : if (status.ok())
21 798 : return;
22 0 : LogPrintf("%s\n", status.ToString());
23 0 : if (status.IsCorruption())
24 0 : throw leveldb_error("Database corrupted");
25 0 : if (status.IsIOError())
26 0 : throw leveldb_error("Database I/O error");
27 0 : if (status.IsNotFound())
28 0 : throw leveldb_error("Database entry missing");
29 0 : throw leveldb_error("Unknown database error");
30 : }
31 :
32 : static leveldb::Options GetOptions(size_t nCacheSize)
33 : {
34 244 : leveldb::Options options;
35 244 : options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
36 244 : options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously
37 244 : options.filter_policy = leveldb::NewBloomFilterPolicy(10);
38 244 : options.compression = leveldb::kNoCompression;
39 244 : options.max_open_files = 64;
40 : if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
41 : // LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error
42 : // on corruption in later versions.
43 244 : options.paranoid_checks = true;
44 : }
45 : return options;
46 : }
47 :
48 1220 : CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
49 : {
50 244 : penv = NULL;
51 244 : readoptions.verify_checksums = true;
52 244 : iteroptions.verify_checksums = true;
53 244 : iteroptions.fill_cache = false;
54 244 : syncoptions.sync = true;
55 244 : options = GetOptions(nCacheSize);
56 244 : options.create_if_missing = true;
57 244 : if (fMemory) {
58 52 : penv = leveldb::NewMemEnv(leveldb::Env::Default());
59 52 : options.env = penv;
60 : } else {
61 192 : if (fWipe) {
62 3 : LogPrintf("Wiping LevelDB in %s\n", path.string());
63 3 : leveldb::Status result = leveldb::DestroyDB(path.string(), options);
64 3 : HandleError(result);
65 : }
66 192 : TryCreateDirectory(path);
67 192 : LogPrintf("Opening LevelDB in %s\n", path.string());
68 : }
69 488 : leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb);
70 244 : HandleError(status);
71 244 : LogPrintf("Opened LevelDB successfully\n");
72 :
73 : // The base-case obfuscation key, which is a noop.
74 732 : obfuscate_key = std::vector<unsigned char>(OBFUSCATE_KEY_NUM_BYTES, '\000');
75 :
76 244 : bool key_exists = Read(OBFUSCATE_KEY_KEY, obfuscate_key);
77 :
78 244 : if (!key_exists && obfuscate && IsEmpty()) {
79 : // Initialize non-degenerate obfuscation if it won't upset
80 : // existing, non-obfuscated data.
81 : std::vector<unsigned char> new_key = CreateObfuscateKey();
82 :
83 : // Write `new_key` so we don't obfuscate the key with itself
84 64 : Write(OBFUSCATE_KEY_KEY, new_key);
85 64 : obfuscate_key = new_key;
86 :
87 128 : LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), GetObfuscateKeyHex());
88 : }
89 :
90 488 : LogPrintf("Using obfuscation key for %s: %s\n", path.string(), GetObfuscateKeyHex());
91 244 : }
92 :
93 488 : CLevelDBWrapper::~CLevelDBWrapper()
94 : {
95 244 : delete pdb;
96 244 : pdb = NULL;
97 244 : delete options.filter_policy;
98 244 : options.filter_policy = NULL;
99 244 : delete options.block_cache;
100 244 : options.block_cache = NULL;
101 244 : delete penv;
102 244 : options.env = NULL;
103 244 : }
104 :
105 551 : bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync) throw(leveldb_error)
106 : {
107 551 : leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);
108 551 : HandleError(status);
109 1102 : return true;
110 : }
111 :
112 : // Prefixed with null character to avoid collisions with other keys
113 : //
114 : // We must use a string constructor which specifies length so that we copy
115 : // past the null-terminator.
116 192 : const std::string CLevelDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14);
117 :
118 : const unsigned int CLevelDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8;
119 :
120 : /**
121 : * Returns a string (consisting of 8 random bytes) suitable for use as an
122 : * obfuscating XOR key.
123 : */
124 0 : std::vector<unsigned char> CLevelDBWrapper::CreateObfuscateKey() const
125 : {
126 : unsigned char buff[OBFUSCATE_KEY_NUM_BYTES];
127 64 : GetRandBytes(buff, OBFUSCATE_KEY_NUM_BYTES);
128 128 : return std::vector<unsigned char>(&buff[0], &buff[OBFUSCATE_KEY_NUM_BYTES]);
129 :
130 : }
131 :
132 66 : bool CLevelDBWrapper::IsEmpty()
133 : {
134 66 : boost::scoped_ptr<leveldb::Iterator> it(NewIterator());
135 66 : it->SeekToFirst();
136 132 : return !(it->Valid());
137 : }
138 :
139 421 : const std::vector<unsigned char>& CLevelDBWrapper::GetObfuscateKey() const
140 : {
141 421 : return obfuscate_key;
142 : }
143 :
144 0 : std::string CLevelDBWrapper::GetObfuscateKeyHex() const
145 : {
146 308 : return HexStr(obfuscate_key);
147 288 : }
|