Skip to content

Commit f8586b2

Browse files
committed
Merge bitcoin/bitcoin#25289: test: implement 'bech32m' mode for getnewdestination() helper
dcf36fe test: implement 'bech32m' mode for `getnewdestination()` helper (Sebastian Falbesoner) 1999dcf test: add helpers for creating P2TR scripts/addresses from output key (Sebastian Falbesoner) Pull request description: This PR adds the missing 'bech32m' mode for the `getnewdestination()` helper and sets it as default, i.e. the function returns a tuple (output x-only-pubkey, scriptPubKey, taproot address) now if not specified otherwise. In a preparation commit, the helpers `output_key_to_p2tr{_script}` are introduced. Note that in contrast to all other common script output types, there are usually _two_ keys involved in creating a taproot output (internal key and output key), hence the prefix `output_` is used to clarify that the output key is expected and the helpers don't do any key tweaking. Thanks to michaelfolkson (for pointing out this TODO that I forgot about) and sipa (for patiently explaining basic things about BIP341). ACKs for top commit: michaelfolkson: ACK dcf36fe w0xlt: reACK bitcoin/bitcoin@dcf36fe Tree-SHA512: 5bb8d5fd96c63092ede10c3f022ffb2e13c14e333c4aa73348d95deb70cbf0a74745218dc4a7c419eb846793dd69e8217a7b4332a13ae2b2758e100b51fb1a9f
2 parents e5df0ba + dcf36fe commit f8586b2

File tree

5 files changed

+27
-16
lines changed

5 files changed

+27
-16
lines changed

test/functional/rpc_createmultisig.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def get_keys(self):
4343
if self.is_bdb_compiled():
4444
self.final = node2.getnewaddress()
4545
else:
46-
self.final = getnewdestination()[2]
46+
self.final = getnewdestination('bech32')[2]
4747

4848
def run_test(self):
4949
node0, node1, node2 = self.nodes
@@ -66,9 +66,7 @@ def run_test(self):
6666

6767
# Test mixed compressed and uncompressed pubkeys
6868
self.log.info('Mixed compressed and uncompressed multisigs are not allowed')
69-
pk0 = getnewdestination()[0].hex()
70-
pk1 = getnewdestination()[0].hex()
71-
pk2 = getnewdestination()[0].hex()
69+
pk0, pk1, pk2 = [getnewdestination('bech32')[0].hex() for _ in range(3)]
7270

7371
# decompress pk2
7472
pk_obj = ECPubKey()

test/functional/test_framework/address.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ def create_deterministic_address_bcrt1_p2tr_op_true():
4747
Returns a tuple with the generated address and the internal key.
4848
"""
4949
internal_key = (1).to_bytes(32, 'big')
50-
scriptPubKey = taproot_construct(internal_key, [(None, CScript([OP_TRUE]))]).scriptPubKey
51-
address = encode_segwit_address("bcrt", 1, scriptPubKey[2:])
50+
address = output_key_to_p2tr(taproot_construct(internal_key, [(None, CScript([OP_TRUE]))]).output_pubkey)
5251
assert_equal(address, 'bcrt1p9yfmy5h72durp7zrhlw9lf7jpwjgvwdg0jr0lqmmjtgg83266lqsekaqka')
5352
return (address, internal_key)
5453

@@ -141,6 +140,10 @@ def script_to_p2sh_p2wsh(script, main=False):
141140
p2shscript = CScript([OP_0, sha256(script)])
142141
return script_to_p2sh(p2shscript, main)
143142

143+
def output_key_to_p2tr(key, main=False):
144+
assert len(key) == 32
145+
return program_to_witness(1, key, main)
146+
144147
def check_key(key):
145148
if (type(key) is str):
146149
key = bytes.fromhex(key) # Assuming this is hex string

test/functional/test_framework/script_util.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ def script_to_p2sh_p2wsh_script(script):
105105
return script_to_p2sh_script(p2shscript)
106106

107107

108+
def output_key_to_p2tr_script(key):
109+
assert len(key) == 32
110+
return program_to_witness_script(1, key)
111+
112+
108113
def check_key(key):
109114
if isinstance(key, str):
110115
key = bytes.fromhex(key) # Assuming this is hex string

test/functional/test_framework/wallet.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@
1919
key_to_p2pkh,
2020
key_to_p2sh_p2wpkh,
2121
key_to_p2wpkh,
22+
output_key_to_p2tr,
2223
)
2324
from test_framework.descriptors import descsum_create
24-
from test_framework.key import ECKey
25+
from test_framework.key import (
26+
ECKey,
27+
compute_xonly_pubkey,
28+
)
2529
from test_framework.messages import (
2630
COIN,
2731
COutPoint,
@@ -38,6 +42,7 @@
3842
OP_NOP,
3943
OP_TRUE,
4044
SIGHASH_ALL,
45+
taproot_construct,
4146
)
4247
from test_framework.script_util import (
4348
key_to_p2pk_script,
@@ -286,10 +291,10 @@ def sendrawtransaction(self, *, from_node, tx_hex, maxfeerate=0, **kwargs):
286291
return txid
287292

288293

289-
def getnewdestination(address_type='bech32'):
294+
def getnewdestination(address_type='bech32m'):
290295
"""Generate a random destination of the specified type and return the
291296
corresponding public key, scriptPubKey and address. Supported types are
292-
'legacy', 'p2sh-segwit' and 'bech32'. Can be used when a random
297+
'legacy', 'p2sh-segwit', 'bech32' and 'bech32m'. Can be used when a random
293298
destination is needed, but no compiled wallet is available (e.g. as
294299
replacement to the getnewaddress/getaddressinfo RPCs)."""
295300
key = ECKey()
@@ -304,7 +309,11 @@ def getnewdestination(address_type='bech32'):
304309
elif address_type == 'bech32':
305310
scriptpubkey = key_to_p2wpkh_script(pubkey)
306311
address = key_to_p2wpkh(pubkey)
307-
# TODO: also support bech32m (need to generate x-only-pubkey)
312+
elif address_type == 'bech32m':
313+
tap = taproot_construct(compute_xonly_pubkey(key.get_bytes())[0])
314+
pubkey = tap.output_pubkey
315+
scriptpubkey = tap.scriptPubKey
316+
address = output_key_to_p2tr(pubkey)
308317
else:
309318
assert False
310319
return pubkey, scriptpubkey, address

test/functional/wallet_taproot.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,18 @@
77
import random
88

99
from decimal import Decimal
10+
from test_framework.address import output_key_to_p2tr
1011
from test_framework.test_framework import BitcoinTestFramework
1112
from test_framework.util import assert_equal
1213
from test_framework.descriptors import descsum_create
1314
from test_framework.script import (
1415
CScript,
1516
MAX_PUBKEYS_PER_MULTI_A,
16-
OP_1,
1717
OP_CHECKSIG,
1818
OP_CHECKSIGADD,
1919
OP_NUMEQUAL,
2020
taproot_construct,
2121
)
22-
from test_framework.segwit_addr import encode_segwit_address
2322

2423
# xprvs/xpubs, and m/* derived x-only pubkeys (created using independent implementation)
2524
KEYS = [
@@ -183,10 +182,7 @@ def multi_a(k, hex_keys, sort=False):
183182

184183
def compute_taproot_address(pubkey, scripts):
185184
"""Compute the address for a taproot output with given inner key and scripts."""
186-
tap = taproot_construct(pubkey, scripts)
187-
assert tap.scriptPubKey[0] == OP_1
188-
assert tap.scriptPubKey[1] == 0x20
189-
return encode_segwit_address("bcrt", 1, tap.scriptPubKey[2:])
185+
return output_key_to_p2tr(taproot_construct(pubkey, scripts).output_pubkey)
190186

191187
class WalletTaprootTest(BitcoinTestFramework):
192188
"""Test generation and spending of P2TR address outputs."""

0 commit comments

Comments
 (0)