[Wallet] Bugfix: FRT: don't terminate when keypool is empty
[bitcoinplatinum.git] / src / dbwrapper.h
blob4a79bbd17dfec56999445ee4f41005d21e93ce8d
1 // Copyright (c) 2012-2015 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.
5 #ifndef BITCOIN_DBWRAPPER_H
6 #define BITCOIN_DBWRAPPER_H
8 #include "clientversion.h"
9 #include "serialize.h"
10 #include "streams.h"
11 #include "util.h"
12 #include "utilstrencodings.h"
13 #include "version.h"
15 #include <boost/filesystem/path.hpp>
17 #include <leveldb/db.h>
18 #include <leveldb/write_batch.h>
20 static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
21 static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
23 class dbwrapper_error : public std::runtime_error
25 public:
26 dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
29 class CDBWrapper;
31 /** These should be considered an implementation detail of the specific database.
33 namespace dbwrapper_private {
35 /** Handle database error by throwing dbwrapper_error exception.
37 void HandleError(const leveldb::Status& status);
39 /** Work around circular dependency, as well as for testing in dbwrapper_tests.
40 * Database obfuscation should be considered an implementation detail of the
41 * specific database.
43 const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w);
47 /** Batch of changes queued to be written to a CDBWrapper */
48 class CDBBatch
50 friend class CDBWrapper;
52 private:
53 const CDBWrapper &parent;
54 leveldb::WriteBatch batch;
56 public:
57 /**
58 * @param[in] _parent CDBWrapper that this batch is to be submitted to
60 CDBBatch(const CDBWrapper &_parent) : parent(_parent) { };
62 template <typename K, typename V>
63 void Write(const K& key, const V& value)
65 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
66 ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
67 ssKey << key;
68 leveldb::Slice slKey(&ssKey[0], ssKey.size());
70 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
71 ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE);
72 ssValue << value;
73 ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));
74 leveldb::Slice slValue(&ssValue[0], ssValue.size());
76 batch.Put(slKey, slValue);
79 template <typename K>
80 void Erase(const K& key)
82 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
83 ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
84 ssKey << key;
85 leveldb::Slice slKey(&ssKey[0], ssKey.size());
87 batch.Delete(slKey);
91 class CDBIterator
93 private:
94 const CDBWrapper &parent;
95 leveldb::Iterator *piter;
97 public:
99 /**
100 * @param[in] _parent Parent CDBWrapper instance.
101 * @param[in] _piter The original leveldb iterator.
103 CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter) :
104 parent(_parent), piter(_piter) { };
105 ~CDBIterator();
107 bool Valid();
109 void SeekToFirst();
111 template<typename K> void Seek(const K& key) {
112 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
113 ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
114 ssKey << key;
115 leveldb::Slice slKey(&ssKey[0], ssKey.size());
116 piter->Seek(slKey);
119 void Next();
121 template<typename K> bool GetKey(K& key) {
122 leveldb::Slice slKey = piter->key();
123 try {
124 CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
125 ssKey >> key;
126 } catch (const std::exception&) {
127 return false;
129 return true;
132 unsigned int GetKeySize() {
133 return piter->key().size();
136 template<typename V> bool GetValue(V& value) {
137 leveldb::Slice slValue = piter->value();
138 try {
139 CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION);
140 ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));
141 ssValue >> value;
142 } catch (const std::exception&) {
143 return false;
145 return true;
148 unsigned int GetValueSize() {
149 return piter->value().size();
154 class CDBWrapper
156 friend const std::vector<unsigned char>& dbwrapper_private::GetObfuscateKey(const CDBWrapper &w);
157 private:
158 //! custom environment this database is using (may be NULL in case of default environment)
159 leveldb::Env* penv;
161 //! database options used
162 leveldb::Options options;
164 //! options used when reading from the database
165 leveldb::ReadOptions readoptions;
167 //! options used when iterating over values of the database
168 leveldb::ReadOptions iteroptions;
170 //! options used when writing to the database
171 leveldb::WriteOptions writeoptions;
173 //! options used when sync writing to the database
174 leveldb::WriteOptions syncoptions;
176 //! the database itself
177 leveldb::DB* pdb;
179 //! a key used for optional XOR-obfuscation of the database
180 std::vector<unsigned char> obfuscate_key;
182 //! the key under which the obfuscation key is stored
183 static const std::string OBFUSCATE_KEY_KEY;
185 //! the length of the obfuscate key in number of bytes
186 static const unsigned int OBFUSCATE_KEY_NUM_BYTES;
188 std::vector<unsigned char> CreateObfuscateKey() const;
190 public:
192 * @param[in] path Location in the filesystem where leveldb data will be stored.
193 * @param[in] nCacheSize Configures various leveldb cache settings.
194 * @param[in] fMemory If true, use leveldb's memory environment.
195 * @param[in] fWipe If true, remove all existing data.
196 * @param[in] obfuscate If true, store data obfuscated via simple XOR. If false, XOR
197 * with a zero'd byte array.
199 CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false);
200 ~CDBWrapper();
202 template <typename K, typename V>
203 bool Read(const K& key, V& value) const
205 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
206 ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
207 ssKey << key;
208 leveldb::Slice slKey(&ssKey[0], ssKey.size());
210 std::string strValue;
211 leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
212 if (!status.ok()) {
213 if (status.IsNotFound())
214 return false;
215 LogPrintf("LevelDB read failure: %s\n", status.ToString());
216 dbwrapper_private::HandleError(status);
218 try {
219 CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
220 ssValue.Xor(obfuscate_key);
221 ssValue >> value;
222 } catch (const std::exception&) {
223 return false;
225 return true;
228 template <typename K, typename V>
229 bool Write(const K& key, const V& value, bool fSync = false)
231 CDBBatch batch(*this);
232 batch.Write(key, value);
233 return WriteBatch(batch, fSync);
236 template <typename K>
237 bool Exists(const K& key) const
239 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
240 ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
241 ssKey << key;
242 leveldb::Slice slKey(&ssKey[0], ssKey.size());
244 std::string strValue;
245 leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
246 if (!status.ok()) {
247 if (status.IsNotFound())
248 return false;
249 LogPrintf("LevelDB read failure: %s\n", status.ToString());
250 dbwrapper_private::HandleError(status);
252 return true;
255 template <typename K>
256 bool Erase(const K& key, bool fSync = false)
258 CDBBatch batch(*this);
259 batch.Erase(key);
260 return WriteBatch(batch, fSync);
263 bool WriteBatch(CDBBatch& batch, bool fSync = false);
265 // not available for LevelDB; provide for compatibility with BDB
266 bool Flush()
268 return true;
271 bool Sync()
273 CDBBatch batch(*this);
274 return WriteBatch(batch, true);
277 CDBIterator *NewIterator()
279 return new CDBIterator(*this, pdb->NewIterator(iteroptions));
283 * Return true if the database managed by this class contains no entries.
285 bool IsEmpty();
288 #endif // BITCOIN_DBWRAPPER_H