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