mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-08 13:49:35 +02:00
Merge #18982: wallet: Minimal fix to restore conflicted transaction notifications
7eaf86d3bftrivial: Suggested cleanups to surrounding code (Russell Yanofsky)b604c5c8b5wallet: Minimal fix to restore conflicted transaction notifications (Russell Yanofsky) Pull request description: This fix is a based on the fix by Antoine Riard (ariard) in https://github.com/bitcoin/bitcoin/pull/18600. Unlike that PR, which implements some new behavior, this just restores previous wallet notification and status behavior for transactions removed from the mempool because they conflict with transactions in a block. The behavior was accidentally changed in two `CWallet::BlockConnected` updates:a31be09bfdand7e89994133from https://github.com/bitcoin/bitcoin/pull/16624, causing issue https://github.com/bitcoin/bitcoin/issues/18325. The change here could be improved and replaced with a more comprehensive cleanup, so it includes a detailed comment explaining future considerations. Fixes #18325 Co-authored-by: Antoine Riard (ariard) ACKs for top commit: jonatack: Re-ACK7eaf86d3bfariard: ACK7eaf86d, reviewed, built and ran tests. MarcoFalke: ACK7eaf86d3bf🍡 Tree-SHA512: 9a1efe975969bb522a9dd73c41064a9348887cb67883cd92c6571fd2df4321b9f4568363891abdaae14a3b9b168ef8142e95c373fc04677e46289b251fb84689
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include <script/descriptor.h>
|
||||
#include <script/script.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <txmempool.h>
|
||||
#include <util/bip32.h>
|
||||
#include <util/check.h>
|
||||
#include <util/error.h>
|
||||
@@ -1100,23 +1101,52 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, CWalletTx::Confirmatio
|
||||
MarkInputsDirty(ptx);
|
||||
}
|
||||
|
||||
void CWallet::transactionAddedToMempool(const CTransactionRef& ptx) {
|
||||
void CWallet::transactionAddedToMempool(const CTransactionRef& tx) {
|
||||
LOCK(cs_wallet);
|
||||
CWalletTx::Confirmation confirm(CWalletTx::Status::UNCONFIRMED, /* block_height */ 0, {}, /* nIndex */ 0);
|
||||
SyncTransaction(ptx, confirm);
|
||||
SyncTransaction(tx, {CWalletTx::Status::UNCONFIRMED, /* block height */ 0, /* block hash */ {}, /* index */ 0});
|
||||
|
||||
auto it = mapWallet.find(ptx->GetHash());
|
||||
auto it = mapWallet.find(tx->GetHash());
|
||||
if (it != mapWallet.end()) {
|
||||
it->second.fInMempool = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CWallet::transactionRemovedFromMempool(const CTransactionRef &ptx) {
|
||||
void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) {
|
||||
LOCK(cs_wallet);
|
||||
auto it = mapWallet.find(ptx->GetHash());
|
||||
auto it = mapWallet.find(tx->GetHash());
|
||||
if (it != mapWallet.end()) {
|
||||
it->second.fInMempool = false;
|
||||
}
|
||||
// Handle transactions that were removed from the mempool because they
|
||||
// conflict with transactions in a newly connected block.
|
||||
if (reason == MemPoolRemovalReason::CONFLICT) {
|
||||
// Call SyncNotifications, so external -walletnotify notifications will
|
||||
// be triggered for these transactions. Set Status::UNCONFIRMED instead
|
||||
// of Status::CONFLICTED for a few reasons:
|
||||
//
|
||||
// 1. The transactionRemovedFromMempool callback does not currently
|
||||
// provide the conflicting block's hash and height, and for backwards
|
||||
// compatibility reasons it may not be not safe to store conflicted
|
||||
// wallet transactions with a null block hash. See
|
||||
// https://github.com/bitcoin/bitcoin/pull/18600#discussion_r420195993.
|
||||
// 2. For most of these transactions, the wallet's internal conflict
|
||||
// detection in the blockConnected handler will subsequently call
|
||||
// MarkConflicted and update them with CONFLICTED status anyway. This
|
||||
// applies to any wallet transaction that has inputs spent in the
|
||||
// block, or that has ancestors in the wallet with inputs spent by
|
||||
// the block.
|
||||
// 3. Longstanding behavior since the sync implementation in
|
||||
// https://github.com/bitcoin/bitcoin/pull/9371 and the prior sync
|
||||
// implementation before that was to mark these transactions
|
||||
// unconfirmed rather than conflicted.
|
||||
//
|
||||
// Nothing described above should be seen as an unchangeable requirement
|
||||
// when improving this code in the future. The wallet's heuristics for
|
||||
// distinguishing between conflicted and unconfirmed transactions are
|
||||
// imperfect, and could be improved in general, see
|
||||
// https://github.com/bitcoin-core/bitcoin-devwiki/wiki/Wallet-Transaction-Conflict-Tracking
|
||||
SyncTransaction(tx, {CWalletTx::Status::UNCONFIRMED, /* block height */ 0, /* block hash */ {}, /* index */ 0});
|
||||
}
|
||||
}
|
||||
|
||||
void CWallet::blockConnected(const CBlock& block, int height)
|
||||
@@ -1127,9 +1157,8 @@ void CWallet::blockConnected(const CBlock& block, int height)
|
||||
m_last_block_processed_height = height;
|
||||
m_last_block_processed = block_hash;
|
||||
for (size_t index = 0; index < block.vtx.size(); index++) {
|
||||
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, height, block_hash, index);
|
||||
SyncTransaction(block.vtx[index], confirm);
|
||||
transactionRemovedFromMempool(block.vtx[index]);
|
||||
SyncTransaction(block.vtx[index], {CWalletTx::Status::CONFIRMED, height, block_hash, (int)index});
|
||||
transactionRemovedFromMempool(block.vtx[index], MemPoolRemovalReason::BLOCK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1144,8 +1173,7 @@ void CWallet::blockDisconnected(const CBlock& block, int height)
|
||||
m_last_block_processed_height = height - 1;
|
||||
m_last_block_processed = block.hashPrevBlock;
|
||||
for (const CTransactionRef& ptx : block.vtx) {
|
||||
CWalletTx::Confirmation confirm(CWalletTx::Status::UNCONFIRMED, /* block_height */ 0, {}, /* nIndex */ 0);
|
||||
SyncTransaction(ptx, confirm);
|
||||
SyncTransaction(ptx, {CWalletTx::Status::UNCONFIRMED, /* block height */ 0, /* block hash */ {}, /* index */ 0});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1685,8 +1713,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
|
||||
break;
|
||||
}
|
||||
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
|
||||
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, block_height, block_hash, posInBlock);
|
||||
SyncTransaction(block.vtx[posInBlock], confirm, fUpdate);
|
||||
SyncTransaction(block.vtx[posInBlock], {CWalletTx::Status::CONFIRMED, block_height, block_hash, (int)posInBlock}, fUpdate);
|
||||
}
|
||||
// scan succeeded, record block as most recent successfully scanned
|
||||
result.last_scanned_block = block_hash;
|
||||
|
||||
@@ -921,7 +921,7 @@ public:
|
||||
uint256 last_failed_block;
|
||||
};
|
||||
ScanResult ScanForWalletTransactions(const uint256& start_block, int start_height, Optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate);
|
||||
void transactionRemovedFromMempool(const CTransactionRef &ptx) override;
|
||||
void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) override;
|
||||
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
void ResendWalletTransactions();
|
||||
struct Balance {
|
||||
|
||||
Reference in New Issue
Block a user