Added 320 fresh seednodes to replace the old ones.
[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 class CAccount;
15 class CAccountingEntry;
16
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;
22
23
24 extern unsigned int nWalletDBUpdated;
25 extern DbEnv dbenv;
26
27
28 extern void DBFlush(bool fShutdown);
29 extern vector<unsigned char> GetKeyFromKeyPool();
30 extern int64 GetOldestKeyPoolTime();
31
32
33
34
35 class CDB
36 {
37 protected:
38     Db* pdb;
39     string strFile;
40     vector<DbTxn*> vTxn;
41     bool fReadOnly;
42
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&);
50
51 protected:
52     template<typename K, typename T>
53     bool Read(const K& key, T& value)
54     {
55         if (!pdb)
56             return false;
57
58         // Key
59         CDataStream ssKey(SER_DISK);
60         ssKey.reserve(1000);
61         ssKey << key;
62         Dbt datKey(&ssKey[0], ssKey.size());
63
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;
71
72         // Unserialize value
73         CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK);
74         ssValue >> value;
75
76         // Clear and free memory
77         memset(datValue.get_data(), 0, datValue.get_size());
78         free(datValue.get_data());
79         return (ret == 0);
80     }
81
82     template<typename K, typename T>
83     bool Write(const K& key, const T& value, bool fOverwrite=true)
84     {
85         if (!pdb)
86             return false;
87         if (fReadOnly)
88             assert(("Write called on database in read-only mode", false));
89
90         // Key
91         CDataStream ssKey(SER_DISK);
92         ssKey.reserve(1000);
93         ssKey << key;
94         Dbt datKey(&ssKey[0], ssKey.size());
95
96         // Value
97         CDataStream ssValue(SER_DISK);
98         ssValue.reserve(10000);
99         ssValue << value;
100         Dbt datValue(&ssValue[0], ssValue.size());
101
102         // Write
103         int ret = pdb->put(GetTxn(), &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
104
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);
109     }
110
111     template<typename K>
112     bool Erase(const K& key)
113     {
114         if (!pdb)
115             return false;
116         if (fReadOnly)
117             assert(("Erase called on database in read-only mode", false));
118
119         // Key
120         CDataStream ssKey(SER_DISK);
121         ssKey.reserve(1000);
122         ssKey << key;
123         Dbt datKey(&ssKey[0], ssKey.size());
124
125         // Erase
126         int ret = pdb->del(GetTxn(), &datKey, 0);
127
128         // Clear memory
129         memset(datKey.get_data(), 0, datKey.get_size());
130         return (ret == 0 || ret == DB_NOTFOUND);
131     }
132
133     template<typename K>
134     bool Exists(const K& key)
135     {
136         if (!pdb)
137             return false;
138
139         // Key
140         CDataStream ssKey(SER_DISK);
141         ssKey.reserve(1000);
142         ssKey << key;
143         Dbt datKey(&ssKey[0], ssKey.size());
144
145         // Exists
146         int ret = pdb->exists(GetTxn(), &datKey, 0);
147
148         // Clear memory
149         memset(datKey.get_data(), 0, datKey.get_size());
150         return (ret == 0);
151     }
152
153     Dbc* GetCursor()
154     {
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;
162     }
163
164     int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT)
165     {
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)
169         {
170             datKey.set_data(&ssKey[0]);
171             datKey.set_size(ssKey.size());
172         }
173         Dbt datValue;
174         if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
175         {
176             datValue.set_data(&ssValue[0]);
177             datValue.set_size(ssValue.size());
178         }
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;
186
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());
194
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;
201     }
202
203     DbTxn* GetTxn()
204     {
205         if (!vTxn.empty())
206             return vTxn.back();
207         else
208             return NULL;
209     }
210
211 public:
212     bool TxnBegin()
213     {
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;
222     }
223
224     bool TxnCommit()
225     {
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);
233     }
234
235     bool TxnAbort()
236     {
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);
244     }
245
246     bool ReadVersion(int& nVersion)
247     {
248         nVersion = 0;
249         return Read(string("version"), nVersion);
250     }
251
252     bool WriteVersion(int nVersion)
253     {
254         return Write(string("version"), nVersion);
255     }
256 };
257
258
259
260
261
262
263
264
265 class CTxDB : public CDB
266 {
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();
290 };
291
292
293
294
295
296 class CAddrDB : public CDB
297 {
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();
307 };
308
309 bool LoadAddresses();
310
311
312
313
314
315
316 class CKeyPool
317 {
318 public:
319     int64 nTime;
320     vector<unsigned char> vchPubKey;
321
322     CKeyPool()
323     {
324         nTime = GetTime();
325     }
326
327     CKeyPool(const vector<unsigned char>& vchPubKeyIn)
328     {
329         nTime = GetTime();
330         vchPubKey = vchPubKeyIn;
331     }
332
333     IMPLEMENT_SERIALIZE
334     (
335         if (!(nType & SER_GETHASH))
336             READWRITE(nVersion);
337         READWRITE(nTime);
338         READWRITE(vchPubKey);
339     )
340 };
341
342
343
344
345 class CWalletDB : public CDB
346 {
347 public:
348     CWalletDB(const char* pszMode="r+") : CDB("wallet.dat", pszMode)
349     {
350     }
351 private:
352     CWalletDB(const CWalletDB&);
353     void operator=(const CWalletDB&);
354 public:
355     bool ReadName(const string& strAddress, string& strName)
356     {
357         strName = "";
358         return Read(make_pair(string("name"), strAddress), strName);
359     }
360
361     bool WriteName(const string& strAddress, const string& strName)
362     {
363         CRITICAL_BLOCK(cs_mapAddressBook)
364             mapAddressBook[strAddress] = strName;
365         nWalletDBUpdated++;
366         return Write(make_pair(string("name"), strAddress), strName);
367     }
368
369     bool EraseName(const string& strAddress)
370     {
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));
377     }
378
379     bool ReadTx(uint256 hash, CWalletTx& wtx)
380     {
381         return Read(make_pair(string("tx"), hash), wtx);
382     }
383
384     bool WriteTx(uint256 hash, const CWalletTx& wtx)
385     {
386         nWalletDBUpdated++;
387         return Write(make_pair(string("tx"), hash), wtx);
388     }
389
390     bool EraseTx(uint256 hash)
391     {
392         nWalletDBUpdated++;
393         return Erase(make_pair(string("tx"), hash));
394     }
395
396     bool ReadKey(const vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey)
397     {
398         vchPrivKey.clear();
399         return Read(make_pair(string("key"), vchPubKey), vchPrivKey);
400     }
401
402     bool WriteKey(const vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)
403     {
404         nWalletDBUpdated++;
405         return Write(make_pair(string("key"), vchPubKey), vchPrivKey, false);
406     }
407
408     bool ReadDefaultKey(vector<unsigned char>& vchPubKey)
409     {
410         vchPubKey.clear();
411         return Read(string("defaultkey"), vchPubKey);
412     }
413
414     bool WriteDefaultKey(const vector<unsigned char>& vchPubKey)
415     {
416         vchDefaultKey = vchPubKey;
417         nWalletDBUpdated++;
418         return Write(string("defaultkey"), vchPubKey);
419     }
420
421     template<typename T>
422     bool ReadSetting(const string& strKey, T& value)
423     {
424         return Read(make_pair(string("setting"), strKey), value);
425     }
426
427     template<typename T>
428     bool WriteSetting(const string& strKey, const T& value)
429     {
430         nWalletDBUpdated++;
431         return Write(make_pair(string("setting"), strKey), value);
432     }
433
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);
439
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();
448 };
449
450 bool LoadWallet(bool& fFirstRunRet);
451 void BackupWallet(const string& strDest);
452
453 inline bool SetAddressBookName(const string& strAddress, const string& strName)
454 {
455     return CWalletDB().WriteName(strAddress, strName);
456 }
457
458 class CReserveKey
459 {
460 protected:
461     int64 nIndex;
462     vector<unsigned char> vchPubKey;
463 public:
464     CReserveKey()
465     {
466         nIndex = -1;
467     }
468
469     ~CReserveKey()
470     {
471         if (!fShutdown)
472             ReturnKey();
473     }
474
475     vector<unsigned char> GetReservedKey()
476     {
477         if (nIndex == -1)
478         {
479             CKeyPool keypool;
480             CWalletDB().ReserveKeyFromKeyPool(nIndex, keypool);
481             vchPubKey = keypool.vchPubKey;
482         }
483         assert(!vchPubKey.empty());
484         return vchPubKey;
485     }
486
487     void KeepKey()
488     {
489         if (nIndex != -1)
490             CWalletDB().KeepKey(nIndex);
491         nIndex = -1;
492         vchPubKey.clear();
493     }
494
495     void ReturnKey()
496     {
497         if (nIndex != -1)
498             CWalletDB::ReturnKey(nIndex);
499         nIndex = -1;
500         vchPubKey.clear();
501     }
502 };