| 1476 | } |
| 1477 | |
| 1478 | void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) { |
| 1479 | LOCK(cs_wallet); |
| 1480 | auto it = mapWallet.find(tx->GetHash()); |
| 1481 | if (it != mapWallet.end()) { |
| 1482 | RefreshMempoolStatus(it->second, chain()); |
| 1483 | } |
| 1484 | // Handle transactions that were removed from the mempool because they |
| 1485 | // conflict with transactions in a newly connected block. |
| 1486 | if (reason == MemPoolRemovalReason::CONFLICT) { |
| 1487 | // Trigger external -walletnotify notifications for these transactions. |
| 1488 | // Set Status::UNCONFIRMED instead of Status::CONFLICTED for a few reasons: |
| 1489 | // |
| 1490 | // 1. The transactionRemovedFromMempool callback does not currently |
| 1491 | // provide the conflicting block's hash and height, and for backwards |
| 1492 | // compatibility reasons it may not be not safe to store conflicted |
| 1493 | // wallet transactions with a null block hash. See |
| 1494 | // https://github.com/bitcoin/bitcoin/pull/18600#discussion_r420195993. |
| 1495 | // 2. For most of these transactions, the wallet's internal conflict |
| 1496 | // detection in the blockConnected handler will subsequently call |
| 1497 | // MarkConflicted and update them with CONFLICTED status anyway. This |
| 1498 | // applies to any wallet transaction that has inputs spent in the |
| 1499 | // block, or that has ancestors in the wallet with inputs spent by |
| 1500 | // the block. |
| 1501 | // 3. Longstanding behavior since the sync implementation in |
| 1502 | // https://github.com/bitcoin/bitcoin/pull/9371 and the prior sync |
| 1503 | // implementation before that was to mark these transactions |
| 1504 | // unconfirmed rather than conflicted. |
| 1505 | // |
| 1506 | // Nothing described above should be seen as an unchangeable requirement |
| 1507 | // when improving this code in the future. The wallet's heuristics for |
| 1508 | // distinguishing between conflicted and unconfirmed transactions are |
| 1509 | // imperfect, and could be improved in general, see |
| 1510 | // https://github.com/bitcoin-core/bitcoin-devwiki/wiki/Wallet-Transaction-Conflict-Tracking |
| 1511 | SyncTransaction(tx, TxStateInactive{}); |
| 1512 | } |
| 1513 | |
| 1514 | const Txid& txid = tx->GetHash(); |
| 1515 | |
| 1516 | for (const CTxIn& tx_in : tx->vin) { |
| 1517 | // Iterate over all wallet transactions spending txin.prev |
| 1518 | // and recursively mark them as no longer conflicting with |
| 1519 | // txid |
| 1520 | for (auto range = mapTxSpends.equal_range(tx_in.prevout); range.first != range.second; range.first++) { |
| 1521 | const Txid& spent_id = range.first->second; |
| 1522 | |
| 1523 | RecursiveUpdateTxState(/*batch=*/nullptr, spent_id, [&txid](CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { |
| 1524 | return wtx.mempool_conflicts.erase(txid) ? TxUpdate::CHANGED : TxUpdate::UNCHANGED; |
| 1525 | }); |
| 1526 | } |
| 1527 | } |
| 1528 | |
| 1529 | if (tx->version == TRUC_VERSION) { |
| 1530 | // If this tx has a parent, unset its truc_child_in_mempool to make it possible |
| 1531 | // to spend from the parent again. If this tx was replaced by another |
| 1532 | // child of the same parent, transactionAddedToMempool |
| 1533 | // will update truc_child_in_mempool |
| 1534 | for (const CTxIn& tx_in : tx->vin) { |
| 1535 | auto parent_it = mapWallet.find(tx_in.prevout.hash); |
no test coverage detected