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