|
7 | 7 | from decimal import Decimal
|
8 | 8 |
|
9 | 9 | from test_framework.blocktools import COINBASE_MATURITY
|
10 |
| -from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut |
| 10 | +from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, BIP125_SEQUENCE_NUMBER |
11 | 11 | from test_framework.script import CScript, OP_DROP
|
12 | 12 | from test_framework.test_framework import BitcoinTestFramework
|
13 | 13 | from test_framework.util import assert_equal, assert_raises_rpc_error, satoshi_round
|
14 | 14 | from test_framework.script_util import DUMMY_P2WPKH_SCRIPT, DUMMY_2_P2WPKH_SCRIPT
|
| 15 | +from test_framework.wallet import MiniWallet |
15 | 16 |
|
16 | 17 | MAX_REPLACEMENT_LIMIT = 100
|
17 | 18 |
|
| 19 | + |
18 | 20 | def txToHex(tx):
|
19 | 21 | return tx.serialize().hex()
|
20 | 22 |
|
@@ -565,67 +567,60 @@ def test_rpc(self):
|
565 | 567 | assert_equal(json1["vin"][0]["sequence"], 4294967294)
|
566 | 568 |
|
567 | 569 | def test_no_inherited_signaling(self):
|
568 |
| - # Send tx from which to conflict outputs later |
569 |
| - base_txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10")) |
570 |
| - self.nodes[0].generate(1) |
571 |
| - self.sync_blocks() |
| 570 | + wallet = MiniWallet(self.nodes[0]) |
| 571 | + wallet.scan_blocks(start=76, num=1) |
| 572 | + confirmed_utxo = wallet.get_utxo() |
572 | 573 |
|
573 | 574 | # Create an explicitly opt-in parent transaction
|
574 |
| - optin_parent_tx = self.nodes[0].createrawtransaction([{ |
575 |
| - 'txid': base_txid, |
576 |
| - 'vout': 0, |
577 |
| - "sequence": 0xfffffffd, |
578 |
| - }], {self.nodes[0].getnewaddress(): Decimal("9.99998")}) |
579 |
| - |
580 |
| - optin_parent_tx = self.nodes[0].signrawtransactionwithwallet(optin_parent_tx) |
581 |
| - |
582 |
| - # Broadcast parent tx |
583 |
| - optin_parent_txid = self.nodes[0].sendrawtransaction(hexstring=optin_parent_tx["hex"], maxfeerate=0) |
584 |
| - assert optin_parent_txid in self.nodes[0].getrawmempool() |
585 |
| - |
586 |
| - replacement_parent_tx = self.nodes[0].createrawtransaction([{ |
587 |
| - 'txid': base_txid, |
588 |
| - 'vout': 0, |
589 |
| - "sequence": 0xfffffffd, |
590 |
| - }], {self.nodes[0].getnewaddress(): Decimal("9.90000")}) |
591 |
| - |
592 |
| - replacement_parent_tx = self.nodes[0].signrawtransactionwithwallet(replacement_parent_tx) |
| 575 | + optin_parent_tx = wallet.send_self_transfer( |
| 576 | + from_node=self.nodes[0], |
| 577 | + utxo_to_spend=confirmed_utxo, |
| 578 | + sequence=BIP125_SEQUENCE_NUMBER, |
| 579 | + fee_rate=Decimal('0.01'), |
| 580 | + ) |
| 581 | + assert_equal(True, self.nodes[0].getmempoolentry(optin_parent_tx['txid'])['bip125-replaceable']) |
| 582 | + |
| 583 | + replacement_parent_tx = wallet.create_self_transfer( |
| 584 | + from_node=self.nodes[0], |
| 585 | + utxo_to_spend=confirmed_utxo, |
| 586 | + sequence=BIP125_SEQUENCE_NUMBER, |
| 587 | + fee_rate=Decimal('0.02'), |
| 588 | + ) |
593 | 589 |
|
594 | 590 | # Test if parent tx can be replaced.
|
595 |
| - res = self.nodes[0].testmempoolaccept(rawtxs=[replacement_parent_tx['hex']], maxfeerate=0)[0] |
| 591 | + res = self.nodes[0].testmempoolaccept(rawtxs=[replacement_parent_tx['hex']])[0] |
596 | 592 |
|
597 | 593 | # Parent can be replaced.
|
598 | 594 | assert_equal(res['allowed'], True)
|
599 | 595 |
|
600 | 596 | # Create an opt-out child tx spending the opt-in parent
|
601 |
| - optout_child_tx = self.nodes[0].createrawtransaction([{ |
602 |
| - 'txid': optin_parent_txid, |
603 |
| - 'vout': 0, |
604 |
| - "sequence": 0xffffffff, |
605 |
| - }], {self.nodes[0].getnewaddress(): Decimal("9.99990")}) |
606 |
| - |
607 |
| - optout_child_tx = self.nodes[0].signrawtransactionwithwallet(optout_child_tx) |
608 |
| - |
609 |
| - # Broadcast child tx |
610 |
| - optout_child_txid = self.nodes[0].sendrawtransaction(hexstring=optout_child_tx["hex"], maxfeerate=0) |
611 |
| - assert optout_child_txid in self.nodes[0].getrawmempool() |
612 |
| - |
613 |
| - replacement_child_tx = self.nodes[0].createrawtransaction([{ |
614 |
| - 'txid': optin_parent_txid, |
615 |
| - 'vout': 0, |
616 |
| - "sequence": 0xffffffff, |
617 |
| - }], {self.nodes[0].getnewaddress(): Decimal("9.00000")}) |
618 |
| - |
619 |
| - replacement_child_tx = self.nodes[0].signrawtransactionwithwallet(replacement_child_tx) |
| 597 | + parent_utxo = wallet.get_utxo(txid=optin_parent_tx['txid']) |
| 598 | + optout_child_tx = wallet.send_self_transfer( |
| 599 | + from_node=self.nodes[0], |
| 600 | + utxo_to_spend=parent_utxo, |
| 601 | + sequence=0xffffffff, |
| 602 | + fee_rate=Decimal('0.01'), |
| 603 | + ) |
| 604 | + |
| 605 | + # Reports true due to inheritance |
| 606 | + assert_equal(True, self.nodes[0].getmempoolentry(optout_child_tx['txid'])['bip125-replaceable']) |
| 607 | + |
| 608 | + replacement_child_tx = wallet.create_self_transfer( |
| 609 | + from_node=self.nodes[0], |
| 610 | + utxo_to_spend=parent_utxo, |
| 611 | + sequence=0xffffffff, |
| 612 | + fee_rate=Decimal('0.02'), |
| 613 | + mempool_valid=False, |
| 614 | + ) |
620 | 615 |
|
621 | 616 | # Broadcast replacement child tx
|
622 | 617 | # BIP 125 :
|
623 | 618 | # 1. The original transactions signal replaceability explicitly or through inheritance as described in the above
|
624 | 619 | # Summary section.
|
625 |
| - # The original transaction (`optout_child_tx`) doesn't signal RBF but its parent (`optin_parent_txid`) does. |
| 620 | + # The original transaction (`optout_child_tx`) doesn't signal RBF but its parent (`optin_parent_tx`) does. |
626 | 621 | # The replacement transaction (`replacement_child_tx`) should be able to replace the original transaction.
|
627 | 622 | # See CVE-2021-31876 for further explanations.
|
628 |
| - assert optin_parent_txid in self.nodes[0].getrawmempool() |
| 623 | + assert_equal(True, self.nodes[0].getmempoolentry(optin_parent_tx['txid'])['bip125-replaceable']) |
629 | 624 | assert_raises_rpc_error(-26, 'txn-mempool-conflict', self.nodes[0].sendrawtransaction, replacement_child_tx["hex"], 0)
|
630 | 625 |
|
631 | 626 | if __name__ == '__main__':
|
|
0 commit comments