diff options
| author | bitflash <dev@bitflash.network> | 2026-08-18 14:33:40 -0300 |
|---|---|---|
| committer | bitflash <dev@bitflash.network> | 2026-08-18 14:33:40 -0300 |
| commit | 440d7f393d74f309d29e1d10ba1f11c41c869226 (patch) | |
| tree | 40c881b79ba7a2571cfd2bcfbb274031a5739071 /src/db.cpp | |
| parent | e58c4022e0ddd137b93cdb3464753bef5df1d456 (diff) | |
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.
Diffstat (limited to 'src/db.cpp')
| -rw-r--r-- | src/db.cpp | 34 |
1 files changed, 34 insertions, 0 deletions
| @@ -164,6 +164,40 @@ bool WalletSQLiteRuntimeEraseRecord(const vector<unsigned char>& vchKey) | |||
| 164 | return pWalletSQLiteRuntime->EraseRecord(vchKey, strError); | 164 | return pWalletSQLiteRuntime->EraseRecord(vchKey, strError); |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | // Transaction bracket for the SQLite runtime. When the SQLite backend is not | ||
| 168 | // active these are no-ops that succeed, so a caller can wrap a group of related | ||
| 169 | // writes and Berkeley DB keeps its existing per-write behaviour unchanged while | ||
| 170 | // SQLite gets all-or-nothing. | ||
| 171 | bool WalletSQLiteRuntimeBeginTxn() | ||
| 172 | { | ||
| 173 | if (!pWalletSQLiteRuntime) | ||
| 174 | return true; | ||
| 175 | string strError; | ||
| 176 | if (pWalletSQLiteRuntime->BeginTransaction(strError)) | ||
| 177 | return true; | ||
| 178 | printf("WalletSQLiteRuntimeBeginTxn() : %s\n", strError.c_str()); | ||
| 179 | return false; | ||
| 180 | } | ||
| 181 | |||
| 182 | bool WalletSQLiteRuntimeCommitTxn() | ||
| 183 | { | ||
| 184 | if (!pWalletSQLiteRuntime) | ||
| 185 | return true; | ||
| 186 | string strError; | ||
| 187 | if (pWalletSQLiteRuntime->CommitTransaction(strError)) | ||
| 188 | return true; | ||
| 189 | printf("WalletSQLiteRuntimeCommitTxn() : %s\n", strError.c_str()); | ||
| 190 | return false; | ||
| 191 | } | ||
| 192 | |||
| 193 | void WalletSQLiteRuntimeRollbackTxn() | ||
| 194 | { | ||
| 195 | if (!pWalletSQLiteRuntime) | ||
| 196 | return; | ||
| 197 | string strError; | ||
| 198 | pWalletSQLiteRuntime->RollbackTransaction(strError); | ||
| 199 | } | ||
| 200 | |||
| 167 | 201 | ||
| 168 | CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) | 202 | CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) |
| 169 | { | 203 | { |