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