upleb.uk

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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBitflash <admin@bitflash.network>2026-08-17 12:08:12 -0300
committerBitflash <admin@bitflash.network>2026-08-17 12:08:12 -0300
commita6eb8dab830be3135c054ae3ae442886f1867b4e (patch)
tree5372e845b7c6cf75fb9aaab2caaaf15eaadd0dd3
parent0175bb9205d7e3dc474aede8000a05f1d70ed0e6 (diff)
parentd082210c5d080c0a91412b94a109d8e73422eb31 (diff)
Merge pull request 'wallet: route CWalletDB through SQLite runtime' (#58) from wallet-sqlite-runtime-write into main
-rw-r--r--src/db.cpp67
-rw-r--r--src/db.h145
-rw-r--r--src/selftest.cpp76
3 files changed, 259 insertions, 29 deletions
diff --git a/src/db.cpp b/src/db.cpp
index 581e5a7..7cfb7c5 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -56,6 +56,7 @@ string strWalletLoadError;
56static DbEnv* pdbenv = NULL; 56static DbEnv* pdbenv = NULL;
57static FILE* pdbErrFile = NULL; 57static FILE* pdbErrFile = NULL;
58static map<string, int> mapFileUseCount; 58static map<string, int> mapFileUseCount;
59static CWalletDBSQLite* pWalletSQLiteRuntime = NULL;
59 60
60DbEnv& GetDbEnv() 61DbEnv& GetDbEnv()
61{ 62{
@@ -95,6 +96,67 @@ public:
95} 96}
96instance_of_cdbinit; 97instance_of_cdbinit;
97 98
99bool WalletSQLiteRuntimeActive()
100{
101 return pWalletSQLiteRuntime != NULL;
102}
103
104bool WalletSQLiteRuntimeOpen(const string& strPath, string& strErrorRet)
105{
106 strErrorRet.clear();
107 if (!FileExists(strPath.c_str()))
108 {
109 strErrorRet = strprintf("SQLite wallet does not exist: %s",
110 strPath.c_str());
111 return false;
112 }
113
114 WalletSQLiteRuntimeClose();
115 std::auto_ptr<CWalletDBSQLite> db(new CWalletDBSQLite());
116 if (!db->Open(strPath, strErrorRet))
117 return false;
118
119 pWalletSQLiteRuntime = db.release();
120 return true;
121}
122
123void WalletSQLiteRuntimeClose()
124{
125 if (pWalletSQLiteRuntime)
126 {
127 delete pWalletSQLiteRuntime;
128 pWalletSQLiteRuntime = NULL;
129 }
130}
131
132bool WalletSQLiteRuntimeReadRecord(const vector<unsigned char>& vchKey,
133 vector<unsigned char>& vchValueRet)
134{
135 if (!pWalletSQLiteRuntime)
136 return false;
137 string strError;
138 return pWalletSQLiteRuntime->ReadRecord(vchKey, vchValueRet, strError);
139}
140
141bool WalletSQLiteRuntimeWriteRecord(const vector<unsigned char>& vchKey,
142 const vector<unsigned char>& vchValue,
143 bool fOverwrite)
144{
145 if (!pWalletSQLiteRuntime)
146 return false;
147 string strError;
148 return pWalletSQLiteRuntime->WriteRecord(vchKey, vchValue, strError,
149 fOverwrite);
150}
151
152bool WalletSQLiteRuntimeEraseRecord(const vector<unsigned char>& vchKey)
153{
154 if (!pWalletSQLiteRuntime)
155 return false;
156 string strError;
157 return pWalletSQLiteRuntime->EraseRecord(vchKey, strError);
158}
159
98 160
99CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) 161CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL)
100{ 162{
@@ -651,6 +713,11 @@ bool CReviewDB::WriteReviews(uint256 hash, const vector<CReview>& vReviews)
651// CWalletDB 713// CWalletDB
652// 714//
653 715
716CWalletDB::CWalletDB(const char* pszMode, bool fTxn) :
717 CDB(WalletSQLiteRuntimeActive() ? NULL : "wallet.dat", pszMode, fTxn)
718{
719}
720
654class CSQLiteWalletRuntimeLoadVisitor : public CWalletRecordVisitor 721class CSQLiteWalletRuntimeLoadVisitor : public CWalletRecordVisitor
655{ 722{
656public: 723public:
diff --git a/src/db.h b/src/db.h
index 59ff24a..8fa4ea8 100644
--- a/src/db.h
+++ b/src/db.h
@@ -356,6 +356,16 @@ private:
356// Legacy IP-based peer address database (CAddrDB / addr.dat) removed -- 356// Legacy IP-based peer address database (CAddrDB / addr.dat) removed --
357// peer discovery is entirely Nostr/.btf-based now. 357// peer discovery is entirely Nostr/.btf-based now.
358 358
359bool WalletSQLiteRuntimeActive();
360bool WalletSQLiteRuntimeOpen(const string& strPath, string& strErrorRet);
361void WalletSQLiteRuntimeClose();
362bool WalletSQLiteRuntimeReadRecord(const vector<unsigned char>& vchKey,
363 vector<unsigned char>& vchValueRet);
364bool WalletSQLiteRuntimeWriteRecord(const vector<unsigned char>& vchKey,
365 const vector<unsigned char>& vchValue,
366 bool fOverwrite);
367bool WalletSQLiteRuntimeEraseRecord(const vector<unsigned char>& vchKey);
368
359 369
360 370
361 371
@@ -363,64 +373,141 @@ private:
363class CWalletDB : public CDB 373class CWalletDB : public CDB
364{ 374{
365public: 375public:
366 CWalletDB(const char* pszMode="r+", bool fTxn=false) : CDB("wallet.dat", pszMode, fTxn) { } 376 CWalletDB(const char* pszMode="r+", bool fTxn=false);
367private: 377private:
368 CWalletDB(const CWalletDB&); 378 CWalletDB(const CWalletDB&);
369 void operator=(const CWalletDB&); 379 void operator=(const CWalletDB&);
380
381 template<typename K, typename T>
382 bool ReadWalletRecord(const K& key, T& value)
383 {
384 if (!WalletSQLiteRuntimeActive())
385 return Read(key, value);
386
387 CDataStream ssKey(SER_DISK);
388 ssKey.reserve(1000);
389 ssKey << key;
390 vector<unsigned char> vchKey(ssKey.begin(), ssKey.end());
391 vector<unsigned char> vchValue;
392
393 bool fOk = WalletSQLiteRuntimeReadRecord(vchKey, vchValue);
394 if (!vchKey.empty())
395 memset(&vchKey[0], 0, vchKey.size());
396 if (!ssKey.empty())
397 memset(&ssKey[0], 0, ssKey.size());
398 if (!fOk)
399 return false;
400
401 CDataStream ssValue(vchValue, SER_DISK);
402 ssValue >> value;
403 bool fReadOk = !ssValue.fail();
404 if (!vchValue.empty())
405 memset(&vchValue[0], 0, vchValue.size());
406 if (!ssValue.empty())
407 memset(&ssValue[0], 0, ssValue.size());
408 return fReadOk;
409 }
410
411 template<typename K, typename T>
412 bool WriteWalletRecord(const K& key, const T& value, bool fOverwrite=true)
413 {
414 if (!WalletSQLiteRuntimeActive())
415 return Write(key, value, fOverwrite);
416
417 CDataStream ssKey(SER_DISK);
418 ssKey.reserve(1000);
419 ssKey << key;
420 CDataStream ssValue(SER_DISK);
421 ssValue.reserve(10000);
422 ssValue << value;
423
424 vector<unsigned char> vchKey(ssKey.begin(), ssKey.end());
425 vector<unsigned char> vchValue(ssValue.begin(), ssValue.end());
426 bool fOk = WalletSQLiteRuntimeWriteRecord(vchKey, vchValue, fOverwrite);
427
428 if (!vchKey.empty())
429 memset(&vchKey[0], 0, vchKey.size());
430 if (!vchValue.empty())
431 memset(&vchValue[0], 0, vchValue.size());
432 if (!ssKey.empty())
433 memset(&ssKey[0], 0, ssKey.size());
434 if (!ssValue.empty())
435 memset(&ssValue[0], 0, ssValue.size());
436 return fOk;
437 }
438
439 template<typename K>
440 bool EraseWalletRecord(const K& key)
441 {
442 if (!WalletSQLiteRuntimeActive())
443 return Erase(key);
444
445 CDataStream ssKey(SER_DISK);
446 ssKey.reserve(1000);
447 ssKey << key;
448 vector<unsigned char> vchKey(ssKey.begin(), ssKey.end());
449 bool fOk = WalletSQLiteRuntimeEraseRecord(vchKey);
450
451 if (!vchKey.empty())
452 memset(&vchKey[0], 0, vchKey.size());
453 if (!ssKey.empty())
454 memset(&ssKey[0], 0, ssKey.size());
455 return fOk;
456 }
370public: 457public:
371 bool ReadName(const string& strAddress, string& strName) 458 bool ReadName(const string& strAddress, string& strName)
372 { 459 {
373 strName = ""; 460 strName = "";
374 return Read(make_pair(string("name"), strAddress), strName); 461 return ReadWalletRecord(make_pair(string("name"), strAddress), strName);
375 } 462 }
376 463
377 bool WriteName(const string& strAddress, const string& strName) 464 bool WriteName(const string& strAddress, const string& strName)
378 { 465 {
379 mapAddressBook[strAddress] = strName; 466 mapAddressBook[strAddress] = strName;
380 return Write(make_pair(string("name"), strAddress), strName); 467 return WriteWalletRecord(make_pair(string("name"), strAddress), strName);
381 } 468 }
382 469
383 bool EraseName(const string& strAddress) 470 bool EraseName(const string& strAddress)
384 { 471 {
385 mapAddressBook.erase(strAddress); 472 mapAddressBook.erase(strAddress);
386 return Erase(make_pair(string("name"), strAddress)); 473 return EraseWalletRecord(make_pair(string("name"), strAddress));
387 } 474 }
388 475
389 bool ReadTx(uint256 hash, CWalletTx& wtx) 476 bool ReadTx(uint256 hash, CWalletTx& wtx)
390 { 477 {
391 return Read(make_pair(string("tx"), hash), wtx); 478 return ReadWalletRecord(make_pair(string("tx"), hash), wtx);
392 } 479 }
393 480
394 bool WriteTx(uint256 hash, const CWalletTx& wtx) 481 bool WriteTx(uint256 hash, const CWalletTx& wtx)
395 { 482 {
396 return Write(make_pair(string("tx"), hash), wtx); 483 return WriteWalletRecord(make_pair(string("tx"), hash), wtx);
397 } 484 }
398 485
399 bool EraseTx(uint256 hash) 486 bool EraseTx(uint256 hash)
400 { 487 {
401 return Erase(make_pair(string("tx"), hash)); 488 return EraseWalletRecord(make_pair(string("tx"), hash));
402 } 489 }
403 490
404 bool ReadKey(const vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey) 491 bool ReadKey(const vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey)
405 { 492 {
406 vchPrivKey.clear(); 493 vchPrivKey.clear();
407 return Read(make_pair(string("key"), vchPubKey), vchPrivKey); 494 return ReadWalletRecord(make_pair(string("key"), vchPubKey), vchPrivKey);
408 } 495 }
409 496
410 bool WriteKey(const vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey) 497 bool WriteKey(const vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)
411 { 498 {
412 return Write(make_pair(string("key"), vchPubKey), vchPrivKey, false); 499 return WriteWalletRecord(make_pair(string("key"), vchPubKey), vchPrivKey, false);
413 } 500 }
414 501
415 bool ReadDefaultKey(vector<unsigned char>& vchPubKey) 502 bool ReadDefaultKey(vector<unsigned char>& vchPubKey)
416 { 503 {
417 vchPubKey.clear(); 504 vchPubKey.clear();
418 return Read(string("defaultkey"), vchPubKey); 505 return ReadWalletRecord(string("defaultkey"), vchPubKey);
419 } 506 }
420 507
421 bool WriteDefaultKey(const vector<unsigned char>& vchPubKey) 508 bool WriteDefaultKey(const vector<unsigned char>& vchPubKey)
422 { 509 {
423 return Write(string("defaultkey"), vchPubKey); 510 return WriteWalletRecord(string("defaultkey"), vchPubKey);
424 } 511 }
425 512
426 // --- Deterministic (BIP32) seed --------------------------------------- 513 // --- Deterministic (BIP32) seed ---------------------------------------
@@ -438,62 +525,62 @@ public:
438 { 525 {
439 vchMasterRet.clear(); 526 vchMasterRet.clear();
440 vchChainCodeRet.clear(); 527 vchChainCodeRet.clear();
441 return Read(string("hdmaster"), vchMasterRet) 528 return ReadWalletRecord(string("hdmaster"), vchMasterRet)
442 && Read(string("hdchaincode"), vchChainCodeRet); 529 && ReadWalletRecord(string("hdchaincode"), vchChainCodeRet);
443 } 530 }
444 531
445 bool WriteHDMaster(const vector<unsigned char>& vchMaster, const vector<unsigned char>& vchChainCode) 532 bool WriteHDMaster(const vector<unsigned char>& vchMaster, const vector<unsigned char>& vchChainCode)
446 { 533 {
447 return Write(string("hdmaster"), vchMaster) 534 return WriteWalletRecord(string("hdmaster"), vchMaster)
448 && Write(string("hdchaincode"), vchChainCode); 535 && WriteWalletRecord(string("hdchaincode"), vchChainCode);
449 } 536 }
450 537
451 bool WriteWalletMinVersion(int nVersion) 538 bool WriteWalletMinVersion(int nVersion)
452 { 539 {
453 return Write(string("walletminversion"), nVersion); 540 return WriteWalletRecord(string("walletminversion"), nVersion);
454 } 541 }
455 542
456 bool WriteMasterKey(unsigned int nID, const CWalletMasterKey& kMasterKey) 543 bool WriteMasterKey(unsigned int nID, const CWalletMasterKey& kMasterKey)
457 { 544 {
458 return Write(make_pair(string("mkey"), nID), kMasterKey, true); 545 return WriteWalletRecord(make_pair(string("mkey"), nID), kMasterKey, true);
459 } 546 }
460 547
461 bool WriteCryptedKey(const vector<unsigned char>& vchPubKey, 548 bool WriteCryptedKey(const vector<unsigned char>& vchPubKey,
462 const vector<unsigned char>& vchCryptedSecret) 549 const vector<unsigned char>& vchCryptedSecret)
463 { 550 {
464 return Write(make_pair(string("ckey"), vchPubKey), vchCryptedSecret, false); 551 return WriteWalletRecord(make_pair(string("ckey"), vchPubKey), vchCryptedSecret, false);
465 } 552 }
466 553
467 bool WriteCryptedHDMaster(const vector<unsigned char>& vchCryptedMaster, 554 bool WriteCryptedHDMaster(const vector<unsigned char>& vchCryptedMaster,
468 const vector<unsigned char>& vchCryptedChainCode) 555 const vector<unsigned char>& vchCryptedChainCode)
469 { 556 {
470 return Write(string("cryptedhdmaster"), vchCryptedMaster) 557 return WriteWalletRecord(string("cryptedhdmaster"), vchCryptedMaster)
471 && Write(string("cryptedhdchaincode"), vchCryptedChainCode); 558 && WriteWalletRecord(string("cryptedhdchaincode"), vchCryptedChainCode);
472 } 559 }
473 560
474 bool WriteHDNext(unsigned int nNext) 561 bool WriteHDNext(unsigned int nNext)
475 { 562 {
476 return Write(string("hdnext"), nNext); 563 return WriteWalletRecord(string("hdnext"), nNext);
477 } 564 }
478 565
479 bool WriteHDSchema(int nSchema) 566 bool WriteHDSchema(int nSchema)
480 { 567 {
481 return Write(string("hdschema"), nSchema); 568 return WriteWalletRecord(string("hdschema"), nSchema);
482 } 569 }
483 570
484 bool WriteHDCoinType(unsigned int nCoinType) 571 bool WriteHDCoinType(unsigned int nCoinType)
485 { 572 {
486 return Write(string("hdcointype"), nCoinType); 573 return WriteWalletRecord(string("hdcointype"), nCoinType);
487 } 574 }
488 575
489 bool WriteHDReceiveNext(unsigned int nNext) 576 bool WriteHDReceiveNext(unsigned int nNext)
490 { 577 {
491 return Write(string("hdreceivenext"), nNext); 578 return WriteWalletRecord(string("hdreceivenext"), nNext);
492 } 579 }
493 580
494 bool WriteHDChangeNext(unsigned int nNext) 581 bool WriteHDChangeNext(unsigned int nNext)
495 { 582 {
496 return Write(string("hdchangenext"), nNext); 583 return WriteWalletRecord(string("hdchangenext"), nNext);
497 } 584 }
498 585
499 // Keys generated ahead of time and not yet handed out. The private key of 586 // Keys generated ahead of time and not yet handed out. The private key of
@@ -501,24 +588,24 @@ public:
501 // record only says that this one is still unspoken for. 588 // record only says that this one is still unspoken for.
502 bool WritePool(int64 nIndex, const vector<unsigned char>& vchPubKey) 589 bool WritePool(int64 nIndex, const vector<unsigned char>& vchPubKey)
503 { 590 {
504 return Write(make_pair(string("pool"), nIndex), vchPubKey); 591 return WriteWalletRecord(make_pair(string("pool"), nIndex), vchPubKey);
505 } 592 }
506 593
507 bool ErasePool(int64 nIndex) 594 bool ErasePool(int64 nIndex)
508 { 595 {
509 return Erase(make_pair(string("pool"), nIndex)); 596 return EraseWalletRecord(make_pair(string("pool"), nIndex));
510 } 597 }
511 598
512 template<typename T> 599 template<typename T>
513 bool ReadSetting(const string& strKey, T& value) 600 bool ReadSetting(const string& strKey, T& value)
514 { 601 {
515 return Read(make_pair(string("setting"), strKey), value); 602 return ReadWalletRecord(make_pair(string("setting"), strKey), value);
516 } 603 }
517 604
518 template<typename T> 605 template<typename T>
519 bool WriteSetting(const string& strKey, const T& value) 606 bool WriteSetting(const string& strKey, const T& value)
520 { 607 {
521 return Write(make_pair(string("setting"), strKey), value); 608 return WriteWalletRecord(make_pair(string("setting"), strKey), value);
522 } 609 }
523 610
524 bool LoadWallet(vector<unsigned char>& vchDefaultKeyRet); 611 bool LoadWallet(vector<unsigned char>& vchDefaultKeyRet);
diff --git a/src/selftest.cpp b/src/selftest.cpp
index a1efaa0..9fa0938 100644
--- a/src/selftest.cpp
+++ b/src/selftest.cpp
@@ -1051,6 +1051,8 @@ static int RunWalletSQLiteSelfTest()
1051 int nFail = 0; 1051 int nFail = 0;
1052 string strPath = tmp + "/wallet.sqlite"; 1052 string strPath = tmp + "/wallet.sqlite";
1053 string strError; 1053 string strError;
1054 string strOldRuntimeDataDir;
1055 bool fRestoreRuntimeDataDir = false;
1054 1056
1055 try 1057 try
1056 { 1058 {
@@ -1166,14 +1168,88 @@ static int RunWalletSQLiteSelfTest()
1166 vchTypedPubKey == vchPubKey, 1168 vchTypedPubKey == vchPubKey,
1167 "SQLite wallet reads a typed defaultkey record") ? 0 : 1; 1169 "SQLite wallet reads a typed defaultkey record") ? 0 : 1;
1168 } 1170 }
1171
1172 {
1173 string strRuntimePath = tmp + "/runtime-wallet.sqlite";
1174 string strRuntimeDir = tmp + "/runtime-datadir";
1175 nFail += Check(MakeDirLocal(strRuntimeDir),
1176 "SQLite runtime datadir can be created") ? 0 : 1;
1177
1178 {
1179 CWalletDBSQLite db;
1180 nFail += Check(db.Open(strRuntimePath, strError),
1181 "SQLite runtime wallet file can be created") ? 0 : 1;
1182 }
1183
1184 string strOldDataDir = strSetDataDir;
1185 strSetDataDir = strRuntimeDir;
1186 strOldRuntimeDataDir = strOldDataDir;
1187 fRestoreRuntimeDataDir = true;
1188 bool fRuntimeOpened = WalletSQLiteRuntimeOpen(strRuntimePath, strError);
1189 nFail += Check(fRuntimeOpened,
1190 "SQLite runtime wallet can be activated") ? 0 : 1;
1191
1192 if (fRuntimeOpened)
1193 {
1194 CKey key;
1195 key.MakeNewKey();
1196 vector<unsigned char> vchRuntimePubKey = key.GetPubKey();
1197 CPrivKey vchRuntimePrivKey = key.GetPrivKey();
1198 string strRuntimeAddress = PubKeyToAddress(vchRuntimePubKey);
1199
1200 nFail += Check(CWalletDB().WriteSetting("runtime-sqlite-setting",
1201 (int64)909090) &&
1202 CWalletDB().WriteDefaultKey(vchRuntimePubKey) &&
1203 CWalletDB().WriteKey(vchRuntimePubKey,
1204 vchRuntimePrivKey) &&
1205 CWalletDB().WriteName(strRuntimeAddress,
1206 "SQLite Runtime Address"),
1207 "CWalletDB writes route to active SQLite runtime") ? 0 : 1;
1208
1209 int64 nRuntimeSetting = 0;
1210 vector<unsigned char> vchRuntimeDefaultKey;
1211 CPrivKey vchRuntimeReadPrivKey;
1212 string strRuntimeName;
1213 nFail += Check(CWalletDB("r").ReadSetting("runtime-sqlite-setting",
1214 nRuntimeSetting) &&
1215 nRuntimeSetting == 909090 &&
1216 CWalletDB("r").ReadDefaultKey(vchRuntimeDefaultKey) &&
1217 vchRuntimeDefaultKey == vchRuntimePubKey &&
1218 CWalletDB("r").ReadKey(vchRuntimePubKey,
1219 vchRuntimeReadPrivKey) &&
1220 vchRuntimeReadPrivKey == vchRuntimePrivKey &&
1221 CWalletDB("r").ReadName(strRuntimeAddress,
1222 strRuntimeName) &&
1223 strRuntimeName == "SQLite Runtime Address",
1224 "CWalletDB reads route to active SQLite runtime") ? 0 : 1;
1225
1226 nFail += Check(CWalletDB().EraseName(strRuntimeAddress) &&
1227 !CWalletDB("r").ReadName(strRuntimeAddress,
1228 strRuntimeName),
1229 "CWalletDB erases route to active SQLite runtime") ? 0 : 1;
1230
1231 nFail += Check(!FileExists((strRuntimeDir + "/wallet.dat").c_str()),
1232 "active SQLite runtime does not create wallet.dat") ? 0 : 1;
1233 }
1234
1235 WalletSQLiteRuntimeClose();
1236 strSetDataDir = strOldDataDir;
1237 fRestoreRuntimeDataDir = false;
1238 }
1169 } 1239 }
1170 catch (const std::exception& e) 1240 catch (const std::exception& e)
1171 { 1241 {
1242 WalletSQLiteRuntimeClose();
1243 if (fRestoreRuntimeDataDir)
1244 strSetDataDir = strOldRuntimeDataDir;
1172 printf(" FAIL exception: %s\n", e.what()); 1245 printf(" FAIL exception: %s\n", e.what());
1173 nFail++; 1246 nFail++;
1174 } 1247 }
1175 catch (...) 1248 catch (...)
1176 { 1249 {
1250 WalletSQLiteRuntimeClose();
1251 if (fRestoreRuntimeDataDir)
1252 strSetDataDir = strOldRuntimeDataDir;
1177 printf(" FAIL unknown exception\n"); 1253 printf(" FAIL unknown exception\n");
1178 nFail++; 1254 nFail++;
1179 } 1255 }