@@ -1264,11 +1264,6 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
1264
1264
{
1265
1265
LOCK (cs_wallet);
1266
1266
1267
- WalletBatch batch (GetDatabase ());
1268
-
1269
- std::set<uint256> todo;
1270
- std::set<uint256> done;
1271
-
1272
1267
// Can't mark abandoned if confirmed or in mempool
1273
1268
auto it = mapWallet.find (hashTx);
1274
1269
assert (it != mapWallet.end ());
@@ -1277,44 +1272,25 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
1277
1272
return false ;
1278
1273
}
1279
1274
1280
- todo.insert (hashTx);
1281
-
1282
- while (!todo.empty ()) {
1283
- uint256 now = *todo.begin ();
1284
- todo.erase (now);
1285
- done.insert (now);
1286
- auto it = mapWallet.find (now);
1287
- assert (it != mapWallet.end ());
1288
- CWalletTx& wtx = it->second ;
1289
- int currentconfirm = GetTxDepthInMainChain (wtx);
1290
- // If the orig tx was not in block, none of its spends can be
1291
- assert (currentconfirm <= 0 );
1292
- // if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon}
1293
- if (currentconfirm == 0 && !wtx.isAbandoned ()) {
1294
- // If the orig tx was not in block/mempool, none of its spends can be in mempool
1295
- assert (!wtx.InMempool ());
1275
+ auto try_updating_state = [](CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED (cs_wallet) {
1276
+ // If the orig tx was not in block/mempool, none of its spends can be.
1277
+ assert (!wtx.isConfirmed ());
1278
+ assert (!wtx.InMempool ());
1279
+ // If already conflicted or abandoned, no need to set abandoned
1280
+ if (!wtx.isConflicted () && !wtx.isAbandoned ()) {
1296
1281
wtx.m_state = TxStateInactive{/* abandoned=*/ true };
1297
- wtx.MarkDirty ();
1298
- batch.WriteTx (wtx);
1299
- NotifyTransactionChanged (wtx.GetHash (), CT_UPDATED);
1300
- // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too.
1301
- // States are not permanent, so these transactions can become unabandoned if they are re-added to the
1302
- // mempool, or confirmed in a block, or conflicted.
1303
- // Note: If the reorged coinbase is re-added to the main chain, the descendants that have not had their
1304
- // states change will remain abandoned and will require manual broadcast if the user wants them.
1305
- for (unsigned int i = 0 ; i < wtx.tx ->vout .size (); ++i) {
1306
- std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range (COutPoint (now, i));
1307
- for (TxSpends::const_iterator iter = range.first ; iter != range.second ; ++iter) {
1308
- if (!done.count (iter->second )) {
1309
- todo.insert (iter->second );
1310
- }
1311
- }
1312
- }
1313
- // If a transaction changes 'conflicted' state, that changes the balance
1314
- // available of the outputs it spends. So force those to be recomputed
1315
- MarkInputsDirty (wtx.tx );
1282
+ return TxUpdate::NOTIFY_CHANGED;
1316
1283
}
1317
- }
1284
+ return TxUpdate::UNCHANGED;
1285
+ };
1286
+
1287
+ // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too.
1288
+ // States are not permanent, so these transactions can become unabandoned if they are re-added to the
1289
+ // mempool, or confirmed in a block, or conflicted.
1290
+ // Note: If the reorged coinbase is re-added to the main chain, the descendants that have not had their
1291
+ // states change will remain abandoned and will require manual broadcast if the user wants them.
1292
+
1293
+ RecursiveUpdateTxState (hashTx, try_updating_state);
1318
1294
1319
1295
return true ;
1320
1296
}
@@ -1331,13 +1307,29 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
1331
1307
if (conflictconfirms >= 0 )
1332
1308
return ;
1333
1309
1310
+ auto try_updating_state = [&](CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED (cs_wallet) {
1311
+ if (conflictconfirms < GetTxDepthInMainChain (wtx)) {
1312
+ // Block is 'more conflicted' than current confirm; update.
1313
+ // Mark transaction as conflicted with this block.
1314
+ wtx.m_state = TxStateConflicted{hashBlock, conflicting_height};
1315
+ return TxUpdate::CHANGED;
1316
+ }
1317
+ return TxUpdate::UNCHANGED;
1318
+ };
1319
+
1320
+ // Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too.
1321
+ RecursiveUpdateTxState (hashTx, try_updating_state);
1322
+
1323
+ }
1324
+
1325
+ void CWallet::RecursiveUpdateTxState (const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
1334
1326
// Do not flush the wallet here for performance reasons
1335
1327
WalletBatch batch (GetDatabase (), false );
1336
1328
1337
1329
std::set<uint256> todo;
1338
1330
std::set<uint256> done;
1339
1331
1340
- todo.insert (hashTx );
1332
+ todo.insert (tx_hash );
1341
1333
1342
1334
while (!todo.empty ()) {
1343
1335
uint256 now = *todo.begin ();
@@ -1346,14 +1338,12 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
1346
1338
auto it = mapWallet.find (now);
1347
1339
assert (it != mapWallet.end ());
1348
1340
CWalletTx& wtx = it->second ;
1349
- int currentconfirm = GetTxDepthInMainChain (wtx);
1350
- if (conflictconfirms < currentconfirm) {
1351
- // Block is 'more conflicted' than current confirm; update.
1352
- // Mark transaction as conflicted with this block.
1353
- wtx.m_state = TxStateConflicted{hashBlock, conflicting_height};
1341
+
1342
+ TxUpdate update_state = try_updating_state (wtx);
1343
+ if (update_state != TxUpdate::UNCHANGED) {
1354
1344
wtx.MarkDirty ();
1355
1345
batch.WriteTx (wtx);
1356
- // Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too
1346
+ // Iterate over all its outputs, and update those tx states as well (if applicable)
1357
1347
for (unsigned int i = 0 ; i < wtx.tx ->vout .size (); ++i) {
1358
1348
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range (COutPoint (now, i));
1359
1349
for (TxSpends::const_iterator iter = range.first ; iter != range.second ; ++iter) {
@@ -1362,7 +1352,12 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
1362
1352
}
1363
1353
}
1364
1354
}
1365
- // If a transaction changes 'conflicted' state, that changes the balance
1355
+
1356
+ if (update_state == TxUpdate::NOTIFY_CHANGED) {
1357
+ NotifyTransactionChanged (wtx.GetHash (), CT_UPDATED);
1358
+ }
1359
+
1360
+ // If a transaction changes its tx state, that usually changes the balance
1366
1361
// available of the outputs it spends. So force those to be recomputed
1367
1362
MarkInputsDirty (wtx.tx );
1368
1363
}
0 commit comments