upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/selftest.cpp
diff options
context:
space:
mode:
authorbitflash <dev@bitflash.network>2026-08-18 14:44:11 -0300
committerbitflash <dev@bitflash.network>2026-08-18 14:44:11 -0300
commit84a60275569dca5d1fb12db38ce184caf7487ed6 (patch)
tree23e39a26b340324a7a33a115aded3b70b5332816 /src/selftest.cpp
parent440d7f393d74f309d29e1d10ba1f11c41c869226 (diff)
wallet: one-shot storage commands honour -walletbackend=sqlite
-walletstorageaudit, -walletstoragecheck and -backupwallet all read wallet.dat regardless of the selected backend. Under -walletbackend=sqlite that is wrong, and for backup it is dangerous: it silently backs up the stale plaintext wallet.dat instead of the live wallet.sqlite. - ScanWalletRecords() routes to the active SQLite store instead of a Berkeley DB cursor (it returned an error under the runtime before). This is the single choke point audit and check scan through. - WalletSQLiteRuntimeOpenReadOnly() opens wallet.sqlite for scanning without loading or validating records, so the pre-load diagnostics can inspect a wallet the loader would refuse. main_gui opens it for audit/check when the SQLite backend is selected (and rejects an unknown backend value there too). - BackupWallet() copies wallet.sqlite (checkpoint, then the temp/old/rename dance; a checkpointed SQLite file is self-contained, no lsn_reset). wallet-sqlite-encrypt self-test proves routing on a datadir where the SQLite wallet is encrypted and wallet.dat beside it is still plaintext: audit with the flag reports the encrypted seed, without it reports the plaintext one; the SQLite backup carries no plaintext key and loadchecks as a standalone wallet.
Diffstat (limited to 'src/selftest.cpp')
-rw-r--r--src/selftest.cpp60
1 files changed, 60 insertions, 0 deletions
diff --git a/src/selftest.cpp b/src/selftest.cpp
index 7ad5a53..90a30d2 100644
--- a/src/selftest.cpp
+++ b/src/selftest.cpp
@@ -2453,6 +2453,66 @@ static int RunWalletSQLiteEncryptSelfTest()
2453 nFail += Check(nAuditRet == 0 && 2453 nFail += Check(nAuditRet == 0 &&
2454 FileContainsText(strAudit, "recovery phrase: present"), 2454 FileContainsText(strAudit, "recovery phrase: present"),
2455 "the encrypted SQLite wallet still has its recovery phrase") ? 0 : 1; 2455 "the encrypted SQLite wallet still has its recovery phrase") ? 0 : 1;
2456
2457 // One-shot storage commands honour -walletbackend. The SQLite wallet is
2458 // encrypted; the wallet.dat beside it is still plaintext. Same datadir,
2459 // opposite answers -> the flag routes the diagnostic to the right file.
2460 string strSqliteAuditJson = tmp + "/sqlite-audit.json";
2461 vector<string> vSqliteAuditArgs;
2462 vSqliteAuditArgs.push_back("-datadir=" + tmp);
2463 vSqliteAuditArgs.push_back("-walletbackend=sqlite");
2464 vSqliteAuditArgs.push_back("-walletstorageauditjson=" + strSqliteAuditJson);
2465 vSqliteAuditArgs.push_back("-nogui");
2466 int nSqliteAuditRet = RunBitflashChild(strExe, vSqliteAuditArgs);
2467 nFail += Check(nSqliteAuditRet == 0 &&
2468 FileContainsText(strSqliteAuditJson, "\"encrypted_hd_seed\": \"complete\"") &&
2469 FileContainsText(strSqliteAuditJson, "\"plain_hd_seed\": \"none\""),
2470 "-walletstorageaudit under SQLite reads the encrypted wallet.sqlite") ? 0 : 1;
2471
2472 string strBdbAuditJson = tmp + "/bdb-audit.json";
2473 vector<string> vBdbAuditArgs;
2474 vBdbAuditArgs.push_back("-datadir=" + tmp);
2475 vBdbAuditArgs.push_back("-walletstorageauditjson=" + strBdbAuditJson);
2476 vBdbAuditArgs.push_back("-nogui");
2477 int nBdbAuditRet = RunBitflashChild(strExe, vBdbAuditArgs);
2478 nFail += Check(nBdbAuditRet == 0 &&
2479 FileContainsText(strBdbAuditJson, "\"plain_hd_seed\": \"complete\"") &&
2480 FileContainsText(strBdbAuditJson, "\"encrypted_hd_seed\": \"none\""),
2481 "-walletstorageaudit without the flag still reads the plaintext wallet.dat") ? 0 : 1;
2482
2483 string strSqliteCheckOut = tmp + "/sqlite-check.txt";
2484 vector<string> vSqliteCheckArgs;
2485 vSqliteCheckArgs.push_back("-datadir=" + tmp);
2486 vSqliteCheckArgs.push_back("-walletbackend=sqlite");
2487 vSqliteCheckArgs.push_back("-walletstoragecheck");
2488 vSqliteCheckArgs.push_back("-nogui");
2489 int nSqliteCheckRet = RunBitflashChild(strExe, vSqliteCheckArgs, NULL, &strSqliteCheckOut);
2490 nFail += Check(nSqliteCheckRet == 0,
2491 "-walletstoragecheck under SQLite passes on the encrypted wallet.sqlite") ? 0 : 1;
2492
2493 // Backup under SQLite copies wallet.sqlite, not the plaintext wallet.dat.
2494 // The copy is a standalone SQLite wallet (loadcheck accepts it) and holds
2495 // none of the plaintext key that wallet.dat still contains.
2496 string strBackupDest = tmp + "/backup.sqlite";
2497 vector<string> vBackupArgs;
2498 vBackupArgs.push_back("-datadir=" + tmp);
2499 vBackupArgs.push_back("-walletbackend=sqlite");
2500 vBackupArgs.push_back("-backupwallet=" + strBackupDest);
2501 vBackupArgs.push_back("-nogui");
2502 int nBackupRet = RunBitflashChild(strExe, vBackupArgs);
2503 nFail += Check(nBackupRet == 0 && FileExists(strBackupDest.c_str()),
2504 "-backupwallet under SQLite writes a backup file") ? 0 : 1;
2505 nFail += Check(!FileContainsBytes(strBackupDest, vchDefaultPrivBytes),
2506 "the SQLite backup holds no plaintext key (it copied wallet.sqlite, not wallet.dat)") ? 0 : 1;
2507
2508 string strBackupLoadCheck = tmp + "/backup-loadcheck.txt";
2509 vector<string> vLoadCheckArgs;
2510 vLoadCheckArgs.push_back("-datadir=" + tmp);
2511 vLoadCheckArgs.push_back("-walletsqliteloadcheck=" + strBackupDest);
2512 vLoadCheckArgs.push_back("-nogui");
2513 int nBackupLoadRet = RunBitflashChild(strExe, vLoadCheckArgs, NULL, &strBackupLoadCheck);
2514 nFail += Check(nBackupLoadRet == 0,
2515 "the SQLite backup is a valid standalone SQLite wallet") ? 0 : 1;
2456 } 2516 }
2457 catch (const std::exception& e) 2517 catch (const std::exception& e)
2458 { 2518 {