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