@@ -2388,8 +2388,21 @@ DBErrors CWallet::LoadWallet()
23882388util::Result<void > CWallet::RemoveTxs (std::vector<uint256>& txs_to_remove)
23892389{
23902390 AssertLockHeld (cs_wallet);
2391- WalletBatch batch (GetDatabase ());
2392- if (!batch.TxnBegin ()) return util::Error{_ (" Error starting db txn for wallet transactions removal" )};
2391+ bilingual_str str_err; // future: make RunWithinTxn return a util::Result
2392+ bool was_txn_committed = RunWithinTxn (GetDatabase (), /* process_desc=*/ " remove transactions" , [&](WalletBatch& batch) EXCLUSIVE_LOCKS_REQUIRED (cs_wallet) {
2393+ util::Result<void > result{RemoveTxs (batch, txs_to_remove)};
2394+ if (!result) str_err = util::ErrorString (result);
2395+ return result.has_value ();
2396+ });
2397+ if (!str_err.empty ()) return util::Error{str_err};
2398+ if (!was_txn_committed) return util::Error{_ (" Error starting/committing db txn for wallet transactions removal process" )};
2399+ return {}; // all good
2400+ }
2401+
2402+ util::Result<void > CWallet::RemoveTxs (WalletBatch& batch, std::vector<uint256>& txs_to_remove)
2403+ {
2404+ AssertLockHeld (cs_wallet);
2405+ if (!batch.HasActiveTxn ()) return util::Error{strprintf (_ (" The transactions removal process can only be executed within a db txn" ))};
23932406
23942407 // Check for transaction existence and remove entries from disk
23952408 using TxIterator = std::unordered_map<uint256, CWalletTx, SaltedTxidHasher>::const_iterator;
@@ -2398,38 +2411,30 @@ util::Result<void> CWallet::RemoveTxs(std::vector<uint256>& txs_to_remove)
23982411 for (const uint256& hash : txs_to_remove) {
23992412 auto it_wtx = mapWallet.find (hash);
24002413 if (it_wtx == mapWallet.end ()) {
2401- str_err = strprintf (_ (" Transaction %s does not belong to this wallet" ), hash.GetHex ());
2402- break ;
2414+ return util::Error{strprintf (_ (" Transaction %s does not belong to this wallet" ), hash.GetHex ())};
24032415 }
24042416 if (!batch.EraseTx (hash)) {
2405- str_err = strprintf (_ (" Failure removing transaction: %s" ), hash.GetHex ());
2406- break ;
2417+ return util::Error{strprintf (_ (" Failure removing transaction: %s" ), hash.GetHex ())};
24072418 }
24082419 erased_txs.emplace_back (it_wtx);
24092420 }
24102421
2411- // Roll back removals in case of an error
2412- if (!str_err.empty ()) {
2413- batch.TxnAbort ();
2414- return util::Error{str_err};
2415- }
2416-
2417- // Dump changes to disk
2418- if (!batch.TxnCommit ()) return util::Error{_ (" Error committing db txn for wallet transactions removal" )};
2419-
2420- // Update the in-memory state and notify upper layers about the removals
2421- for (const auto & it : erased_txs) {
2422- const uint256 hash{it->first };
2423- wtxOrdered.erase (it->second .m_it_wtxOrdered );
2424- for (const auto & txin : it->second .tx ->vin )
2425- mapTxSpends.erase (txin.prevout );
2426- mapWallet.erase (it);
2427- NotifyTransactionChanged (hash, CT_DELETED);
2428- }
2422+ // Register callback to update the memory state only when the db txn is actually dumped to disk
2423+ batch.RegisterTxnListener ({.on_commit =[&, erased_txs]() EXCLUSIVE_LOCKS_REQUIRED (cs_wallet) {
2424+ // Update the in-memory state and notify upper layers about the removals
2425+ for (const auto & it : erased_txs) {
2426+ const uint256 hash{it->first };
2427+ wtxOrdered.erase (it->second .m_it_wtxOrdered );
2428+ for (const auto & txin : it->second .tx ->vin )
2429+ mapTxSpends.erase (txin.prevout );
2430+ mapWallet.erase (it);
2431+ NotifyTransactionChanged (hash, CT_DELETED);
2432+ }
24292433
2430- MarkDirty ();
2434+ MarkDirty ();
2435+ }, .on_abort ={}});
24312436
2432- return {}; // all good
2437+ return {};
24332438}
24342439
24352440bool CWallet::SetAddressBookWithDB (WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::optional<AddressPurpose>& new_purpose)
0 commit comments