automatically change displayed address whenever it receives anything,
[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 \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, 0);\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 LoadBlockIndex();\r
284 };\r
285 \r
286 \r
287 \r
288 \r
289 \r
290 class CAddrDB : public CDB\r
291 {\r
292 public:\r
293     CAddrDB(const char* pszMode="r+") : CDB("addr.dat", pszMode) { }\r
294 private:\r
295     CAddrDB(const CAddrDB&);\r
296     void operator=(const CAddrDB&);\r
297 public:\r
298     bool WriteAddress(const CAddress& addr);\r
299     bool LoadAddresses();\r
300 };\r
301 \r
302 bool LoadAddresses();\r
303 \r
304 \r
305 \r
306 \r
307 \r
308 \r
309 class CWalletDB : public CDB\r
310 {\r
311 public:\r
312     CWalletDB(const char* pszMode="r+") : CDB("wallet.dat", pszMode) { }\r
313 private:\r
314     CWalletDB(const CWalletDB&);\r
315     void operator=(const CWalletDB&);\r
316 public:\r
317     bool ReadName(const string& strAddress, string& strName)\r
318     {\r
319         strName = "";\r
320         return Read(make_pair(string("name"), strAddress), strName);\r
321     }\r
322 \r
323     bool WriteName(const string& strAddress, const string& strName)\r
324     {\r
325         CRITICAL_BLOCK(cs_mapAddressBook)\r
326             mapAddressBook[strAddress] = strName;\r
327         nWalletDBUpdated++;\r
328         return Write(make_pair(string("name"), strAddress), strName);\r
329     }\r
330 \r
331     bool EraseName(const string& strAddress)\r
332     {\r
333         // This should only be used for sending addresses, never for receiving addresses,\r
334         // receiving addresses must always have an address book entry if they're not change return.\r
335         CRITICAL_BLOCK(cs_mapAddressBook)\r
336             mapAddressBook.erase(strAddress);\r
337         nWalletDBUpdated++;\r
338         return Erase(make_pair(string("name"), strAddress));\r
339     }\r
340 \r
341     bool ReadTx(uint256 hash, CWalletTx& wtx)\r
342     {\r
343         return Read(make_pair(string("tx"), hash), wtx);\r
344     }\r
345 \r
346     bool WriteTx(uint256 hash, const CWalletTx& wtx)\r
347     {\r
348         nWalletDBUpdated++;\r
349         return Write(make_pair(string("tx"), hash), wtx);\r
350     }\r
351 \r
352     bool EraseTx(uint256 hash)\r
353     {\r
354         nWalletDBUpdated++;\r
355         return Erase(make_pair(string("tx"), hash));\r
356     }\r
357 \r
358     bool ReadKey(const vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey)\r
359     {\r
360         vchPrivKey.clear();\r
361         return Read(make_pair(string("key"), vchPubKey), vchPrivKey);\r
362     }\r
363 \r
364     bool WriteKey(const vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)\r
365     {\r
366         nWalletDBUpdated++;\r
367         return Write(make_pair(string("key"), vchPubKey), vchPrivKey, false);\r
368     }\r
369 \r
370     bool ReadDefaultKey(vector<unsigned char>& vchPubKey)\r
371     {\r
372         vchPubKey.clear();\r
373         return Read(string("defaultkey"), vchPubKey);\r
374     }\r
375 \r
376     bool WriteDefaultKey(const vector<unsigned char>& vchPubKey)\r
377     {\r
378         vchDefaultKey = vchPubKey;\r
379         nWalletDBUpdated++;\r
380         return Write(string("defaultkey"), vchPubKey);\r
381     }\r
382 \r
383     template<typename T>\r
384     bool ReadSetting(const string& strKey, T& value)\r
385     {\r
386         return Read(make_pair(string("setting"), strKey), value);\r
387     }\r
388 \r
389     template<typename T>\r
390     bool WriteSetting(const string& strKey, const T& value)\r
391     {\r
392         nWalletDBUpdated++;\r
393         return Write(make_pair(string("setting"), strKey), value);\r
394     }\r
395 \r
396     bool LoadWallet();\r
397 };\r
398 \r
399 bool LoadWallet(bool& fFirstRunRet);\r
400 \r
401 inline bool SetAddressBookName(const string& strAddress, const string& strName)\r
402 {\r
403     return CWalletDB().WriteName(strAddress, strName);\r
404 }\r