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-14 09:39:24 -0300
committerBitflash <admin@bitflash.network>2026-08-14 09:39:24 -0300
commit636644d0102689f61ec488dde62cd53e4835b8f1 (patch)
tree1ca90f11685b47aaa6a36e3677d0a3dfed072136
parentcf597ca37aec53b0dd7016399fee73e1959dc604 (diff)
parent95bd9cbcb1d17f4bc6223e6bfe3a92bfb8c3067d (diff)
Merge pull request 'wallet: add read-only record scan boundary' (#40) from wallet-store-read-abstraction into main
-rw-r--r--docs/storage.md3
-rw-r--r--src/db.cpp39
-rw-r--r--src/db.h11
-rw-r--r--src/walletcmd.cpp63
4 files changed, 78 insertions, 38 deletions
diff --git a/docs/storage.md b/docs/storage.md
index 4dd35bd..e533589 100644
--- a/docs/storage.md
+++ b/docs/storage.md
@@ -41,6 +41,9 @@ level schema migration is intentionally introduced.
41## `wallet.dat` 41## `wallet.dat`
42 42
43`wallet.dat` is accessed through `CWalletDB`. 43`wallet.dat` is accessed through `CWalletDB`.
44Read-only tooling should go through `ScanWalletRecords()` instead of opening a
45Berkeley DB cursor directly. That keeps migration checks, audits, and future
46backends behind one record-stream boundary.
44 47
45| Key shape | Value | Secret? | Meaning | 48| Key shape | Value | Secret? | Meaning |
46|---|---|---:|---| 49|---|---|---:|---|
diff --git a/src/db.cpp b/src/db.cpp
index 9f62964..4fa72af 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -932,6 +932,45 @@ bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet)
932 return true; 932 return true;
933} 933}
934 934
935bool ScanWalletRecords(CWalletRecordVisitor& visitor, string& strErrorRet)
936{
937 class CWalletScanDB : public CWalletDB
938 {
939 public:
940 CWalletScanDB() : CWalletDB("r") { }
941 using CDB::GetCursor;
942 using CDB::ReadAtCursor;
943 };
944
945 strErrorRet.clear();
946 CWalletScanDB dbWallet;
947 Dbc* pcursor = dbWallet.GetCursor();
948 if (!pcursor)
949 {
950 strErrorRet = "could not open a wallet cursor";
951 return false;
952 }
953 CAutoCursor cursorGuard(pcursor);
954
955 loop
956 {
957 CDataStream ssKey(SER_DISK);
958 CDataStream ssValue(SER_DISK);
959 int ret = dbWallet.ReadAtCursor(pcursor, ssKey, ssValue);
960 if (ret == DB_NOTFOUND)
961 break;
962 if (ret != 0)
963 {
964 strErrorRet = strprintf("could not read wallet record: Berkeley DB error %d", ret);
965 return false;
966 }
967 if (!visitor.VisitWalletRecord(ssKey, ssValue, strErrorRet))
968 return false;
969 }
970
971 return true;
972}
973
935bool LoadWallet() 974bool LoadWallet()
936{ 975{
937 vector<unsigned char> vchDefaultKey; 976 vector<unsigned char> vchDefaultKey;
diff --git a/src/db.h b/src/db.h
index 4fb5cfd..2816957 100644
--- a/src/db.h
+++ b/src/db.h
@@ -524,6 +524,17 @@ public:
524 bool LoadWallet(vector<unsigned char>& vchDefaultKeyRet); 524 bool LoadWallet(vector<unsigned char>& vchDefaultKeyRet);
525}; 525};
526 526
527class CWalletRecordVisitor
528{
529public:
530 virtual ~CWalletRecordVisitor() { }
531 virtual bool VisitWalletRecord(const CDataStream& ssKey,
532 const CDataStream& ssValue,
533 string& strErrorRet) = 0;
534};
535
536bool ScanWalletRecords(CWalletRecordVisitor& visitor, string& strErrorRet);
537
527bool LoadWallet(); 538bool LoadWallet();
528 539
529// Writes a wallet.dat that opens on its own, anywhere -- see the definition in 540// Writes a wallet.dat that opens on its own, anywhere -- see the definition in
diff --git a/src/walletcmd.cpp b/src/walletcmd.cpp
index ce0da02..71f1ec3 100644
--- a/src/walletcmd.cpp
+++ b/src/walletcmd.cpp
@@ -553,51 +553,38 @@ static void CountWalletStorageType(const std::string& strType,
553static bool ReadWalletStorageCounts(WalletStorageAuditCounts& counts, 553static bool ReadWalletStorageCounts(WalletStorageAuditCounts& counts,
554 std::string& strError) 554 std::string& strError)
555{ 555{
556 class CWalletAuditDB : public CWalletDB 556 class CWalletStorageCountVisitor : public CWalletRecordVisitor
557 { 557 {
558 public: 558 public:
559 CWalletAuditDB() : CWalletDB("r") { } 559 WalletStorageAuditCounts& counts;
560 using CDB::GetCursor;
561 using CDB::ReadAtCursor;
562 };
563
564 CWalletAuditDB walletdb;
565 Dbc* pcursor = walletdb.GetCursor();
566 if (!pcursor)
567 {
568 strError = "cannot open wallet.dat cursor";
569 return false;
570 }
571 560
572 for (;;) 561 explicit CWalletStorageCountVisitor(WalletStorageAuditCounts& countsIn)
573 { 562 : counts(countsIn) { }
574 CDataStream ssKey(SER_DISK);
575 CDataStream ssValue(SER_DISK);
576 int ret = walletdb.ReadAtCursor(pcursor, ssKey, ssValue);
577 if (ret == DB_NOTFOUND)
578 break;
579 if (ret != 0)
580 {
581 pcursor->close();
582 strError = strprintf("Berkeley DB cursor read failed (%d)", ret);
583 return false;
584 }
585 563
586 counts.nTotal++; 564 bool VisitWalletRecord(const CDataStream& ssKeyIn,
587 try 565 const CDataStream& ssValue,
566 std::string& strErrorRet)
588 { 567 {
589 std::string strType; 568 (void)ssValue;
590 ssKey >> strType; 569 (void)strErrorRet;
591 CountWalletStorageType(strType, counts); 570 counts.nTotal++;
592 } 571 try
593 catch (...) 572 {
594 { 573 CDataStream ssKey = ssKeyIn;
595 counts.nMalformed++; 574 std::string strType;
575 ssKey >> strType;
576 CountWalletStorageType(strType, counts);
577 }
578 catch (...)
579 {
580 counts.nMalformed++;
581 }
582 return true;
596 } 583 }
597 } 584 };
598 585
599 pcursor->close(); 586 CWalletStorageCountVisitor visitor(counts);
600 return true; 587 return ScanWalletRecords(visitor, strError);
601} 588}
602 589
603static std::string WalletStorageAuditJson(const WalletStorageAuditCounts& counts) 590static std::string WalletStorageAuditJson(const WalletStorageAuditCounts& counts)