upleb.uk

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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNsable-sh <nsable-sh@noreply.git.bitflash.network>2026-08-14 09:55:53 -0300
committerNsable-sh <nsable-sh@noreply.git.bitflash.network>2026-08-14 09:55:53 -0300
commit5352185c7198a183c5906898e16bc4a6bb4e8654 (patch)
tree33bc227c6a686d3625cb30c1d815efea94d58f68
parent636644d0102689f61ec488dde62cd53e4835b8f1 (diff)
wallet: route rewrite copies through record scan
-rw-r--r--docs/storage.md4
-rw-r--r--src/db.cpp105
2 files changed, 54 insertions, 55 deletions
diff --git a/docs/storage.md b/docs/storage.md
index e533589..e4a66d2 100644
--- a/docs/storage.md
+++ b/docs/storage.md
@@ -43,7 +43,9 @@ level schema migration is intentionally introduced.
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 44Read-only tooling should go through `ScanWalletRecords()` instead of opening a
45Berkeley DB cursor directly. That keeps migration checks, audits, and future 45Berkeley DB cursor directly. That keeps migration checks, audits, and future
46backends behind one record-stream boundary. 46backends behind one record-stream boundary. Wallet rewrite code should also use
47that boundary when it needs to copy existing records into a newly written
48wallet file.
47 49
48| Key shape | Value | Secret? | Meaning | 50| Key shape | Value | Secret? | Meaning |
49|---|---|---:|---| 51|---|---|---:|---|
diff --git a/src/db.cpp b/src/db.cpp
index 4fa72af..b90219e 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -1354,70 +1354,68 @@ public:
1354 { 1354 {
1355 return Write(make_pair(string("pool"), nIndex), vchPubKey); 1355 return Write(make_pair(string("pool"), nIndex), vchPubKey);
1356 } 1356 }
1357};
1358
1359static bool IsWalletEncryptionPrivateRecord(const string& strType)
1360{
1361 return strType == "key" ||
1362 strType == "pool" ||
1363 strType == "hdmaster" ||
1364 strType == "hdchaincode" ||
1365 strType == "mkey" ||
1366 strType == "ckey" ||
1367 strType == "cryptedhdmaster" ||
1368 strType == "cryptedhdchaincode" ||
1369 strType == "walletminversion";
1370}
1357 1371
1358 bool CopyPublicRecordsTo(CWalletRewriteDB& dbTo, int& nCopiedRet, string& strErrorRet) 1372class CWalletPublicRecordCopyVisitor : public CWalletRecordVisitor
1373{
1374public:
1375 CWalletRewriteDB& dbTo;
1376 int& nCopied;
1377
1378 CWalletPublicRecordCopyVisitor(CWalletRewriteDB& dbToIn, int& nCopiedIn)
1379 : dbTo(dbToIn), nCopied(nCopiedIn) { }
1380
1381 bool VisitWalletRecord(const CDataStream& ssKey,
1382 const CDataStream& ssValue,
1383 string& strErrorRet)
1359 { 1384 {
1360 nCopiedRet = 0; 1385 string strType;
1361 Dbc* pcursor = GetCursor(); 1386 try
1362 if (!pcursor)
1363 { 1387 {
1364 strErrorRet = "could not open a wallet cursor"; 1388 CDataStream ssType = ssKey;
1365 return false; 1389 ssType >> strType;
1366 } 1390 }
1367 1391 catch (...)
1368 unsigned int fFlags = DB_NEXT;
1369 loop
1370 { 1392 {
1371 CDataStream ssKey; 1393 strErrorRet = "wallet.dat has a record whose key type cannot be read";
1372 CDataStream ssValue; 1394 return false;
1373 int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); 1395 }
1374 if (ret == DB_NOTFOUND)
1375 break;
1376 if (ret != 0)
1377 {
1378 pcursor->close();
1379 strErrorRet = strprintf("could not read wallet record: Berkeley DB error %d", ret);
1380 return false;
1381 }
1382
1383 string strType;
1384 try
1385 {
1386 CDataStream ssType = ssKey;
1387 ssType >> strType;
1388 }
1389 catch (...)
1390 {
1391 pcursor->close();
1392 strErrorRet = "wallet.dat has a record whose key type cannot be read";
1393 return false;
1394 }
1395 1396
1396 if (strType == "key" || 1397 if (IsWalletEncryptionPrivateRecord(strType))
1397 strType == "pool" || 1398 return true;
1398 strType == "hdmaster" ||
1399 strType == "hdchaincode" ||
1400 strType == "mkey" ||
1401 strType == "ckey" ||
1402 strType == "cryptedhdmaster" ||
1403 strType == "cryptedhdchaincode" ||
1404 strType == "walletminversion")
1405 continue;
1406 1399
1407 if (!dbTo.WriteRaw(ssKey, ssValue)) 1400 if (!dbTo.WriteRaw(ssKey, ssValue))
1408 { 1401 {
1409 pcursor->close(); 1402 strErrorRet = strprintf("could not copy wallet record '%s'", strType.c_str());
1410 strErrorRet = strprintf("could not copy wallet record '%s'", strType.c_str()); 1403 return false;
1411 return false;
1412 }
1413 nCopiedRet++;
1414 } 1404 }
1415 1405 nCopied++;
1416 pcursor->close();
1417 return true; 1406 return true;
1418 } 1407 }
1419}; 1408};
1420 1409
1410static bool CopyPublicWalletRecordsTo(CWalletRewriteDB& dbTo,
1411 int& nCopiedRet,
1412 string& strErrorRet)
1413{
1414 nCopiedRet = 0;
1415 CWalletPublicRecordCopyVisitor visitor(dbTo, nCopiedRet);
1416 return ScanWalletRecords(visitor, strErrorRet);
1417}
1418
1421static string WalletEncryptBackupPath() 1419static string WalletEncryptBackupPath()
1422{ 1420{
1423 string strBase = GetAppDir() + "/wallet.dat.before-encrypt."; 1421 string strBase = GetAppDir() + "/wallet.dat.before-encrypt.";
@@ -1594,9 +1592,8 @@ bool EncryptWallet(const string& strPassphrase, string& strBackupRet, string& st
1594 1592
1595 int nCopied = 0; 1593 int nCopied = 0;
1596 { 1594 {
1597 CWalletRewriteDB dbSource("wallet.dat", "r");
1598 CWalletRewriteDB dbTarget(strTempFile.c_str(), "c+"); 1595 CWalletRewriteDB dbTarget(strTempFile.c_str(), "c+");
1599 if (!dbSource.CopyPublicRecordsTo(dbTarget, nCopied, strErrorRet)) 1596 if (!CopyPublicWalletRecordsTo(dbTarget, nCopied, strErrorRet))
1600 { 1597 {
1601 remove(strTempPath.c_str()); 1598 remove(strTempPath.c_str());
1602 return false; 1599 return false;