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