Merge with Bitcoin v0.6.3
[novacoin.git] / src / db.h
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Copyright (c) 2011-2012 The PPCoin developers
4 // Distributed under the MIT/X11 software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 #ifndef BITCOIN_DB_H
7 #define BITCOIN_DB_H
8
9 #include "main.h"
10
11 #include <map>
12 #include <string>
13 #include <vector>
14
15 #include <db_cxx.h>
16
17 class CAddress;
18 class CAddrMan;
19 class CBlockLocator;
20 class CDiskBlockIndex;
21 class CDiskTxPos;
22 class CMasterKey;
23 class COutPoint;
24 class CTxIndex;
25 class CWallet;
26 class CWalletTx;
27
28 extern unsigned int nWalletDBUpdated;
29 extern bool fDetachDB;
30 extern DbEnv dbenv;
31
32 extern void DBFlush(bool fShutdown);
33 void ThreadFlushWalletDB(void* parg);
34 bool BackupWallet(const CWallet& wallet, const std::string& strDest);
35
36
37 /** RAII class that provides access to a Berkeley database */
38 class CDB
39 {
40 protected:
41     Db* pdb;
42     std::string strFile;
43     std::vector<DbTxn*> vTxn;
44     bool fReadOnly;
45
46     explicit CDB(const char* pszFile, const char* pszMode="r+");
47     ~CDB() { Close(); }
48 public:
49     void Close();
50 private:
51     CDB(const CDB&);
52     void operator=(const CDB&);
53
54 protected:
55     template<typename K, typename T>
56     bool Read(const K& key, T& value)
57     {
58         if (!pdb)
59             return false;
60
61         // Key
62         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
63         ssKey.reserve(1000);
64         ssKey << key;
65         Dbt datKey(&ssKey[0], ssKey.size());
66
67         // Read
68         Dbt datValue;
69         datValue.set_flags(DB_DBT_MALLOC);
70         int ret = pdb->get(GetTxn(), &datKey, &datValue, 0);
71         memset(datKey.get_data(), 0, datKey.get_size());
72         if (datValue.get_data() == NULL)
73             return false;
74
75         // Unserialize value
76         try {
77             CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
78             ssValue >> value;
79         }
80         catch (std::exception &e) {
81             return false;
82         }
83
84         // Clear and free memory
85         memset(datValue.get_data(), 0, datValue.get_size());
86         free(datValue.get_data());
87         return (ret == 0);
88     }
89
90     template<typename K, typename T>
91     bool Write(const K& key, const T& value, bool fOverwrite=true)
92     {
93         if (!pdb)
94             return false;
95         if (fReadOnly)
96             assert(!"Write called on database in read-only mode");
97
98         // Key
99         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
100         ssKey.reserve(1000);
101         ssKey << key;
102         Dbt datKey(&ssKey[0], ssKey.size());
103
104         // Value
105         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
106         ssValue.reserve(10000);
107         ssValue << value;
108         Dbt datValue(&ssValue[0], ssValue.size());
109
110         // Write
111         int ret = pdb->put(GetTxn(), &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
112
113         // Clear memory in case it was a private key
114         memset(datKey.get_data(), 0, datKey.get_size());
115         memset(datValue.get_data(), 0, datValue.get_size());
116         return (ret == 0);
117     }
118
119     template<typename K>
120     bool Erase(const K& key)
121     {
122         if (!pdb)
123             return false;
124         if (fReadOnly)
125             assert(!"Erase called on database in read-only mode");
126
127         // Key
128         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
129         ssKey.reserve(1000);
130         ssKey << key;
131         Dbt datKey(&ssKey[0], ssKey.size());
132
133         // Erase
134         int ret = pdb->del(GetTxn(), &datKey, 0);
135
136         // Clear memory
137         memset(datKey.get_data(), 0, datKey.get_size());
138         return (ret == 0 || ret == DB_NOTFOUND);
139     }
140
141     template<typename K>
142     bool Exists(const K& key)
143     {
144         if (!pdb)
145             return false;
146
147         // Key
148         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
149         ssKey.reserve(1000);
150         ssKey << key;
151         Dbt datKey(&ssKey[0], ssKey.size());
152
153         // Exists
154         int ret = pdb->exists(GetTxn(), &datKey, 0);
155
156         // Clear memory
157         memset(datKey.get_data(), 0, datKey.get_size());
158         return (ret == 0);
159     }
160
161     Dbc* GetCursor()
162     {
163         if (!pdb)
164             return NULL;
165         Dbc* pcursor = NULL;
166         int ret = pdb->cursor(NULL, &pcursor, 0);
167         if (ret != 0)
168             return NULL;
169         return pcursor;
170     }
171
172     int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT)
173     {
174         // Read at cursor
175         Dbt datKey;
176         if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
177         {
178             datKey.set_data(&ssKey[0]);
179             datKey.set_size(ssKey.size());
180         }
181         Dbt datValue;
182         if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
183         {
184             datValue.set_data(&ssValue[0]);
185             datValue.set_size(ssValue.size());
186         }
187         datKey.set_flags(DB_DBT_MALLOC);
188         datValue.set_flags(DB_DBT_MALLOC);
189         int ret = pcursor->get(&datKey, &datValue, fFlags);
190         if (ret != 0)
191             return ret;
192         else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
193             return 99999;
194
195         // Convert to streams
196         ssKey.SetType(SER_DISK);
197         ssKey.clear();
198         ssKey.write((char*)datKey.get_data(), datKey.get_size());
199         ssValue.SetType(SER_DISK);
200         ssValue.clear();
201         ssValue.write((char*)datValue.get_data(), datValue.get_size());
202
203         // Clear and free memory
204         memset(datKey.get_data(), 0, datKey.get_size());
205         memset(datValue.get_data(), 0, datValue.get_size());
206         free(datKey.get_data());
207         free(datValue.get_data());
208         return 0;
209     }
210
211     DbTxn* GetTxn()
212     {
213         if (!vTxn.empty())
214             return vTxn.back();
215         else
216             return NULL;
217     }
218
219 public:
220     bool TxnBegin()
221     {
222         if (!pdb)
223             return false;
224         DbTxn* ptxn = NULL;
225         int ret = dbenv.txn_begin(GetTxn(), &ptxn, DB_TXN_WRITE_NOSYNC);
226         if (!ptxn || ret != 0)
227             return false;
228         vTxn.push_back(ptxn);
229         return true;
230     }
231
232     bool TxnCommit()
233     {
234         if (!pdb)
235             return false;
236         if (vTxn.empty())
237             return false;
238         int ret = vTxn.back()->commit(0);
239         vTxn.pop_back();
240         return (ret == 0);
241     }
242
243     bool TxnAbort()
244     {
245         if (!pdb)
246             return false;
247         if (vTxn.empty())
248             return false;
249         int ret = vTxn.back()->abort();
250         vTxn.pop_back();
251         return (ret == 0);
252     }
253
254     bool ReadVersion(int& nVersion)
255     {
256         nVersion = 0;
257         return Read(std::string("version"), nVersion);
258     }
259
260     bool WriteVersion(int nVersion)
261     {
262         return Write(std::string("version"), nVersion);
263     }
264
265     bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL);
266 };
267
268
269
270
271
272
273
274 /** Access to the transaction database (blkindex.dat) */
275 class CTxDB : public CDB
276 {
277 public:
278     CTxDB(const char* pszMode="r+") : CDB("blkindex.dat", pszMode) { }
279 private:
280     CTxDB(const CTxDB&);
281     void operator=(const CTxDB&);
282 public:
283     bool ReadTxIndex(uint256 hash, CTxIndex& txindex);
284     bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex);
285     bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight);
286     bool EraseTxIndex(const CTransaction& tx);
287     bool ContainsTx(uint256 hash);
288     bool ReadOwnerTxes(uint160 hash160, int nHeight, std::vector<CTransaction>& vtx);
289     bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex);
290     bool ReadDiskTx(uint256 hash, CTransaction& tx);
291     bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex);
292     bool ReadDiskTx(COutPoint outpoint, CTransaction& tx);
293     bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
294     bool EraseBlockIndex(uint256 hash);
295     bool ReadHashBestChain(uint256& hashBestChain);
296     bool WriteHashBestChain(uint256 hashBestChain);
297     bool ReadBestInvalidTrust(uint64& nBestInvalidTrust);
298     bool WriteBestInvalidTrust(uint64 nBestInvalidTrust);
299     bool ReadSyncCheckpoint(uint256& hashCheckpoint);
300     bool WriteSyncCheckpoint(uint256 hashCheckpoint);
301     bool ReadCheckpointPubKey(std::string& strPubKey);
302     bool WriteCheckpointPubKey(const std::string& strPubKey);
303     bool LoadBlockIndex();
304 };
305
306
307
308
309 /** Access to the (IP) address database (addr.dat) */
310 class CAddrDB : public CDB
311 {
312 public:
313     CAddrDB(const char* pszMode="r+") : CDB("addr.dat", pszMode) { }
314 private:
315     CAddrDB(const CAddrDB&);
316     void operator=(const CAddrDB&);
317 public:
318     bool WriteAddrman(const CAddrMan& addr);
319     bool LoadAddresses();
320 };
321
322 bool LoadAddresses();
323
324
325 #endif // BITCOIN_DB_H