Bugfix: avoid sub-cent change (lost in fees) whenever possible
[bitcoin.git] / db.h
blobc9c40d58c613bc65b5cf2a2e37999cd97ab79258
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
5 class CTransaction;
6 class CTxIndex;
7 class CDiskBlockIndex;
8 class CDiskTxPos;
9 class COutPoint;
10 class CUser;
11 class CReview;
12 class CAddress;
13 class CWalletTx;
14 class CAccount;
15 class CAccountingEntry;
17 extern map<string, string> mapAddressBook;
18 extern CCriticalSection cs_mapAddressBook;
19 extern vector<unsigned char> vchDefaultKey;
20 extern bool fClient;
21 extern int nBestHeight;
24 extern unsigned int nWalletDBUpdated;
25 extern DbEnv dbenv;
28 extern void DBFlush(bool fShutdown);
29 extern vector<unsigned char> GetKeyFromKeyPool();
30 extern int64 GetOldestKeyPoolTime();
35 class CDB
37 protected:
38 Db* pdb;
39 string strFile;
40 vector<DbTxn*> vTxn;
41 bool fReadOnly;
43 explicit CDB(const char* pszFile, const char* pszMode="r+");
44 ~CDB() { Close(); }
45 public:
46 void Close();
47 private:
48 CDB(const CDB&);
49 void operator=(const CDB&);
51 protected:
52 template<typename K, typename T>
53 bool Read(const K& key, T& value)
55 if (!pdb)
56 return false;
58 // Key
59 CDataStream ssKey(SER_DISK);
60 ssKey.reserve(1000);
61 ssKey << key;
62 Dbt datKey(&ssKey[0], ssKey.size());
64 // Read
65 Dbt datValue;
66 datValue.set_flags(DB_DBT_MALLOC);
67 int ret = pdb->get(GetTxn(), &datKey, &datValue, 0);
68 memset(datKey.get_data(), 0, datKey.get_size());
69 if (datValue.get_data() == NULL)
70 return false;
72 // Unserialize value
73 CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK);
74 ssValue >> value;
76 // Clear and free memory
77 memset(datValue.get_data(), 0, datValue.get_size());
78 free(datValue.get_data());
79 return (ret == 0);
82 template<typename K, typename T>
83 bool Write(const K& key, const T& value, bool fOverwrite=true)
85 if (!pdb)
86 return false;
87 if (fReadOnly)
88 assert(("Write called on database in read-only mode", false));
90 // Key
91 CDataStream ssKey(SER_DISK);
92 ssKey.reserve(1000);
93 ssKey << key;
94 Dbt datKey(&ssKey[0], ssKey.size());
96 // Value
97 CDataStream ssValue(SER_DISK);
98 ssValue.reserve(10000);
99 ssValue << value;
100 Dbt datValue(&ssValue[0], ssValue.size());
102 // Write
103 int ret = pdb->put(GetTxn(), &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
105 // Clear memory in case it was a private key
106 memset(datKey.get_data(), 0, datKey.get_size());
107 memset(datValue.get_data(), 0, datValue.get_size());
108 return (ret == 0);
111 template<typename K>
112 bool Erase(const K& key)
114 if (!pdb)
115 return false;
116 if (fReadOnly)
117 assert(("Erase called on database in read-only mode", false));
119 // Key
120 CDataStream ssKey(SER_DISK);
121 ssKey.reserve(1000);
122 ssKey << key;
123 Dbt datKey(&ssKey[0], ssKey.size());
125 // Erase
126 int ret = pdb->del(GetTxn(), &datKey, 0);
128 // Clear memory
129 memset(datKey.get_data(), 0, datKey.get_size());
130 return (ret == 0 || ret == DB_NOTFOUND);
133 template<typename K>
134 bool Exists(const K& key)
136 if (!pdb)
137 return false;
139 // Key
140 CDataStream ssKey(SER_DISK);
141 ssKey.reserve(1000);
142 ssKey << key;
143 Dbt datKey(&ssKey[0], ssKey.size());
145 // Exists
146 int ret = pdb->exists(GetTxn(), &datKey, 0);
148 // Clear memory
149 memset(datKey.get_data(), 0, datKey.get_size());
150 return (ret == 0);
153 Dbc* GetCursor()
155 if (!pdb)
156 return NULL;
157 Dbc* pcursor = NULL;
158 int ret = pdb->cursor(NULL, &pcursor, 0);
159 if (ret != 0)
160 return NULL;
161 return pcursor;
164 int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT)
166 // Read at cursor
167 Dbt datKey;
168 if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
170 datKey.set_data(&ssKey[0]);
171 datKey.set_size(ssKey.size());
173 Dbt datValue;
174 if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
176 datValue.set_data(&ssValue[0]);
177 datValue.set_size(ssValue.size());
179 datKey.set_flags(DB_DBT_MALLOC);
180 datValue.set_flags(DB_DBT_MALLOC);
181 int ret = pcursor->get(&datKey, &datValue, fFlags);
182 if (ret != 0)
183 return ret;
184 else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
185 return 99999;
187 // Convert to streams
188 ssKey.SetType(SER_DISK);
189 ssKey.clear();
190 ssKey.write((char*)datKey.get_data(), datKey.get_size());
191 ssValue.SetType(SER_DISK);
192 ssValue.clear();
193 ssValue.write((char*)datValue.get_data(), datValue.get_size());
195 // Clear and free memory
196 memset(datKey.get_data(), 0, datKey.get_size());
197 memset(datValue.get_data(), 0, datValue.get_size());
198 free(datKey.get_data());
199 free(datValue.get_data());
200 return 0;
203 DbTxn* GetTxn()
205 if (!vTxn.empty())
206 return vTxn.back();
207 else
208 return NULL;
211 public:
212 bool TxnBegin()
214 if (!pdb)
215 return false;
216 DbTxn* ptxn = NULL;
217 int ret = dbenv.txn_begin(GetTxn(), &ptxn, DB_TXN_NOSYNC);
218 if (!ptxn || ret != 0)
219 return false;
220 vTxn.push_back(ptxn);
221 return true;
224 bool TxnCommit()
226 if (!pdb)
227 return false;
228 if (vTxn.empty())
229 return false;
230 int ret = vTxn.back()->commit(0);
231 vTxn.pop_back();
232 return (ret == 0);
235 bool TxnAbort()
237 if (!pdb)
238 return false;
239 if (vTxn.empty())
240 return false;
241 int ret = vTxn.back()->abort();
242 vTxn.pop_back();
243 return (ret == 0);
246 bool ReadVersion(int& nVersion)
248 nVersion = 0;
249 return Read(string("version"), nVersion);
252 bool WriteVersion(int nVersion)
254 return Write(string("version"), nVersion);
265 class CTxDB : public CDB
267 public:
268 CTxDB(const char* pszMode="r+") : CDB("blkindex.dat", pszMode) { }
269 private:
270 CTxDB(const CTxDB&);
271 void operator=(const CTxDB&);
272 public:
273 bool ReadTxIndex(uint256 hash, CTxIndex& txindex);
274 bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex);
275 bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight);
276 bool EraseTxIndex(const CTransaction& tx);
277 bool ContainsTx(uint256 hash);
278 bool ReadOwnerTxes(uint160 hash160, int nHeight, vector<CTransaction>& vtx);
279 bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex);
280 bool ReadDiskTx(uint256 hash, CTransaction& tx);
281 bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex);
282 bool ReadDiskTx(COutPoint outpoint, CTransaction& tx);
283 bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
284 bool EraseBlockIndex(uint256 hash);
285 bool ReadHashBestChain(uint256& hashBestChain);
286 bool WriteHashBestChain(uint256 hashBestChain);
287 bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork);
288 bool WriteBestInvalidWork(CBigNum bnBestInvalidWork);
289 bool LoadBlockIndex();
296 class CAddrDB : public CDB
298 public:
299 CAddrDB(const char* pszMode="r+") : CDB("addr.dat", pszMode) { }
300 private:
301 CAddrDB(const CAddrDB&);
302 void operator=(const CAddrDB&);
303 public:
304 bool WriteAddress(const CAddress& addr);
305 bool EraseAddress(const CAddress& addr);
306 bool LoadAddresses();
309 bool LoadAddresses();
316 class CKeyPool
318 public:
319 int64 nTime;
320 vector<unsigned char> vchPubKey;
322 CKeyPool()
324 nTime = GetTime();
327 CKeyPool(const vector<unsigned char>& vchPubKeyIn)
329 nTime = GetTime();
330 vchPubKey = vchPubKeyIn;
333 IMPLEMENT_SERIALIZE
335 if (!(nType & SER_GETHASH))
336 READWRITE(nVersion);
337 READWRITE(nTime);
338 READWRITE(vchPubKey);
345 class CWalletDB : public CDB
347 public:
348 CWalletDB(const char* pszMode="r+") : CDB("wallet.dat", pszMode)
351 private:
352 CWalletDB(const CWalletDB&);
353 void operator=(const CWalletDB&);
354 public:
355 bool ReadName(const string& strAddress, string& strName)
357 strName = "";
358 return Read(make_pair(string("name"), strAddress), strName);
361 bool WriteName(const string& strAddress, const string& strName)
363 CRITICAL_BLOCK(cs_mapAddressBook)
364 mapAddressBook[strAddress] = strName;
365 nWalletDBUpdated++;
366 return Write(make_pair(string("name"), strAddress), strName);
369 bool EraseName(const string& strAddress)
371 // This should only be used for sending addresses, never for receiving addresses,
372 // receiving addresses must always have an address book entry if they're not change return.
373 CRITICAL_BLOCK(cs_mapAddressBook)
374 mapAddressBook.erase(strAddress);
375 nWalletDBUpdated++;
376 return Erase(make_pair(string("name"), strAddress));
379 bool ReadTx(uint256 hash, CWalletTx& wtx)
381 return Read(make_pair(string("tx"), hash), wtx);
384 bool WriteTx(uint256 hash, const CWalletTx& wtx)
386 nWalletDBUpdated++;
387 return Write(make_pair(string("tx"), hash), wtx);
390 bool EraseTx(uint256 hash)
392 nWalletDBUpdated++;
393 return Erase(make_pair(string("tx"), hash));
396 bool ReadKey(const vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey)
398 vchPrivKey.clear();
399 return Read(make_pair(string("key"), vchPubKey), vchPrivKey);
402 bool WriteKey(const vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)
404 nWalletDBUpdated++;
405 return Write(make_pair(string("key"), vchPubKey), vchPrivKey, false);
408 bool ReadDefaultKey(vector<unsigned char>& vchPubKey)
410 vchPubKey.clear();
411 return Read(string("defaultkey"), vchPubKey);
414 bool WriteDefaultKey(const vector<unsigned char>& vchPubKey)
416 vchDefaultKey = vchPubKey;
417 nWalletDBUpdated++;
418 return Write(string("defaultkey"), vchPubKey);
421 template<typename T>
422 bool ReadSetting(const string& strKey, T& value)
424 return Read(make_pair(string("setting"), strKey), value);
427 template<typename T>
428 bool WriteSetting(const string& strKey, const T& value)
430 nWalletDBUpdated++;
431 return Write(make_pair(string("setting"), strKey), value);
434 bool ReadAccount(const string& strAccount, CAccount& account);
435 bool WriteAccount(const string& strAccount, const CAccount& account);
436 bool WriteAccountingEntry(const CAccountingEntry& acentry);
437 int64 GetAccountCreditDebit(const string& strAccount);
438 void ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& acentries);
440 bool LoadWallet();
441 protected:
442 void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool);
443 void KeepKey(int64 nIndex);
444 static void ReturnKey(int64 nIndex);
445 friend class CReserveKey;
446 friend vector<unsigned char> GetKeyFromKeyPool();
447 friend int64 GetOldestKeyPoolTime();
450 bool LoadWallet(bool& fFirstRunRet);
451 void BackupWallet(const string& strDest);
453 inline bool SetAddressBookName(const string& strAddress, const string& strName)
455 return CWalletDB().WriteName(strAddress, strName);
458 class CReserveKey
460 protected:
461 int64 nIndex;
462 vector<unsigned char> vchPubKey;
463 public:
464 CReserveKey()
466 nIndex = -1;
469 ~CReserveKey()
471 if (!fShutdown)
472 ReturnKey();
475 vector<unsigned char> GetReservedKey()
477 if (nIndex == -1)
479 CKeyPool keypool;
480 CWalletDB().ReserveKeyFromKeyPool(nIndex, keypool);
481 vchPubKey = keypool.vchPubKey;
483 assert(!vchPubKey.empty());
484 return vchPubKey;
487 void KeepKey()
489 if (nIndex != -1)
490 CWalletDB().KeepKey(nIndex);
491 nIndex = -1;
492 vchPubKey.clear();
495 void ReturnKey()
497 if (nIndex != -1)
498 CWalletDB::ReturnKey(nIndex);
499 nIndex = -1;
500 vchPubKey.clear();