diff options
| author | bitflash <dev@bitflash.network> | 2026-08-18 14:44:11 -0300 |
|---|---|---|
| committer | bitflash <dev@bitflash.network> | 2026-08-18 14:44:11 -0300 |
| commit | 84a60275569dca5d1fb12db38ce184caf7487ed6 (patch) | |
| tree | 23e39a26b340324a7a33a115aded3b70b5332816 /src/selftest.cpp | |
| parent | 440d7f393d74f309d29e1d10ba1f11c41c869226 (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.cpp | 60 |
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 | { |