diff options
-rwxr-xr-x | test/functional/feature_rbf.py | 87 | ||||
-rwxr-xr-x | test/functional/test_framework/messages.py | 2 |
2 files changed, 42 insertions, 47 deletions
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py index 5cbbd60cad..04f6681566 100755 --- a/test/functional/feature_rbf.py +++ b/test/functional/feature_rbf.py @@ -7,14 +7,16 @@ from decimal import Decimal from test_framework.blocktools import COINBASE_MATURITY -from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut +from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, BIP125_SEQUENCE_NUMBER from test_framework.script import CScript, OP_DROP from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error, satoshi_round from test_framework.script_util import DUMMY_P2WPKH_SCRIPT, DUMMY_2_P2WPKH_SCRIPT +from test_framework.wallet import MiniWallet MAX_REPLACEMENT_LIMIT = 100 + def txToHex(tx): return tx.serialize().hex() @@ -565,67 +567,60 @@ class ReplaceByFeeTest(BitcoinTestFramework): assert_equal(json1["vin"][0]["sequence"], 4294967294) def test_no_inherited_signaling(self): - # Send tx from which to conflict outputs later - base_txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10")) - self.nodes[0].generate(1) - self.sync_blocks() + wallet = MiniWallet(self.nodes[0]) + wallet.scan_blocks(start=76, num=1) + confirmed_utxo = wallet.get_utxo() # Create an explicitly opt-in parent transaction - optin_parent_tx = self.nodes[0].createrawtransaction([{ - 'txid': base_txid, - 'vout': 0, - "sequence": 0xfffffffd, - }], {self.nodes[0].getnewaddress(): Decimal("9.99998")}) - - optin_parent_tx = self.nodes[0].signrawtransactionwithwallet(optin_parent_tx) - - # Broadcast parent tx - optin_parent_txid = self.nodes[0].sendrawtransaction(hexstring=optin_parent_tx["hex"], maxfeerate=0) - assert optin_parent_txid in self.nodes[0].getrawmempool() - - replacement_parent_tx = self.nodes[0].createrawtransaction([{ - 'txid': base_txid, - 'vout': 0, - "sequence": 0xfffffffd, - }], {self.nodes[0].getnewaddress(): Decimal("9.90000")}) - - replacement_parent_tx = self.nodes[0].signrawtransactionwithwallet(replacement_parent_tx) + optin_parent_tx = wallet.send_self_transfer( + from_node=self.nodes[0], + utxo_to_spend=confirmed_utxo, + sequence=BIP125_SEQUENCE_NUMBER, + fee_rate=Decimal('0.01'), + ) + assert_equal(True, self.nodes[0].getmempoolentry(optin_parent_tx['txid'])['bip125-replaceable']) + + replacement_parent_tx = wallet.create_self_transfer( + from_node=self.nodes[0], + utxo_to_spend=confirmed_utxo, + sequence=BIP125_SEQUENCE_NUMBER, + fee_rate=Decimal('0.02'), + ) # Test if parent tx can be replaced. - res = self.nodes[0].testmempoolaccept(rawtxs=[replacement_parent_tx['hex']], maxfeerate=0)[0] + res = self.nodes[0].testmempoolaccept(rawtxs=[replacement_parent_tx['hex']])[0] # Parent can be replaced. assert_equal(res['allowed'], True) # Create an opt-out child tx spending the opt-in parent - optout_child_tx = self.nodes[0].createrawtransaction([{ - 'txid': optin_parent_txid, - 'vout': 0, - "sequence": 0xffffffff, - }], {self.nodes[0].getnewaddress(): Decimal("9.99990")}) - - optout_child_tx = self.nodes[0].signrawtransactionwithwallet(optout_child_tx) - - # Broadcast child tx - optout_child_txid = self.nodes[0].sendrawtransaction(hexstring=optout_child_tx["hex"], maxfeerate=0) - assert optout_child_txid in self.nodes[0].getrawmempool() - - replacement_child_tx = self.nodes[0].createrawtransaction([{ - 'txid': optin_parent_txid, - 'vout': 0, - "sequence": 0xffffffff, - }], {self.nodes[0].getnewaddress(): Decimal("9.00000")}) - - replacement_child_tx = self.nodes[0].signrawtransactionwithwallet(replacement_child_tx) + parent_utxo = wallet.get_utxo(txid=optin_parent_tx['txid']) + optout_child_tx = wallet.send_self_transfer( + from_node=self.nodes[0], + utxo_to_spend=parent_utxo, + sequence=0xffffffff, + fee_rate=Decimal('0.01'), + ) + + # Reports true due to inheritance + assert_equal(True, self.nodes[0].getmempoolentry(optout_child_tx['txid'])['bip125-replaceable']) + + replacement_child_tx = wallet.create_self_transfer( + from_node=self.nodes[0], + utxo_to_spend=parent_utxo, + sequence=0xffffffff, + fee_rate=Decimal('0.02'), + mempool_valid=False, + ) # Broadcast replacement child tx # BIP 125 : # 1. The original transactions signal replaceability explicitly or through inheritance as described in the above # Summary section. - # The original transaction (`optout_child_tx`) doesn't signal RBF but its parent (`optin_parent_txid`) does. + # The original transaction (`optout_child_tx`) doesn't signal RBF but its parent (`optin_parent_tx`) does. # The replacement transaction (`replacement_child_tx`) should be able to replace the original transaction. # See CVE-2021-31876 for further explanations. - assert optin_parent_txid in self.nodes[0].getrawmempool() + assert_equal(True, self.nodes[0].getmempoolentry(optin_parent_tx['txid'])['bip125-replaceable']) assert_raises_rpc_error(-26, 'txn-mempool-conflict', self.nodes[0].sendrawtransaction, replacement_child_tx["hex"], 0) if __name__ == '__main__': diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index 5a9736a7a3..3d79174356 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -39,7 +39,7 @@ MAX_BLOOM_HASH_FUNCS = 50 COIN = 100000000 # 1 btc in satoshis MAX_MONEY = 21000000 * COIN -BIP125_SEQUENCE_NUMBER = 0xfffffffd # Sequence number that is BIP 125 opt-in and BIP 68-opt-out +BIP125_SEQUENCE_NUMBER = 0xfffffffd # Sequence number that is rbf-opt-in (BIP 125) and csv-opt-out (BIP 68) MAX_PROTOCOL_MESSAGE_LENGTH = 4000000 # Maximum length of incoming protocol messages MAX_HEADERS_RESULTS = 2000 # Number of headers sent in one getheaders result |