Miner module fix
[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 CMasterKey;
21 class COutPoint;
22 class CWallet;
23 class CWalletTx;
24
25 extern unsigned int nWalletDBUpdated;
26
27 void ThreadFlushWalletDB(void* parg);
28 bool BackupWallet(const CWallet& wallet, const std::string& strDest);
29
30
31 class CDBEnv
32 {
33 private:
34     bool fDetachDB;
35     bool fDbEnvInit;
36     bool fMockDb;
37     boost::filesystem::path pathEnv;
38
39     void EnvShutdown();
40
41 public:
42     mutable CCriticalSection cs_db;
43     DbEnv dbenv;
44     std::map<std::string, int> mapFileUseCount;
45     std::map<std::string, Db*> mapDb;
46
47     CDBEnv();
48     ~CDBEnv();
49     void MakeMock();
50     bool IsMock() { return fMockDb; };
51
52     /*
53      * Verify that database file strFile is OK. If it is not,
54      * call the callback to try to recover.
55      * This must be called BEFORE strFile is opened.
56      * Returns true if strFile is OK.
57      */
58     enum VerifyResult { VERIFY_OK, RECOVER_OK, RECOVER_FAIL };
59     VerifyResult Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile));
60     /*
61      * Salvage data from a file that Verify says is bad.
62      * fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation).
63      * Appends binary key/value pairs to vResult, returns true if successful.
64      * NOTE: reads the entire database into memory, so cannot be used
65      * for huge databases.
66      */
67     typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
68     bool Salvage(std::string strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
69
70     bool Open(boost::filesystem::path pathEnv_);
71     void Close();
72     void Flush(bool fShutdown);
73     void CheckpointLSN(std::string strFile);
74     void SetDetach(bool fDetachDB_) { fDetachDB = fDetachDB_; }
75     bool GetDetach() { return fDetachDB; }
76
77     void CloseDb(const std::string& strFile);
78     bool RemoveDb(const std::string& strFile);
79
80     DbTxn *TxnBegin(int flags=DB_TXN_WRITE_NOSYNC)
81     {
82         DbTxn* ptxn = NULL;
83         int ret = dbenv.txn_begin(NULL, &ptxn, flags);
84         if (!ptxn || ret != 0)
85             return NULL;
86         return ptxn;
87     }
88 };
89
90 extern CDBEnv bitdb;
91
92
93 /** RAII class that provides access to a Berkeley database */
94 class CDB
95 {
96 protected:
97     Db* pdb;
98     std::string strFile;
99     DbTxn *activeTxn;
100     bool fReadOnly;
101
102     explicit CDB(const char* pszFile, const char* pszMode="r+");
103     ~CDB() { Close(); }
104 public:
105     void Flush();
106     void Close();
107 private:
108     CDB(const CDB&);
109     void operator=(const CDB&);
110
111 protected:
112     template<typename K, typename T>
113     bool Read(const K& key, T& value)
114     {
115         if (!pdb)
116             return false;
117
118         // Key
119         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
120         ssKey.reserve(1000);
121         ssKey << key;
122         Dbt datKey(&ssKey[0], ssKey.size());
123
124         // Read
125         Dbt datValue;
126         datValue.set_flags(DB_DBT_MALLOC);
127         int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
128         memset(datKey.get_data(), 0, datKey.get_size());
129         if (datValue.get_data() == NULL)
130             return false;
131
132         // Unserialize value
133         try {
134             CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
135             ssValue >> value;
136         }
137         catch (std::exception &e) {
138             return false;
139         }
140
141         // Clear and free memory
142         memset(datValue.get_data(), 0, datValue.get_size());
143         free(datValue.get_data());
144         return (ret == 0);
145     }
146
147     template<typename K, typename T>
148     bool Write(const K& key, const T& value, bool fOverwrite=true)
149     {
150         if (!pdb)
151             return false;
152         if (fReadOnly)
153             assert(!"Write called on database in read-only mode");
154
155         // Key
156         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
157         ssKey.reserve(1000);
158         ssKey << key;
159         Dbt datKey(&ssKey[0], ssKey.size());
160
161         // Value
162         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
163         ssValue.reserve(10000);
164         ssValue << value;
165         Dbt datValue(&ssValue[0], ssValue.size());
166
167         // Write
168         int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
169
170         // Clear memory in case it was a private key
171         memset(datKey.get_data(), 0, datKey.get_size());
172         memset(datValue.get_data(), 0, datValue.get_size());
173         return (ret == 0);
174     }
175
176     template<typename K>
177     bool Erase(const K& key)
178     {
179         if (!pdb)
180             return false;
181         if (fReadOnly)
182             assert(!"Erase called on database in read-only mode");
183
184         // Key
185         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
186         ssKey.reserve(1000);
187         ssKey << key;
188         Dbt datKey(&ssKey[0], ssKey.size());
189
190         // Erase
191         int ret = pdb->del(activeTxn, &datKey, 0);
192
193         // Clear memory
194         memset(datKey.get_data(), 0, datKey.get_size());
195         return (ret == 0 || ret == DB_NOTFOUND);
196     }
197
198     template<typename K>
199     bool Exists(const K& key)
200     {
201         if (!pdb)
202             return false;
203
204         // Key
205         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
206         ssKey.reserve(1000);
207         ssKey << key;
208         Dbt datKey(&ssKey[0], ssKey.size());
209
210         // Exists
211         int ret = pdb->exists(activeTxn, &datKey, 0);
212
213         // Clear memory
214         memset(datKey.get_data(), 0, datKey.get_size());
215         return (ret == 0);
216     }
217
218     Dbc* GetCursor()
219     {
220         if (!pdb)
221             return NULL;
222         Dbc* pcursor = NULL;
223         int ret = pdb->cursor(NULL, &pcursor, 0);
224         if (ret != 0)
225             return NULL;
226         return pcursor;
227     }
228
229     int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT)
230     {
231         // Read at cursor
232         Dbt datKey;
233         if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
234         {
235             datKey.set_data(&ssKey[0]);
236             datKey.set_size(ssKey.size());
237         }
238         Dbt datValue;
239         if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
240         {
241             datValue.set_data(&ssValue[0]);
242             datValue.set_size(ssValue.size());
243         }
244         datKey.set_flags(DB_DBT_MALLOC);
245         datValue.set_flags(DB_DBT_MALLOC);
246         int ret = pcursor->get(&datKey, &datValue, fFlags);
247         if (ret != 0)
248             return ret;
249         else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
250             return 99999;
251
252         // Convert to streams
253         ssKey.SetType(SER_DISK);
254         ssKey.clear();
255         ssKey.write((char*)datKey.get_data(), datKey.get_size());
256         ssValue.SetType(SER_DISK);
257         ssValue.clear();
258         ssValue.write((char*)datValue.get_data(), datValue.get_size());
259
260         // Clear and free memory
261         memset(datKey.get_data(), 0, datKey.get_size());
262         memset(datValue.get_data(), 0, datValue.get_size());
263         free(datKey.get_data());
264         free(datValue.get_data());
265         return 0;
266     }
267
268 public:
269     bool TxnBegin()
270     {
271         if (!pdb || activeTxn)
272             return false;
273         DbTxn* ptxn = bitdb.TxnBegin();
274         if (!ptxn)
275             return false;
276         activeTxn = ptxn;
277         return true;
278     }
279
280     bool TxnCommit()
281     {
282         if (!pdb || !activeTxn)
283             return false;
284         int ret = activeTxn->commit(0);
285         activeTxn = NULL;
286         return (ret == 0);
287     }
288
289     bool TxnAbort()
290     {
291         if (!pdb || !activeTxn)
292             return false;
293         int ret = activeTxn->abort();
294         activeTxn = NULL;
295         return (ret == 0);
296     }
297
298     bool ReadVersion(int& nVersion)
299     {
300         nVersion = 0;
301         return Read(std::string("version"), nVersion);
302     }
303
304     bool WriteVersion(int nVersion)
305     {
306         return Write(std::string("version"), nVersion);
307     }
308
309     bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL);
310 };
311
312
313
314
315
316
317
318 /** Access to the transaction database (coins.dat) */
319 class CCoinsDB : public CDB
320 {
321 public:
322     CCoinsDB(const char* pszMode="r+") : CDB("coins.dat", pszMode) { }
323 private:
324     CCoinsDB(const CCoinsDB&);
325     void operator=(const CCoinsDB&);
326 public:
327     bool ReadCoins(uint256 hash, CCoins &coins);
328     bool WriteCoins(uint256 hash, const CCoins& coins);
329     bool HaveCoins(uint256 hash);
330     bool ReadHashBestChain(uint256& hashBestChain);
331     bool WriteHashBestChain(uint256 hashBestChain);
332 };
333
334
335 /** CCoinsView backed by a CCoinsDB */
336 class CCoinsViewDB : public CCoinsView
337 {
338 protected:
339     CCoinsDB db;
340 public:
341     CCoinsViewDB();
342     bool GetCoins(uint256 txid, CCoins &coins);
343     bool SetCoins(uint256 txid, const CCoins &coins);
344     bool HaveCoins(uint256 txid);
345     CBlockIndex *GetBestBlock();
346     bool SetBestBlock(CBlockIndex *pindex);
347     bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
348 };
349
350
351 /** Access to the block database (chain.dat) */
352 class CChainDB : public CDB
353 {
354 public:
355     CChainDB(const char* pszMode="r+") : CDB("chain.dat", pszMode) { }
356 private:
357     CChainDB(const CChainDB&);
358     void operator=(const CChainDB&);
359 public:
360     bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
361     bool ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust);
362     bool WriteBestInvalidTrust(CBigNum bnBestInvalidTrust);
363     bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo);
364     bool WriteBlockFileInfo(int nFile, const CBlockFileInfo &fileinfo);
365     bool ReadLastBlockFile(int &nFile);
366     bool WriteLastBlockFile(int nFile);
367     bool ReadSyncCheckpoint(uint256& hashCheckpoint);
368     bool WriteSyncCheckpoint(uint256 hashCheckpoint);
369     bool ReadCheckpointPubKey(std::string& strPubKey);
370     bool WriteCheckpointPubKey(const std::string& strPubKey);
371     bool LoadBlockIndexGuts();
372 };
373
374
375 bool LoadBlockIndex(CChainDB &chaindb);
376
377
378 /** Access to the (IP) address database (peers.dat) */
379 class CAddrDB
380 {
381 private:
382     boost::filesystem::path pathAddr;
383 public:
384     CAddrDB();
385     bool Write(const CAddrMan& addr);
386     bool Read(CAddrMan& addr);
387 };
388
389 #endif // BITCOIN_DB_H