From 440d7f393d74f309d29e1d10ba1f11c41c869226 Mon Sep 17 00:00:00 2001 From: bitflash Date: Tue, 18 Aug 2026 14:33:40 -0300 Subject: wallet: bracket WriteHDMaster in a SQLite runtime transaction The SQLite runtime wrote each record as its own autocommit, so a group that must land together -- hdmaster and hdchaincode, the two halves of an HD seed -- could be left half-written by a failure or crash between them, the incomplete-seed state -walletstoragecheck exists to catch. Berkeley DB was no worse (it is not transactional here either) but no better. Add WalletSQLiteRuntimeBeginTxn/CommitTxn/RollbackTxn -- no-ops that succeed when the SQLite backend is not active, so Berkeley DB keeps its existing per-write behaviour -- and wrap WriteHDMaster in them so the seed lands all-or-nothing under SQLite. The one BDB-atomic wallet rewrite, the encrypt path, is already matched by its own transaction in the SQLite encrypt branch; every other wallet multi-write is ordering-based on both backends by design. wallet-sqlite self-test now proves the bracket: a rolled-back runtime write leaves no record, a committed one persists, and WriteHDMaster lands both halves of the seed. --- src/db.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'src/db.cpp') diff --git a/src/db.cpp b/src/db.cpp index 86f6dd7..c16edb4 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -164,6 +164,40 @@ bool WalletSQLiteRuntimeEraseRecord(const vector& vchKey) return pWalletSQLiteRuntime->EraseRecord(vchKey, strError); } +// Transaction bracket for the SQLite runtime. When the SQLite backend is not +// active these are no-ops that succeed, so a caller can wrap a group of related +// writes and Berkeley DB keeps its existing per-write behaviour unchanged while +// SQLite gets all-or-nothing. +bool WalletSQLiteRuntimeBeginTxn() +{ + if (!pWalletSQLiteRuntime) + return true; + string strError; + if (pWalletSQLiteRuntime->BeginTransaction(strError)) + return true; + printf("WalletSQLiteRuntimeBeginTxn() : %s\n", strError.c_str()); + return false; +} + +bool WalletSQLiteRuntimeCommitTxn() +{ + if (!pWalletSQLiteRuntime) + return true; + string strError; + if (pWalletSQLiteRuntime->CommitTransaction(strError)) + return true; + printf("WalletSQLiteRuntimeCommitTxn() : %s\n", strError.c_str()); + return false; +} + +void WalletSQLiteRuntimeRollbackTxn() +{ + if (!pWalletSQLiteRuntime) + return; + string strError; + pWalletSQLiteRuntime->RollbackTransaction(strError); +} + CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) { -- cgit v1.2.3