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