Skip to content

Commit afaaba6

Browse files
committed
test: refactor out same-txid-diff-wtxid tx to reuse in other tests
useful to easily create transactions with same txid, different wtxid and valid witness for testing scenarios in other places (ex: private broadcast connections)
1 parent 084eee0 commit afaaba6

File tree

2 files changed

+59
-42
lines changed

2 files changed

+59
-42
lines changed

test/functional/mempool_accept_wtxid.py

Lines changed: 6 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,18 @@
77
with identical non-witness data but different witness.
88
"""
99

10-
from copy import deepcopy
1110
from test_framework.messages import (
1211
COIN,
13-
COutPoint,
14-
CTransaction,
15-
CTxIn,
16-
CTxInWitness,
17-
CTxOut,
18-
sha256,
1912
)
2013
from test_framework.p2p import P2PTxInvStore
21-
from test_framework.script import (
22-
CScript,
23-
OP_0,
24-
OP_ELSE,
25-
OP_ENDIF,
26-
OP_EQUAL,
27-
OP_HASH160,
28-
OP_IF,
29-
OP_TRUE,
30-
hash160,
31-
)
14+
from test_framework.script_util import ValidWitnessMalleatedTx
3215
from test_framework.test_framework import BitcoinTestFramework
3316
from test_framework.util import (
3417
assert_not_equal,
3518
assert_equal,
3619
)
3720

21+
3822
class MempoolWtxidTest(BitcoinTestFramework):
3923
def set_test_params(self):
4024
self.num_nodes = 1
@@ -50,38 +34,19 @@ def run_test(self):
5034
assert_equal(node.getmempoolinfo()['size'], 0)
5135

5236
self.log.info("Submit parent with multiple script branches to mempool")
53-
hashlock = hash160(b'Preimage')
54-
witness_script = CScript([OP_IF, OP_HASH160, hashlock, OP_EQUAL, OP_ELSE, OP_TRUE, OP_ENDIF])
55-
witness_program = sha256(witness_script)
56-
script_pubkey = CScript([OP_0, witness_program])
57-
58-
parent = CTransaction()
59-
parent.vin.append(CTxIn(COutPoint(int(txid, 16), 0), b""))
60-
parent.vout.append(CTxOut(int(9.99998 * COIN), script_pubkey))
37+
txgen = ValidWitnessMalleatedTx()
38+
parent = txgen.build_parent_tx(txid, 9.99998 * COIN)
6139

6240
privkeys = [node.get_deterministic_priv_key().key]
6341
raw_parent = node.signrawtransactionwithkey(hexstring=parent.serialize().hex(), privkeys=privkeys)['hex']
64-
parent_txid = node.sendrawtransaction(hexstring=raw_parent, maxfeerate=0)
42+
signed_parent_txid = node.sendrawtransaction(hexstring=raw_parent, maxfeerate=0)
6543
self.generate(node, 1)
6644

6745
peer_wtxid_relay = node.add_p2p_connection(P2PTxInvStore())
6846

69-
# Create a new transaction with witness solving first branch
70-
child_witness_script = CScript([OP_TRUE])
71-
child_witness_program = sha256(child_witness_script)
72-
child_script_pubkey = CScript([OP_0, child_witness_program])
73-
74-
child_one = CTransaction()
75-
child_one.vin.append(CTxIn(COutPoint(int(parent_txid, 16), 0), b""))
76-
child_one.vout.append(CTxOut(int(9.99996 * COIN), child_script_pubkey))
77-
child_one.wit.vtxinwit.append(CTxInWitness())
78-
child_one.wit.vtxinwit[0].scriptWitness.stack = [b'Preimage', b'\x01', witness_script]
47+
child_one, child_two = txgen.build_malleated_children(signed_parent_txid, 9.99996 * COIN)
7948
child_one_wtxid = child_one.wtxid_hex
8049
child_one_txid = child_one.txid_hex
81-
82-
# Create another identical transaction with witness solving second branch
83-
child_two = deepcopy(child_one)
84-
child_two.wit.vtxinwit[0].scriptWitness.stack = [b'', witness_script]
8550
child_two_wtxid = child_two.wtxid_hex
8651
child_two_txid = child_two.txid_hex
8752

test/functional/test_framework/script_util.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@
55
"""Useful Script constants and utils."""
66
import unittest
77

8+
from copy import deepcopy
9+
10+
from test_framework.messages import (
11+
COutPoint,
12+
CTransaction,
13+
CTxIn,
14+
CTxInWitness,
15+
CTxOut,
16+
sha256,
17+
)
818
from test_framework.script import (
919
CScript,
1020
OP_0,
@@ -14,12 +24,15 @@
1424
OP_CHECKMULTISIG,
1525
OP_CHECKSIG,
1626
OP_DUP,
27+
OP_ELSE,
28+
OP_ENDIF,
1729
OP_EQUAL,
1830
OP_EQUALVERIFY,
1931
OP_HASH160,
32+
OP_IF,
2033
OP_RETURN,
34+
OP_TRUE,
2135
hash160,
22-
sha256,
2336
)
2437

2538
# To prevent a "tx-size-small" policy rule error, a transaction has to have a
@@ -131,6 +144,45 @@ def check_script(script):
131144
assert False
132145

133146

147+
class ValidWitnessMalleatedTx:
148+
"""
149+
Creates a valid witness malleation transaction test case:
150+
- Parent transaction with a script supporting 2 branches
151+
- 2 child transactions with the same txid but different wtxids
152+
"""
153+
def __init__(self):
154+
hashlock = hash160(b'Preimage')
155+
self.witness_script = CScript([OP_IF, OP_HASH160, hashlock, OP_EQUAL, OP_ELSE, OP_TRUE, OP_ENDIF])
156+
157+
def build_parent_tx(self, funding_txid, amount):
158+
# Create an unsigned parent transaction paying to the witness script.
159+
witness_program = sha256(self.witness_script)
160+
script_pubkey = CScript([OP_0, witness_program])
161+
162+
parent = CTransaction()
163+
parent.vin.append(CTxIn(COutPoint(int(funding_txid, 16), 0), b""))
164+
parent.vout.append(CTxOut(int(amount), script_pubkey))
165+
return parent
166+
167+
def build_malleated_children(self, signed_parent_txid, amount):
168+
# Create 2 valid children that differ only in witness data.
169+
# 1. Create a new transaction with witness solving first branch
170+
child_witness_script = CScript([OP_TRUE])
171+
child_witness_program = sha256(child_witness_script)
172+
child_script_pubkey = CScript([OP_0, child_witness_program])
173+
174+
child_one = CTransaction()
175+
child_one.vin.append(CTxIn(COutPoint(int(signed_parent_txid, 16), 0), b""))
176+
child_one.vout.append(CTxOut(int(amount), child_script_pubkey))
177+
child_one.wit.vtxinwit.append(CTxInWitness())
178+
child_one.wit.vtxinwit[0].scriptWitness.stack = [b'Preimage', b'\x01', self.witness_script]
179+
180+
# 2. Create another identical transaction with witness solving second branch
181+
child_two = deepcopy(child_one)
182+
child_two.wit.vtxinwit[0].scriptWitness.stack = [b'', self.witness_script]
183+
return child_one, child_two
184+
185+
134186
class TestFrameworkScriptUtil(unittest.TestCase):
135187
def test_multisig(self):
136188
fake_pubkey = bytes([0]*33)

0 commit comments

Comments
 (0)