upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/db.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/db.h')
-rw-r--r--src/db.h546
1 files changed, 546 insertions, 0 deletions
diff --git a/src/db.h b/src/db.h
new file mode 100644
index 0000000..4fb5cfd
--- /dev/null
+++ b/src/db.h
@@ -0,0 +1,546 @@
1// Copyright (c) 2009 Satoshi Nakamoto
2// Distributed under the MIT/X11 software license, see the accompanying
3// file license.txt or http://www.opensource.org/licenses/mit-license.php.
4
5#include <db_cxx.h>
6class CTransaction;
7class CTxIndex;
8class CDiskBlockIndex;
9class CDiskTxPos;
10class COutPoint;
11class CUser;
12class CReview;
13class CAddress;
14class CWalletTx;
15
16extern map<string, string> mapAddressBook;
17extern bool fClient;
18
19// Wallet file format guard. The current wallet stores private keys in plain
20// records. The next format will encrypt them; builds that do not implement it
21// must stop before they can show an empty-looking wallet.
22static const int WALLET_FORMAT_PLAINTEXT = 1;
23static const int WALLET_FORMAT_ENCRYPTED = 2;
24static const int WALLET_FORMAT_SUPPORTED = WALLET_FORMAT_ENCRYPTED;
25
26class CWalletMasterKey
27{
28public:
29 vector<unsigned char> vchCryptedKey;
30 vector<unsigned char> vchSalt;
31 unsigned int nDerivationMethod;
32 unsigned int nDeriveIterations;
33
34 CWalletMasterKey()
35 {
36 nDerivationMethod = 0;
37 nDeriveIterations = 25000;
38 vchSalt.resize(8);
39 }
40
41 IMPLEMENT_SERIALIZE
42 (
43 READWRITE(vchCryptedKey);
44 READWRITE(vchSalt);
45 READWRITE(nDerivationMethod);
46 READWRITE(nDeriveIterations);
47 )
48};
49
50
51extern DbEnv dbenv;
52extern void DBFlush(bool fShutdown);
53// Close the environment and delete its logs. Only the encryption command calls
54// this: the logs hold the plaintext records the old wallet wrote.
55extern void PurgeDbEnvironmentLogs();
56
57// Set by LoadWallet() when it refuses for a reason worth telling the user.
58extern string strWalletLoadError;
59
60
61
62
63class CDB
64{
65protected:
66 Db* pdb;
67 string strFile;
68 vector<DbTxn*> vTxn;
69
70 explicit CDB(const char* pszFile, const char* pszMode="r+", bool fTxn=false);
71 ~CDB() { Close(); }
72public:
73 void Close();
74private:
75 CDB(const CDB&);
76 void operator=(const CDB&);
77
78protected:
79 template<typename K, typename T>
80 bool Read(const K& key, T& value)
81 {
82 if (!pdb)
83 return false;
84
85 // Key
86 CDataStream ssKey(SER_DISK);
87 ssKey.reserve(1000);
88 ssKey << key;
89 Dbt datKey(&ssKey[0], ssKey.size());
90
91 // Read
92 Dbt datValue;
93 datValue.set_flags(DB_DBT_MALLOC);
94 int ret = pdb->get(GetTxn(), &datKey, &datValue, 0);
95 memset(datKey.get_data(), 0, datKey.get_size());
96 if (datValue.get_data() == NULL)
97 return false;
98
99 // Unserialize value
100 CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK);
101 ssValue >> value;
102
103 // Clear and free memory
104 memset(datValue.get_data(), 0, datValue.get_size());
105 free(datValue.get_data());
106 return (ret == 0);
107 }
108
109 template<typename K, typename T>
110 bool Write(const K& key, const T& value, bool fOverwrite=true)
111 {
112 if (!pdb)
113 return false;
114
115 // Key
116 CDataStream ssKey(SER_DISK);
117 ssKey.reserve(1000);
118 ssKey << key;
119 Dbt datKey(&ssKey[0], ssKey.size());
120
121 // Value
122 CDataStream ssValue(SER_DISK);
123 ssValue.reserve(10000);
124 ssValue << value;
125 Dbt datValue(&ssValue[0], ssValue.size());
126
127 // Write
128 int ret = pdb->put(GetTxn(), &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
129
130 // Clear memory in case it was a private key
131 memset(datKey.get_data(), 0, datKey.get_size());
132 memset(datValue.get_data(), 0, datValue.get_size());
133 return (ret == 0);
134 }
135
136 template<typename K>
137 bool Erase(const K& key)
138 {
139 if (!pdb)
140 return false;
141
142 // Key
143 CDataStream ssKey(SER_DISK);
144 ssKey.reserve(1000);
145 ssKey << key;
146 Dbt datKey(&ssKey[0], ssKey.size());
147
148 // Erase
149 int ret = pdb->del(GetTxn(), &datKey, 0);
150
151 // Clear memory
152 memset(datKey.get_data(), 0, datKey.get_size());
153 return (ret == 0 || ret == DB_NOTFOUND);
154 }
155
156 template<typename K>
157 bool Exists(const K& key)
158 {
159 if (!pdb)
160 return false;
161
162 // Key
163 CDataStream ssKey(SER_DISK);
164 ssKey.reserve(1000);
165 ssKey << key;
166 Dbt datKey(&ssKey[0], ssKey.size());
167
168 // Exists
169 int ret = pdb->exists(GetTxn(), &datKey, 0);
170
171 // Clear memory
172 memset(datKey.get_data(), 0, datKey.get_size());
173 return (ret == 0);
174 }
175
176 Dbc* GetCursor()
177 {
178 if (!pdb)
179 return NULL;
180 Dbc* pcursor = NULL;
181 int ret = pdb->cursor(NULL, &pcursor, 0);
182 if (ret != 0)
183 return NULL;
184 return pcursor;
185 }
186
187 int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT)
188 {
189 // Read at cursor
190 Dbt datKey;
191 if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
192 {
193 datKey.set_data(&ssKey[0]);
194 datKey.set_size(ssKey.size());
195 }
196 Dbt datValue;
197 if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
198 {
199 datValue.set_data(&ssValue[0]);
200 datValue.set_size(ssValue.size());
201 }
202 datKey.set_flags(DB_DBT_MALLOC);
203 datValue.set_flags(DB_DBT_MALLOC);
204 int ret = pcursor->get(&datKey, &datValue, fFlags);
205 if (ret != 0)
206 return ret;
207 else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
208 return 99999;
209
210 // Convert to streams
211 ssKey.SetType(SER_DISK);
212 ssKey.clear();
213 ssKey.write((char*)datKey.get_data(), datKey.get_size());
214 ssValue.SetType(SER_DISK);
215 ssValue.clear();
216 ssValue.write((char*)datValue.get_data(), datValue.get_size());
217
218 // Clear and free memory
219 memset(datKey.get_data(), 0, datKey.get_size());
220 memset(datValue.get_data(), 0, datValue.get_size());
221 free(datKey.get_data());
222 free(datValue.get_data());
223 return 0;
224 }
225
226 DbTxn* GetTxn()
227 {
228 if (!vTxn.empty())
229 return vTxn.back();
230 else
231 return NULL;
232 }
233
234public:
235 bool TxnBegin()
236 {
237 if (!pdb)
238 return false;
239 DbTxn* ptxn = NULL;
240 int ret = dbenv.txn_begin(GetTxn(), &ptxn, 0);
241 if (!ptxn || ret != 0)
242 return false;
243 vTxn.push_back(ptxn);
244 return true;
245 }
246
247 bool TxnCommit()
248 {
249 if (!pdb)
250 return false;
251 if (vTxn.empty())
252 return false;
253 int ret = vTxn.back()->commit(0);
254 vTxn.pop_back();
255 return (ret == 0);
256 }
257
258 bool TxnAbort()
259 {
260 if (!pdb)
261 return false;
262 if (vTxn.empty())
263 return false;
264 int ret = vTxn.back()->abort();
265 vTxn.pop_back();
266 return (ret == 0);
267 }
268
269 bool ReadVersion(int& nVersion)
270 {
271 nVersion = 0;
272 return Read(string("version"), nVersion);
273 }
274
275 bool WriteVersion(int nVersion)
276 {
277 return Write(string("version"), nVersion);
278 }
279};
280
281
282
283
284
285
286
287
288class CTxDB : public CDB
289{
290public:
291 CTxDB(const char* pszMode="r+", bool fTxn=false) : CDB(!fClient ? "blkindex.dat" : NULL, pszMode, fTxn) { }
292private:
293 CTxDB(const CTxDB&);
294 void operator=(const CTxDB&);
295public:
296 bool ReadTxIndex(uint256 hash, CTxIndex& txindex);
297 bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex);
298 bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight);
299 bool EraseTxIndex(const CTransaction& tx);
300 bool ContainsTx(uint256 hash);
301 bool ReadOwnerTxes(uint160 hash160, int nHeight, vector<CTransaction>& vtx);
302 bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex);
303 bool ReadDiskTx(uint256 hash, CTransaction& tx);
304 bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex);
305 bool ReadDiskTx(COutPoint outpoint, CTransaction& tx);
306 bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
307 bool EraseBlockIndex(uint256 hash);
308 bool ReadHashBestChain(uint256& hashBestChain);
309 bool WriteHashBestChain(uint256 hashBestChain);
310 bool LoadBlockIndex();
311};
312
313
314
315
316
317class CReviewDB : public CDB
318{
319public:
320 CReviewDB(const char* pszMode="r+", bool fTxn=false) : CDB("reviews.dat", pszMode, fTxn) { }
321private:
322 CReviewDB(const CReviewDB&);
323 void operator=(const CReviewDB&);
324public:
325 bool ReadUser(uint256 hash, CUser& user)
326 {
327 return Read(make_pair(string("user"), hash), user);
328 }
329
330 bool WriteUser(uint256 hash, const CUser& user)
331 {
332 return Write(make_pair(string("user"), hash), user);
333 }
334
335 bool ReadReviews(uint256 hash, vector<CReview>& vReviews);
336 bool WriteReviews(uint256 hash, const vector<CReview>& vReviews);
337};
338
339
340
341
342
343class CMarketDB : public CDB
344{
345public:
346 CMarketDB(const char* pszMode="r+", bool fTxn=false) : CDB("market.dat", pszMode, fTxn) { }
347private:
348 CMarketDB(const CMarketDB&);
349 void operator=(const CMarketDB&);
350};
351
352
353
354
355
356// Legacy IP-based peer address database (CAddrDB / addr.dat) removed --
357// peer discovery is entirely Nostr/.btf-based now.
358
359
360
361
362
363class CWalletDB : public CDB
364{
365public:
366 CWalletDB(const char* pszMode="r+", bool fTxn=false) : CDB("wallet.dat", pszMode, fTxn) { }
367private:
368 CWalletDB(const CWalletDB&);
369 void operator=(const CWalletDB&);
370public:
371 bool ReadName(const string& strAddress, string& strName)
372 {
373 strName = "";
374 return Read(make_pair(string("name"), strAddress), strName);
375 }
376
377 bool WriteName(const string& strAddress, const string& strName)
378 {
379 mapAddressBook[strAddress] = strName;
380 return Write(make_pair(string("name"), strAddress), strName);
381 }
382
383 bool EraseName(const string& strAddress)
384 {
385 mapAddressBook.erase(strAddress);
386 return Erase(make_pair(string("name"), strAddress));
387 }
388
389 bool ReadTx(uint256 hash, CWalletTx& wtx)
390 {
391 return Read(make_pair(string("tx"), hash), wtx);
392 }
393
394 bool WriteTx(uint256 hash, const CWalletTx& wtx)
395 {
396 return Write(make_pair(string("tx"), hash), wtx);
397 }
398
399 bool EraseTx(uint256 hash)
400 {
401 return Erase(make_pair(string("tx"), hash));
402 }
403
404 bool ReadKey(const vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey)
405 {
406 vchPrivKey.clear();
407 return Read(make_pair(string("key"), vchPubKey), vchPrivKey);
408 }
409
410 bool WriteKey(const vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)
411 {
412 return Write(make_pair(string("key"), vchPubKey), vchPrivKey, false);
413 }
414
415 bool ReadDefaultKey(vector<unsigned char>& vchPubKey)
416 {
417 vchPubKey.clear();
418 return Read(string("defaultkey"), vchPubKey);
419 }
420
421 bool WriteDefaultKey(const vector<unsigned char>& vchPubKey)
422 {
423 return Write(string("defaultkey"), vchPubKey);
424 }
425
426 // --- Deterministic (BIP32) seed ---------------------------------------
427 //
428 // Stored as the master key and chain code rather than the mnemonic: the
429 // twelve words are the user's to write down, and keeping a copy of them in
430 // the file they are meant to protect defeats the point of having them.
431 //
432 // "hdschema" identifies the derivation layout. Wallets created before the
433 // field existed are inferred as HD_SCHEMA_LEGACY when a seed is present.
434 // "hdnext" is that legacy layout's next child index. The receive/change
435 // counters and coin type are reserved for the BIP44 layout that uses
436 // separate chains.
437 bool ReadHDMaster(vector<unsigned char>& vchMasterRet, vector<unsigned char>& vchChainCodeRet)
438 {
439 vchMasterRet.clear();
440 vchChainCodeRet.clear();
441 return Read(string("hdmaster"), vchMasterRet)
442 && Read(string("hdchaincode"), vchChainCodeRet);
443 }
444
445 bool WriteHDMaster(const vector<unsigned char>& vchMaster, const vector<unsigned char>& vchChainCode)
446 {
447 return Write(string("hdmaster"), vchMaster)
448 && Write(string("hdchaincode"), vchChainCode);
449 }
450
451 bool WriteWalletMinVersion(int nVersion)
452 {
453 return Write(string("walletminversion"), nVersion);
454 }
455
456 bool WriteMasterKey(unsigned int nID, const CWalletMasterKey& kMasterKey)
457 {
458 return Write(make_pair(string("mkey"), nID), kMasterKey, true);
459 }
460
461 bool WriteCryptedKey(const vector<unsigned char>& vchPubKey,
462 const vector<unsigned char>& vchCryptedSecret)
463 {
464 return Write(make_pair(string("ckey"), vchPubKey), vchCryptedSecret, false);
465 }
466
467 bool WriteCryptedHDMaster(const vector<unsigned char>& vchCryptedMaster,
468 const vector<unsigned char>& vchCryptedChainCode)
469 {
470 return Write(string("cryptedhdmaster"), vchCryptedMaster)
471 && Write(string("cryptedhdchaincode"), vchCryptedChainCode);
472 }
473
474 bool WriteHDNext(unsigned int nNext)
475 {
476 return Write(string("hdnext"), nNext);
477 }
478
479 bool WriteHDSchema(int nSchema)
480 {
481 return Write(string("hdschema"), nSchema);
482 }
483
484 bool WriteHDCoinType(unsigned int nCoinType)
485 {
486 return Write(string("hdcointype"), nCoinType);
487 }
488
489 bool WriteHDReceiveNext(unsigned int nNext)
490 {
491 return Write(string("hdreceivenext"), nNext);
492 }
493
494 bool WriteHDChangeNext(unsigned int nNext)
495 {
496 return Write(string("hdchangenext"), nNext);
497 }
498
499 // Keys generated ahead of time and not yet handed out. The private key of
500 // each is already stored under its own "key" record by AddKey; a "pool"
501 // record only says that this one is still unspoken for.
502 bool WritePool(int64 nIndex, const vector<unsigned char>& vchPubKey)
503 {
504 return Write(make_pair(string("pool"), nIndex), vchPubKey);
505 }
506
507 bool ErasePool(int64 nIndex)
508 {
509 return Erase(make_pair(string("pool"), nIndex));
510 }
511
512 template<typename T>
513 bool ReadSetting(const string& strKey, T& value)
514 {
515 return Read(make_pair(string("setting"), strKey), value);
516 }
517
518 template<typename T>
519 bool WriteSetting(const string& strKey, const T& value)
520 {
521 return Write(make_pair(string("setting"), strKey), value);
522 }
523
524 bool LoadWallet(vector<unsigned char>& vchDefaultKeyRet);
525};
526
527bool LoadWallet();
528
529// Writes a wallet.dat that opens on its own, anywhere -- see the definition in
530// db.cpp for why a plain file copy does not. Still a point-in-time snapshot:
531// keys are made as needed rather than derived from a seed, so coins paid to an
532// address created after this call are not spendable from the file it writes.
533bool BackupWallet(const string& strDest);
534
535// Plain-text key export/import: no Berkeley DB, no environment, no version
536// coupling. What you fall back on when wallet.dat itself will not cooperate.
537// DumpWallet refuses to overwrite an existing file and writes owner-only on
538// POSIX -- the output holds private keys in the clear.
539bool DumpWallet(const string& strDest);
540bool ImportWallet(const string& strSrc, int& nAddedRet, int& nSkippedRet);
541bool EncryptWallet(const string& strPassphrase, string& strBackupRet, string& strErrorRet);
542
543inline bool SetAddressBookName(const string& strAddress, const string& strName)
544{
545 return CWalletDB().WriteName(strAddress, strName);
546}