Projects : bitcoin : bitcoin_dumpblock_no_losers
1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
2 | // Copyright (c) 2011 The Bitcoin developers |
3 | // Distributed under the MIT/X11 software license, see the accompanying |
4 | // file license.txt or http://www.opensource.org/licenses/mit-license.php. |
5 | #ifndef BITCOIN_DB_H |
6 | #define BITCOIN_DB_H |
7 | |
8 | #include "key.h" |
9 | |
10 | #include <map> |
11 | #include <string> |
12 | #include <vector> |
13 | |
14 | #include <db_cxx.h> |
15 | |
16 | class CTxIndex; |
17 | class CDiskBlockIndex; |
18 | class CDiskTxPos; |
19 | class COutPoint; |
20 | class CAddress; |
21 | class CWalletTx; |
22 | class CWallet; |
23 | class CAccount; |
24 | class CAccountingEntry; |
25 | class CBlockLocator; |
26 | |
27 | |
28 | extern unsigned int nWalletDBUpdated; |
29 | extern DbEnv dbenv; |
30 | |
31 | extern void DBFlush(bool fShutdown); |
32 | void ThreadFlushWalletDB(void* parg); |
33 | bool BackupWallet(const CWallet& wallet, const std::string& strDest); |
34 | |
35 | |
36 | |
37 | class CDB |
38 | { |
39 | protected: |
40 | Db* pdb; |
41 | std::string strFile; |
42 | std::vector<DbTxn*> vTxn; |
43 | bool fReadOnly; |
44 | |
45 | explicit CDB(const char* pszFile, const char* pszMode="r+"); |
46 | ~CDB() { Close(); } |
47 | public: |
48 | void Close(); |
49 | private: |
50 | CDB(const CDB&); |
51 | void operator=(const CDB&); |
52 | |
53 | protected: |
54 | template<typename K, typename T> |
55 | bool Read(const K& key, T& value) |
56 | { |
57 | if (!pdb) |
58 | return false; |
59 | |
60 | // Key |
61 | CDataStream ssKey(SER_DISK); |
62 | ssKey.reserve(1000); |
63 | ssKey << key; |
64 | Dbt datKey(&ssKey[0], ssKey.size()); |
65 | |
66 | // Read |
67 | Dbt datValue; |
68 | datValue.set_flags(DB_DBT_MALLOC); |
69 | int ret = pdb->get(GetTxn(), &datKey, &datValue, 0); |
70 | memset(datKey.get_data(), 0, datKey.get_size()); |
71 | if (datValue.get_data() == NULL) |
72 | return false; |
73 | |
74 | // Unserialize value |
75 | CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK); |
76 | ssValue >> value; |
77 | |
78 | // Clear and free memory |
79 | memset(datValue.get_data(), 0, datValue.get_size()); |
80 | free(datValue.get_data()); |
81 | return (ret == 0); |
82 | } |
83 | |
84 | template<typename K, typename T> |
85 | bool Write(const K& key, const T& value, bool fOverwrite=true) |
86 | { |
87 | if (!pdb) |
88 | return false; |
89 | if (fReadOnly) |
90 | assert(!"Write called on database in read-only mode"); |
91 | |
92 | // Key |
93 | CDataStream ssKey(SER_DISK); |
94 | ssKey.reserve(1000); |
95 | ssKey << key; |
96 | Dbt datKey(&ssKey[0], ssKey.size()); |
97 | |
98 | // Value |
99 | CDataStream ssValue(SER_DISK); |
100 | ssValue.reserve(10000); |
101 | ssValue << value; |
102 | Dbt datValue(&ssValue[0], ssValue.size()); |
103 | |
104 | // Write |
105 | int ret = pdb->put(GetTxn(), &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE)); |
106 | |
107 | // Clear memory in case it was a private key |
108 | memset(datKey.get_data(), 0, datKey.get_size()); |
109 | memset(datValue.get_data(), 0, datValue.get_size()); |
110 | return (ret == 0); |
111 | } |
112 | |
113 | template<typename K> |
114 | bool Erase(const K& key) |
115 | { |
116 | if (!pdb) |
117 | return false; |
118 | if (fReadOnly) |
119 | assert(!"Erase called on database in read-only mode"); |
120 | |
121 | // Key |
122 | CDataStream ssKey(SER_DISK); |
123 | ssKey.reserve(1000); |
124 | ssKey << key; |
125 | Dbt datKey(&ssKey[0], ssKey.size()); |
126 | |
127 | // Erase |
128 | int ret = pdb->del(GetTxn(), &datKey, 0); |
129 | |
130 | // Clear memory |
131 | memset(datKey.get_data(), 0, datKey.get_size()); |
132 | return (ret == 0 || ret == DB_NOTFOUND); |
133 | } |
134 | |
135 | template<typename K> |
136 | bool Exists(const K& key) |
137 | { |
138 | if (!pdb) |
139 | return false; |
140 | |
141 | // Key |
142 | CDataStream ssKey(SER_DISK); |
143 | ssKey.reserve(1000); |
144 | ssKey << key; |
145 | Dbt datKey(&ssKey[0], ssKey.size()); |
146 | |
147 | // Exists |
148 | int ret = pdb->exists(GetTxn(), &datKey, 0); |
149 | |
150 | // Clear memory |
151 | memset(datKey.get_data(), 0, datKey.get_size()); |
152 | return (ret == 0); |
153 | } |
154 | |
155 | Dbc* GetCursor() |
156 | { |
157 | if (!pdb) |
158 | return NULL; |
159 | Dbc* pcursor = NULL; |
160 | int ret = pdb->cursor(NULL, &pcursor, 0); |
161 | if (ret != 0) |
162 | return NULL; |
163 | return pcursor; |
164 | } |
165 | |
166 | int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT) |
167 | { |
168 | // Read at cursor |
169 | Dbt datKey; |
170 | if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) |
171 | { |
172 | datKey.set_data(&ssKey[0]); |
173 | datKey.set_size(ssKey.size()); |
174 | } |
175 | Dbt datValue; |
176 | if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) |
177 | { |
178 | datValue.set_data(&ssValue[0]); |
179 | datValue.set_size(ssValue.size()); |
180 | } |
181 | datKey.set_flags(DB_DBT_MALLOC); |
182 | datValue.set_flags(DB_DBT_MALLOC); |
183 | int ret = pcursor->get(&datKey, &datValue, fFlags); |
184 | if (ret != 0) |
185 | return ret; |
186 | else if (datKey.get_data() == NULL || datValue.get_data() == NULL) |
187 | return 99999; |
188 | |
189 | // Convert to streams |
190 | ssKey.SetType(SER_DISK); |
191 | ssKey.clear(); |
192 | ssKey.write((char*)datKey.get_data(), datKey.get_size()); |
193 | ssValue.SetType(SER_DISK); |
194 | ssValue.clear(); |
195 | ssValue.write((char*)datValue.get_data(), datValue.get_size()); |
196 | |
197 | // Clear and free memory |
198 | memset(datKey.get_data(), 0, datKey.get_size()); |
199 | memset(datValue.get_data(), 0, datValue.get_size()); |
200 | free(datKey.get_data()); |
201 | free(datValue.get_data()); |
202 | return 0; |
203 | } |
204 | |
205 | DbTxn* GetTxn() |
206 | { |
207 | if (!vTxn.empty()) |
208 | return vTxn.back(); |
209 | else |
210 | return NULL; |
211 | } |
212 | |
213 | public: |
214 | bool TxnBegin() |
215 | { |
216 | if (!pdb) |
217 | return false; |
218 | DbTxn* ptxn = NULL; |
219 | int ret = dbenv.txn_begin(GetTxn(), &ptxn, DB_TXN_NOSYNC); |
220 | if (!ptxn || ret != 0) |
221 | return false; |
222 | vTxn.push_back(ptxn); |
223 | return true; |
224 | } |
225 | |
226 | bool TxnCommit() |
227 | { |
228 | if (!pdb) |
229 | return false; |
230 | if (vTxn.empty()) |
231 | return false; |
232 | int ret = vTxn.back()->commit(0); |
233 | vTxn.pop_back(); |
234 | return (ret == 0); |
235 | } |
236 | |
237 | bool TxnAbort() |
238 | { |
239 | if (!pdb) |
240 | return false; |
241 | if (vTxn.empty()) |
242 | return false; |
243 | int ret = vTxn.back()->abort(); |
244 | vTxn.pop_back(); |
245 | return (ret == 0); |
246 | } |
247 | |
248 | bool ReadVersion(int& nVersion) |
249 | { |
250 | nVersion = 0; |
251 | return Read(std::string("version"), nVersion); |
252 | } |
253 | |
254 | bool WriteVersion(int nVersion) |
255 | { |
256 | return Write(std::string("version"), nVersion); |
257 | } |
258 | |
259 | bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL); |
260 | }; |
261 | |
262 | |
263 | |
264 | |
265 | |
266 | |
267 | |
268 | |
269 | class CTxDB : public CDB |
270 | { |
271 | public: |
272 | CTxDB(const char* pszMode="r+") : CDB("blkindex.dat", pszMode) { } |
273 | private: |
274 | CTxDB(const CTxDB&); |
275 | void operator=(const CTxDB&); |
276 | public: |
277 | bool ReadTxIndex(uint256 hash, CTxIndex& txindex); |
278 | bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex); |
279 | bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight); |
280 | bool EraseTxIndex(const CTransaction& tx); |
281 | bool ContainsTx(uint256 hash); |
282 | bool ReadOwnerTxes(uint160 hash160, int nHeight, std::vector<CTransaction>& vtx); |
283 | bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex); |
284 | bool ReadDiskTx(uint256 hash, CTransaction& tx); |
285 | bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex); |
286 | bool ReadDiskTx(COutPoint outpoint, CTransaction& tx); |
287 | bool WriteBlockIndex(const CDiskBlockIndex& blockindex); |
288 | bool EraseBlockIndex(uint256 hash); |
289 | bool ReadHashBestChain(uint256& hashBestChain); |
290 | bool WriteHashBestChain(uint256 hashBestChain); |
291 | bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork); |
292 | bool WriteBestInvalidWork(CBigNum bnBestInvalidWork); |
293 | bool LoadBlockIndex(); |
294 | }; |
295 | |
296 | |
297 | |
298 | |
299 | |
300 | class CAddrDB : public CDB |
301 | { |
302 | public: |
303 | CAddrDB(const char* pszMode="r+") : CDB("addr.dat", pszMode) { } |
304 | private: |
305 | CAddrDB(const CAddrDB&); |
306 | void operator=(const CAddrDB&); |
307 | public: |
308 | bool WriteAddress(const CAddress& addr); |
309 | bool EraseAddress(const CAddress& addr); |
310 | bool LoadAddresses(); |
311 | }; |
312 | |
313 | bool LoadAddresses(); |
314 | |
315 | |
316 | |
317 | class CKeyPool |
318 | { |
319 | public: |
320 | int64 nTime; |
321 | std::vector<unsigned char> vchPubKey; |
322 | |
323 | CKeyPool() |
324 | { |
325 | nTime = GetTime(); |
326 | } |
327 | |
328 | CKeyPool(const std::vector<unsigned char>& vchPubKeyIn) |
329 | { |
330 | nTime = GetTime(); |
331 | vchPubKey = vchPubKeyIn; |
332 | } |
333 | |
334 | IMPLEMENT_SERIALIZE |
335 | ( |
336 | if (!(nType & SER_GETHASH)) |
337 | READWRITE(nVersion); |
338 | READWRITE(nTime); |
339 | READWRITE(vchPubKey); |
340 | ) |
341 | }; |
342 | |
343 | |
344 | |
345 | |
346 | enum DBErrors |
347 | { |
348 | DB_LOAD_OK, |
349 | DB_CORRUPT, |
350 | DB_TOO_NEW, |
351 | DB_LOAD_FAIL, |
352 | DB_NEED_REWRITE |
353 | }; |
354 | |
355 | class CWalletDB : public CDB |
356 | { |
357 | public: |
358 | CWalletDB(std::string strFilename, const char* pszMode="r+") : CDB(strFilename.c_str(), pszMode) |
359 | { |
360 | } |
361 | private: |
362 | CWalletDB(const CWalletDB&); |
363 | void operator=(const CWalletDB&); |
364 | public: |
365 | bool ReadName(const std::string& strAddress, std::string& strName) |
366 | { |
367 | strName = ""; |
368 | return Read(std::make_pair(std::string("name"), strAddress), strName); |
369 | } |
370 | |
371 | bool WriteName(const std::string& strAddress, const std::string& strName); |
372 | |
373 | bool EraseName(const std::string& strAddress); |
374 | |
375 | bool ReadTx(uint256 hash, CWalletTx& wtx) |
376 | { |
377 | return Read(std::make_pair(std::string("tx"), hash), wtx); |
378 | } |
379 | |
380 | bool WriteTx(uint256 hash, const CWalletTx& wtx) |
381 | { |
382 | nWalletDBUpdated++; |
383 | return Write(std::make_pair(std::string("tx"), hash), wtx); |
384 | } |
385 | |
386 | bool EraseTx(uint256 hash) |
387 | { |
388 | nWalletDBUpdated++; |
389 | return Erase(std::make_pair(std::string("tx"), hash)); |
390 | } |
391 | |
392 | bool ReadKey(const std::vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey) |
393 | { |
394 | vchPrivKey.clear(); |
395 | return Read(std::make_pair(std::string("key"), vchPubKey), vchPrivKey); |
396 | } |
397 | |
398 | bool WriteKey(const std::vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey) |
399 | { |
400 | nWalletDBUpdated++; |
401 | return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false); |
402 | } |
403 | |
404 | bool WriteCryptedKey(const std::vector<unsigned char>& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true) |
405 | { |
406 | nWalletDBUpdated++; |
407 | if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) |
408 | return false; |
409 | if (fEraseUnencryptedKey) |
410 | { |
411 | Erase(std::make_pair(std::string("key"), vchPubKey)); |
412 | Erase(std::make_pair(std::string("wkey"), vchPubKey)); |
413 | } |
414 | return true; |
415 | } |
416 | |
417 | bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey) |
418 | { |
419 | nWalletDBUpdated++; |
420 | return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true); |
421 | } |
422 | |
423 | bool WriteBestBlock(const CBlockLocator& locator) |
424 | { |
425 | nWalletDBUpdated++; |
426 | return Write(std::string("bestblock"), locator); |
427 | } |
428 | |
429 | bool ReadBestBlock(CBlockLocator& locator) |
430 | { |
431 | return Read(std::string("bestblock"), locator); |
432 | } |
433 | |
434 | bool ReadDefaultKey(std::vector<unsigned char>& vchPubKey) |
435 | { |
436 | vchPubKey.clear(); |
437 | return Read(std::string("defaultkey"), vchPubKey); |
438 | } |
439 | |
440 | bool WriteDefaultKey(const std::vector<unsigned char>& vchPubKey) |
441 | { |
442 | nWalletDBUpdated++; |
443 | return Write(std::string("defaultkey"), vchPubKey); |
444 | } |
445 | |
446 | bool ReadPool(int64 nPool, CKeyPool& keypool) |
447 | { |
448 | return Read(std::make_pair(std::string("pool"), nPool), keypool); |
449 | } |
450 | |
451 | bool WritePool(int64 nPool, const CKeyPool& keypool) |
452 | { |
453 | nWalletDBUpdated++; |
454 | return Write(std::make_pair(std::string("pool"), nPool), keypool); |
455 | } |
456 | |
457 | bool ErasePool(int64 nPool) |
458 | { |
459 | nWalletDBUpdated++; |
460 | return Erase(std::make_pair(std::string("pool"), nPool)); |
461 | } |
462 | |
463 | template<typename T> |
464 | bool ReadSetting(const std::string& strKey, T& value) |
465 | { |
466 | return Read(std::make_pair(std::string("setting"), strKey), value); |
467 | } |
468 | |
469 | template<typename T> |
470 | bool WriteSetting(const std::string& strKey, const T& value) |
471 | { |
472 | nWalletDBUpdated++; |
473 | return Write(std::make_pair(std::string("setting"), strKey), value); |
474 | } |
475 | |
476 | bool ReadAccount(const std::string& strAccount, CAccount& account); |
477 | bool WriteAccount(const std::string& strAccount, const CAccount& account); |
478 | bool WriteAccountingEntry(const CAccountingEntry& acentry); |
479 | int64 GetAccountCreditDebit(const std::string& strAccount); |
480 | void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries); |
481 | |
482 | int LoadWallet(CWallet* pwallet); |
483 | }; |
484 | |
485 | #endif |