new safety feature displays a warning message and locks down RPC if it detects a...
[novacoin.git] / db.h
1 // Copyright (c) 2009-2010 Satoshi Nakamoto\r
2 // Distributed under the MIT/X11 software license, see the accompanying\r
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.\r
4 \r
5 class CTransaction;\r
6 class CTxIndex;\r
7 class CDiskBlockIndex;\r
8 class CDiskTxPos;\r
9 class COutPoint;\r
10 class CUser;\r
11 class CReview;\r
12 class CAddress;\r
13 class CWalletTx;\r
14 \r
15 extern map<string, string> mapAddressBook;\r
16 extern CCriticalSection cs_mapAddressBook;\r
17 extern vector<unsigned char> vchDefaultKey;\r
18 extern bool fClient;\r
19 extern int nBestHeight;\r
20 \r
21 \r
22 extern unsigned int nWalletDBUpdated;\r
23 extern DbEnv dbenv;\r
24 \r
25 \r
26 extern void DBFlush(bool fShutdown);\r
27 \r
28 \r
29 \r
30 \r
31 class CDB\r
32 {\r
33 protected:\r
34     Db* pdb;\r
35     string strFile;\r
36     vector<DbTxn*> vTxn;\r
37     bool fReadOnly;\r
38 \r
39     explicit CDB(const char* pszFile, const char* pszMode="r+");\r
40     ~CDB() { Close(); }\r
41 public:\r
42     void Close();\r
43 private:\r
44     CDB(const CDB&);\r
45     void operator=(const CDB&);\r
46 \r
47 protected:\r
48     template<typename K, typename T>\r
49     bool Read(const K& key, T& value)\r
50     {\r
51         if (!pdb)\r
52             return false;\r
53 \r
54         // Key\r
55         CDataStream ssKey(SER_DISK);\r
56         ssKey.reserve(1000);\r
57         ssKey << key;\r
58         Dbt datKey(&ssKey[0], ssKey.size());\r
59 \r
60         // Read\r
61         Dbt datValue;\r
62         datValue.set_flags(DB_DBT_MALLOC);\r
63         int ret = pdb->get(GetTxn(), &datKey, &datValue, 0);\r
64         memset(datKey.get_data(), 0, datKey.get_size());\r
65         if (datValue.get_data() == NULL)\r
66             return false;\r
67 \r
68         // Unserialize value\r
69         CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK);\r
70         ssValue >> value;\r
71 \r
72         // Clear and free memory\r
73         memset(datValue.get_data(), 0, datValue.get_size());\r
74         free(datValue.get_data());\r
75         return (ret == 0);\r
76     }\r
77 \r
78     template<typename K, typename T>\r
79     bool Write(const K& key, const T& value, bool fOverwrite=true)\r
80     {\r
81         if (!pdb)\r
82             return false;\r
83         if (fReadOnly)\r
84             assert(("Write called on database in read-only mode", false));\r
85 \r
86         // Key\r
87         CDataStream ssKey(SER_DISK);\r
88         ssKey.reserve(1000);\r
89         ssKey << key;\r
90         Dbt datKey(&ssKey[0], ssKey.size());\r
91 \r
92         // Value\r
93         CDataStream ssValue(SER_DISK);\r
94         ssValue.reserve(10000);\r
95         ssValue << value;\r
96         Dbt datValue(&ssValue[0], ssValue.size());\r
97 \r
98         // Write\r
99         int ret = pdb->put(GetTxn(), &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));\r
100 \r
101         // Clear memory in case it was a private key\r
102         memset(datKey.get_data(), 0, datKey.get_size());\r
103         memset(datValue.get_data(), 0, datValue.get_size());\r
104         return (ret == 0);\r
105     }\r
106 \r
107     template<typename K>\r
108     bool Erase(const K& key)\r
109     {\r
110         if (!pdb)\r
111             return false;\r
112         if (fReadOnly)\r
113             assert(("Erase called on database in read-only mode", false));\r
114 \r
115         // Key\r
116         CDataStream ssKey(SER_DISK);\r
117         ssKey.reserve(1000);\r
118         ssKey << key;\r
119         Dbt datKey(&ssKey[0], ssKey.size());\r
120 \r
121         // Erase\r
122         int ret = pdb->del(GetTxn(), &datKey, 0);\r
123 \r
124         // Clear memory\r
125         memset(datKey.get_data(), 0, datKey.get_size());\r
126         return (ret == 0 || ret == DB_NOTFOUND);\r
127     }\r
128 \r
129     template<typename K>\r
130     bool Exists(const K& key)\r
131     {\r
132         if (!pdb)\r
133             return false;\r
134 \r
135         // Key\r
136         CDataStream ssKey(SER_DISK);\r
137         ssKey.reserve(1000);\r
138         ssKey << key;\r
139         Dbt datKey(&ssKey[0], ssKey.size());\r
140 \r
141         // Exists\r
142         int ret = pdb->exists(GetTxn(), &datKey, 0);\r
143 \r
144         // Clear memory\r
145         memset(datKey.get_data(), 0, datKey.get_size());\r
146         return (ret == 0);\r
147     }\r
148 \r
149     Dbc* GetCursor()\r
150     {\r
151         if (!pdb)\r
152             return NULL;\r
153         Dbc* pcursor = NULL;\r
154         int ret = pdb->cursor(NULL, &pcursor, 0);\r
155         if (ret != 0)\r
156             return NULL;\r
157         return pcursor;\r
158     }\r
159 \r
160     int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT)\r
161     {\r
162         // Read at cursor\r
163         Dbt datKey;\r
164         if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)\r
165         {\r
166             datKey.set_data(&ssKey[0]);\r
167             datKey.set_size(ssKey.size());\r
168         }\r
169         Dbt datValue;\r
170         if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)\r
171         {\r
172             datValue.set_data(&ssValue[0]);\r
173             datValue.set_size(ssValue.size());\r
174         }\r
175         datKey.set_flags(DB_DBT_MALLOC);\r
176         datValue.set_flags(DB_DBT_MALLOC);\r
177         int ret = pcursor->get(&datKey, &datValue, fFlags);\r
178         if (ret != 0)\r
179             return ret;\r
180         else if (datKey.get_data() == NULL || datValue.get_data() == NULL)\r
181             return 99999;\r
182 \r
183         // Convert to streams\r
184         ssKey.SetType(SER_DISK);\r
185         ssKey.clear();\r
186         ssKey.write((char*)datKey.get_data(), datKey.get_size());\r
187         ssValue.SetType(SER_DISK);\r
188         ssValue.clear();\r
189         ssValue.write((char*)datValue.get_data(), datValue.get_size());\r
190 \r
191         // Clear and free memory\r
192         memset(datKey.get_data(), 0, datKey.get_size());\r
193         memset(datValue.get_data(), 0, datValue.get_size());\r
194         free(datKey.get_data());\r
195         free(datValue.get_data());\r
196         return 0;\r
197     }\r
198 \r
199     DbTxn* GetTxn()\r
200     {\r
201         if (!vTxn.empty())\r
202             return vTxn.back();\r
203         else\r
204             return NULL;\r
205     }\r
206 \r
207 public:\r
208     bool TxnBegin()\r
209     {\r
210         if (!pdb)\r
211             return false;\r
212         DbTxn* ptxn = NULL;\r
213         int ret = dbenv.txn_begin(GetTxn(), &ptxn, DB_TXN_NOSYNC);\r
214         if (!ptxn || ret != 0)\r
215             return false;\r
216         vTxn.push_back(ptxn);\r
217         return true;\r
218     }\r
219 \r
220     bool TxnCommit()\r
221     {\r
222         if (!pdb)\r
223             return false;\r
224         if (vTxn.empty())\r
225             return false;\r
226         int ret = vTxn.back()->commit(0);\r
227         vTxn.pop_back();\r
228         return (ret == 0);\r
229     }\r
230 \r
231     bool TxnAbort()\r
232     {\r
233         if (!pdb)\r
234             return false;\r
235         if (vTxn.empty())\r
236             return false;\r
237         int ret = vTxn.back()->abort();\r
238         vTxn.pop_back();\r
239         return (ret == 0);\r
240     }\r
241 \r
242     bool ReadVersion(int& nVersion)\r
243     {\r
244         nVersion = 0;\r
245         return Read(string("version"), nVersion);\r
246     }\r
247 \r
248     bool WriteVersion(int nVersion)\r
249     {\r
250         return Write(string("version"), nVersion);\r
251     }\r
252 };\r
253 \r
254 \r
255 \r
256 \r
257 \r
258 \r
259 \r
260 \r
261 class CTxDB : public CDB\r
262 {\r
263 public:\r
264     CTxDB(const char* pszMode="r+") : CDB(!fClient ? "blkindex.dat" : NULL, pszMode) { }\r
265 private:\r
266     CTxDB(const CTxDB&);\r
267     void operator=(const CTxDB&);\r
268 public:\r
269     bool ReadTxIndex(uint256 hash, CTxIndex& txindex);\r
270     bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex);\r
271     bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight);\r
272     bool EraseTxIndex(const CTransaction& tx);\r
273     bool ContainsTx(uint256 hash);\r
274     bool ReadOwnerTxes(uint160 hash160, int nHeight, vector<CTransaction>& vtx);\r
275     bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex);\r
276     bool ReadDiskTx(uint256 hash, CTransaction& tx);\r
277     bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex);\r
278     bool ReadDiskTx(COutPoint outpoint, CTransaction& tx);\r
279     bool WriteBlockIndex(const CDiskBlockIndex& blockindex);\r
280     bool EraseBlockIndex(uint256 hash);\r
281     bool ReadHashBestChain(uint256& hashBestChain);\r
282     bool WriteHashBestChain(uint256 hashBestChain);\r
283     bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork);\r
284     bool WriteBestInvalidWork(CBigNum bnBestInvalidWork);\r
285     bool LoadBlockIndex();\r
286 };\r
287 \r
288 \r
289 \r
290 \r
291 \r
292 class CAddrDB : public CDB\r
293 {\r
294 public:\r
295     CAddrDB(const char* pszMode="r+") : CDB("addr.dat", pszMode) { }\r
296 private:\r
297     CAddrDB(const CAddrDB&);\r
298     void operator=(const CAddrDB&);\r
299 public:\r
300     bool WriteAddress(const CAddress& addr);\r
301     bool LoadAddresses();\r
302 };\r
303 \r
304 bool LoadAddresses();\r
305 \r
306 \r
307 \r
308 \r
309 \r
310 \r
311 class CWalletDB : public CDB\r
312 {\r
313 public:\r
314     CWalletDB(const char* pszMode="r+") : CDB("wallet.dat", pszMode) { }\r
315 private:\r
316     CWalletDB(const CWalletDB&);\r
317     void operator=(const CWalletDB&);\r
318 public:\r
319     bool ReadName(const string& strAddress, string& strName)\r
320     {\r
321         strName = "";\r
322         return Read(make_pair(string("name"), strAddress), strName);\r
323     }\r
324 \r
325     bool WriteName(const string& strAddress, const string& strName)\r
326     {\r
327         CRITICAL_BLOCK(cs_mapAddressBook)\r
328             mapAddressBook[strAddress] = strName;\r
329         nWalletDBUpdated++;\r
330         return Write(make_pair(string("name"), strAddress), strName);\r
331     }\r
332 \r
333     bool EraseName(const string& strAddress)\r
334     {\r
335         // This should only be used for sending addresses, never for receiving addresses,\r
336         // receiving addresses must always have an address book entry if they're not change return.\r
337         CRITICAL_BLOCK(cs_mapAddressBook)\r
338             mapAddressBook.erase(strAddress);\r
339         nWalletDBUpdated++;\r
340         return Erase(make_pair(string("name"), strAddress));\r
341     }\r
342 \r
343     bool ReadTx(uint256 hash, CWalletTx& wtx)\r
344     {\r
345         return Read(make_pair(string("tx"), hash), wtx);\r
346     }\r
347 \r
348     bool WriteTx(uint256 hash, const CWalletTx& wtx)\r
349     {\r
350         nWalletDBUpdated++;\r
351         return Write(make_pair(string("tx"), hash), wtx);\r
352     }\r
353 \r
354     bool EraseTx(uint256 hash)\r
355     {\r
356         nWalletDBUpdated++;\r
357         return Erase(make_pair(string("tx"), hash));\r
358     }\r
359 \r
360     bool ReadKey(const vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey)\r
361     {\r
362         vchPrivKey.clear();\r
363         return Read(make_pair(string("key"), vchPubKey), vchPrivKey);\r
364     }\r
365 \r
366     bool WriteKey(const vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)\r
367     {\r
368         nWalletDBUpdated++;\r
369         return Write(make_pair(string("key"), vchPubKey), vchPrivKey, false);\r
370     }\r
371 \r
372     bool ReadDefaultKey(vector<unsigned char>& vchPubKey)\r
373     {\r
374         vchPubKey.clear();\r
375         return Read(string("defaultkey"), vchPubKey);\r
376     }\r
377 \r
378     bool WriteDefaultKey(const vector<unsigned char>& vchPubKey)\r
379     {\r
380         vchDefaultKey = vchPubKey;\r
381         nWalletDBUpdated++;\r
382         return Write(string("defaultkey"), vchPubKey);\r
383     }\r
384 \r
385     template<typename T>\r
386     bool ReadSetting(const string& strKey, T& value)\r
387     {\r
388         return Read(make_pair(string("setting"), strKey), value);\r
389     }\r
390 \r
391     template<typename T>\r
392     bool WriteSetting(const string& strKey, const T& value)\r
393     {\r
394         nWalletDBUpdated++;\r
395         return Write(make_pair(string("setting"), strKey), value);\r
396     }\r
397 \r
398     bool LoadWallet();\r
399 };\r
400 \r
401 bool LoadWallet(bool& fFirstRunRet);\r
402 \r
403 inline bool SetAddressBookName(const string& strAddress, const string& strName)\r
404 {\r
405     return CWalletDB().WriteName(strAddress, strName);\r
406 }\r