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