Skip to content

Commit 906b6d9

Browse files
committed
test: Extend feature_rbf.py with no inherited signaling
1 parent 4741aec commit 906b6d9

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed

test/functional/feature_rbf.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ def run_test(self):
115115
self.log.info("Running test prioritised transactions...")
116116
self.test_prioritised_transactions()
117117

118+
self.log.info("Running test no inherited signaling...")
119+
self.test_no_inherited_signaling()
120+
118121
self.log.info("Passed")
119122

120123
def test_simple_doublespend(self):
@@ -563,5 +566,69 @@ def test_rpc(self):
563566
assert_equal(json0["vin"][0]["sequence"], 4294967293)
564567
assert_equal(json1["vin"][0]["sequence"], 4294967294)
565568

569+
def test_no_inherited_signaling(self):
570+
# Send tx from which to conflict outputs later
571+
base_txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
572+
self.nodes[0].generate(1)
573+
self.sync_blocks()
574+
575+
# Create an explicitly opt-in parent transaction
576+
optin_parent_tx = self.nodes[0].createrawtransaction([{
577+
'txid': base_txid,
578+
'vout': 0,
579+
"sequence": 0xfffffffd,
580+
}], {self.nodes[0].getnewaddress(): Decimal("9.99998")})
581+
582+
optin_parent_tx = self.nodes[0].signrawtransactionwithwallet(optin_parent_tx)
583+
584+
# Broadcast parent tx
585+
optin_parent_txid = self.nodes[0].sendrawtransaction(hexstring=optin_parent_tx["hex"], maxfeerate=0)
586+
assert optin_parent_txid in self.nodes[0].getrawmempool()
587+
588+
replacement_parent_tx = self.nodes[0].createrawtransaction([{
589+
'txid': base_txid,
590+
'vout': 0,
591+
"sequence": 0xfffffffd,
592+
}], {self.nodes[0].getnewaddress(): Decimal("9.90000")})
593+
594+
replacement_parent_tx = self.nodes[0].signrawtransactionwithwallet(replacement_parent_tx)
595+
596+
# Test if parent tx can be replaced.
597+
res = self.nodes[0].testmempoolaccept(rawtxs=[replacement_parent_tx['hex']], maxfeerate=0)[0]
598+
599+
# Parent can be replaced.
600+
assert_equal(res['allowed'], True)
601+
602+
# Create an opt-out child tx spending the opt-in parent
603+
optout_child_tx = self.nodes[0].createrawtransaction([{
604+
'txid': optin_parent_txid,
605+
'vout': 0,
606+
"sequence": 0xffffffff,
607+
}], {self.nodes[0].getnewaddress(): Decimal("9.99990")})
608+
609+
optout_child_tx = self.nodes[0].signrawtransactionwithwallet(optout_child_tx)
610+
611+
# Broadcast child tx
612+
optout_child_txid = self.nodes[0].sendrawtransaction(hexstring=optout_child_tx["hex"], maxfeerate=0)
613+
assert optout_child_txid in self.nodes[0].getrawmempool()
614+
615+
replacement_child_tx = self.nodes[0].createrawtransaction([{
616+
'txid': optin_parent_txid,
617+
'vout': 0,
618+
"sequence": 0xffffffff,
619+
}], {self.nodes[0].getnewaddress(): Decimal("9.00000")})
620+
621+
replacement_child_tx = self.nodes[0].signrawtransactionwithwallet(replacement_child_tx)
622+
623+
# Broadcast replacement child tx
624+
# BIP 125 :
625+
# 1. The original transactions signal replaceability explicitly or through inheritance as described in the above
626+
# Summary section.
627+
# The original transaction (`optout_child_tx`) doesn't signal RBF but its parent (`optin_parent_txid`) does.
628+
# The replacement transaction (`replacement_child_tx`) should be able to replace the original transaction.
629+
# See CVE-2021-31876 for further explanations.
630+
assert optin_parent_txid in self.nodes[0].getrawmempool()
631+
assert_raises_rpc_error(-26, 'txn-mempool-conflict', self.nodes[0].sendrawtransaction, replacement_child_tx["hex"], 0)
632+
566633
if __name__ == '__main__':
567634
ReplaceByFeeTest().main()

0 commit comments

Comments
 (0)