Merge ElementsProject/elements#1535: Wallet: don't create transaction chains that will be rejected by mempool by default

a76dc401d6 Merge bitcoin/bitcoin#24502: wallet: don't create long chains by default (MarcoFalke)

Pull request description:

  Cherry pick of bitcoin/bitcoin#24502 with additional functional test to check rejection.

ACKs for top commit:
  delta1:
    ACK a76dc401d6; tested locally

Tree-SHA512: e053109dfda4cc2603a286641a1376d83f3d6cbaa42603d23d38e02d77e6c56d1e0192d2fb504b70c6ba44d92850f449c65d5bc22cba8bf108eb6cb5bb64ab82
This commit is contained in:
merge-script 2026-04-17 15:13:40 +02:00
commit 797965ef71
No known key found for this signature in database
GPG key ID: DE8F6EA20A661697
4 changed files with 32 additions and 3 deletions

View file

@ -98,7 +98,7 @@ static const CAmount WALLET_INCREMENTAL_RELAY_FEE = 5000;
//! Default for -spendzeroconfchange
static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true;
//! Default for -walletrejectlongchains
static const bool DEFAULT_WALLET_REJECT_LONG_CHAINS = false;
static const bool DEFAULT_WALLET_REJECT_LONG_CHAINS{true};
//! -txconfirmtarget default
static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;
//! -walletrbf default

View file

@ -53,7 +53,9 @@ class WalletTest(BitcoinTestFramework):
self.num_nodes = 2
self.setup_clean_chain = True
self.extra_args = [
['-limitdescendantcount=3'], # Limit mempool descendants as a hack to have wallet txs rejected from the mempool
# Limit mempool descendants as a hack to have wallet txs rejected from the mempool.
# Set walletrejectlongchains=0 so the wallet still creates the transactions.
['-limitdescendantcount=3', '-walletrejectlongchains=0'],
[],
]

View file

@ -27,6 +27,7 @@ class WalletTest(BitcoinTestFramework):
self.extra_args = [[
"-acceptnonstdtxn=1",
"-bech32_hrp=bcrt",
"-walletrejectlongchains=0"
]] * self.num_nodes
self.setup_clean_chain = True
self.supports_cli = False
@ -573,7 +574,7 @@ class WalletTest(BitcoinTestFramework):
self.log.info("Test -reindex")
self.stop_nodes()
# set lower ancestor limit for later
self.start_node(0, ['-reindex', "-limitancestorcount=" + str(chainlimit)])
self.start_node(0, ['-reindex', "-walletrejectlongchains=0", "-limitancestorcount=" + str(chainlimit)])
self.start_node(1, ['-reindex', "-limitancestorcount=" + str(chainlimit)])
self.start_node(2, ['-reindex', "-limitancestorcount=" + str(chainlimit)])
# reindex will leave rpc warm up "early"; Wait for it to finish

View file

@ -29,6 +29,7 @@ class CreateTxWalletTest(BitcoinTestFramework):
self.test_anti_fee_sniping()
self.test_tx_size_too_large()
self.test_create_too_long_mempool_chain()
def test_anti_fee_sniping(self):
self.log.info('Check that we have some (old) blocks and that anti-fee-sniping is disabled')
@ -80,6 +81,31 @@ class CreateTxWalletTest(BitcoinTestFramework):
)
self.nodes[0].settxfee(0)
def test_create_too_long_mempool_chain(self):
self.log.info('Check too-long mempool chain error')
df_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
self.nodes[0].createwallet("too_long")
test_wallet = self.nodes[0].get_wallet_rpc("too_long")
tx_data = df_wallet.send(outputs=[{test_wallet.getnewaddress(): 25}], options={"change_position": 0})
txid = tx_data['txid']
vout = 1
options = {"change_position": 0, "add_inputs": False}
for i in range(1, 25):
options['inputs'] = [{'txid': txid, 'vout': vout}]
tx_data = test_wallet.send(outputs=[{test_wallet.getnewaddress(): 25 - i}], options=options)
txid = tx_data['txid']
options = {"include_unsafe": True, 'add_inputs': True}
# Sending one more chained transaction will fail
assert_raises_rpc_error(-4, "Insufficient funds",
test_wallet.send, outputs=[{test_wallet.getnewaddress(): 0.3}], options=options)
test_wallet.unloadwallet()
if __name__ == '__main__':
CreateTxWalletTest().main()