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