Further reduce header dependencies
[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 license.txt 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 DbEnv dbenv;
29
30 extern void DBFlush(bool fShutdown);
31 void ThreadFlushWalletDB(void* parg);
32 bool BackupWallet(const CWallet& wallet, const std::string& strDest);
33
34
35 /** RAII class that provides access to a Berkeley database */
36 class CDB
37 {
38 protected:
39     Db* pdb;
40     std::string strFile;
41     std::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, CLIENT_VERSION);
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, CLIENT_VERSION);
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");
90
91         // Key
92         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
93         ssKey.reserve(1000);
94         ssKey << key;
95         Dbt datKey(&ssKey[0], ssKey.size());
96
97         // Value
98         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
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");
119
120         // Key
121         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
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, CLIENT_VERSION);
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(std::string("version"), nVersion);
251     }
252
253     bool WriteVersion(int nVersion)
254     {
255         return Write(std::string("version"), nVersion);
256     }
257
258     bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL);
259 };
260
261
262
263
264
265
266
267 /** Access to the transaction database (blkindex.dat) */
268 class CTxDB : public CDB
269 {
270 public:
271     CTxDB(const char* pszMode="r+") : CDB("blkindex.dat", pszMode) { }
272 private:
273     CTxDB(const CTxDB&);
274     void operator=(const CTxDB&);
275 public:
276     bool ReadTxIndex(uint256 hash, CTxIndex& txindex);
277     bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex);
278     bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight);
279     bool EraseTxIndex(const CTransaction& tx);
280     bool ContainsTx(uint256 hash);
281     bool ReadOwnerTxes(uint160 hash160, int nHeight, std::vector<CTransaction>& vtx);
282     bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex);
283     bool ReadDiskTx(uint256 hash, CTransaction& tx);
284     bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex);
285     bool ReadDiskTx(COutPoint outpoint, CTransaction& tx);
286     bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
287     bool EraseBlockIndex(uint256 hash);
288     bool ReadHashBestChain(uint256& hashBestChain);
289     bool WriteHashBestChain(uint256 hashBestChain);
290     bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork);
291     bool WriteBestInvalidWork(CBigNum bnBestInvalidWork);
292     bool LoadBlockIndex();
293 };
294
295
296
297
298 /** Access to the (IP) address database (addr.dat) */
299 class CAddrDB : public CDB
300 {
301 public:
302     CAddrDB(const char* pszMode="r+") : CDB("addr.dat", pszMode) { }
303 private:
304     CAddrDB(const CAddrDB&);
305     void operator=(const CAddrDB&);
306 public:
307     bool WriteAddrman(const CAddrMan& addr);
308     bool LoadAddresses();
309 };
310
311 bool LoadAddresses();
312
313
314 #endif // BITCOIN_DB_H