@@ -2388,8 +2388,21 @@ DBErrors CWallet::LoadWallet()
2388
2388
util::Result<void > CWallet::RemoveTxs (std::vector<uint256>& txs_to_remove)
2389
2389
{
2390
2390
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" ))};
2393
2406
2394
2407
// Check for transaction existence and remove entries from disk
2395
2408
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)
2398
2411
for (const uint256& hash : txs_to_remove) {
2399
2412
auto it_wtx = mapWallet.find (hash);
2400
2413
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 ())};
2403
2415
}
2404
2416
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 ())};
2407
2418
}
2408
2419
erased_txs.emplace_back (it_wtx);
2409
2420
}
2410
2421
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
+ }
2429
2433
2430
- MarkDirty ();
2434
+ MarkDirty ();
2435
+ }, .on_abort ={}});
2431
2436
2432
- return {}; // all good
2437
+ return {};
2433
2438
}
2434
2439
2435
2440
bool CWallet::SetAddressBookWithDB (WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::optional<AddressPurpose>& new_purpose)
0 commit comments