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