diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py index 420147542e2..39859d01512 100755 --- a/test/functional/feature_rbf.py +++ b/test/functional/feature_rbf.py @@ -47,8 +47,8 @@ def set_test_params(self): def run_test(self): self.wallet = MiniWallet(self.nodes[0]) # the pre-mined test framework chain contains coinbase outputs to the - # MiniWallet's default address ADDRESS_BCRT1_P2WSH_OP_TRUE in blocks - # 76-100 (see method BitcoinTestFramework._initialize_chain()) + # MiniWallet's default address in blocks 76-100 (see method + # BitcoinTestFramework._initialize_chain()) self.wallet.rescan_utxos() self.log.info("Running test simple doublespend...") diff --git a/test/functional/feature_utxo_set_hash.py b/test/functional/feature_utxo_set_hash.py index b1b4703d37a..33b7615aeaf 100755 --- a/test/functional/feature_utxo_set_hash.py +++ b/test/functional/feature_utxo_set_hash.py @@ -69,8 +69,8 @@ def test_muhash_implementation(self): assert_equal(finalized[::-1].hex(), node_muhash) self.log.info("Test deterministic UTXO set hash results") - assert_equal(node.gettxoutsetinfo()['hash_serialized_2'], "5b1b44097406226c0eb8e1362cd17a1f346522cf9390a8175a57a5262cb1963f") - assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "4b8803075d7151d06fad3e88b68ba726886794873fbfa841d12aefb2cc2b881b") + assert_equal(node.gettxoutsetinfo()['hash_serialized_2'], "221f245cf4c9010eeb7f5183d342c002ae6c1c27e98aa357dccb788c21d98049") + assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "7c0890c68501f7630d36aeb3999dc924e63af084ae1bbfba11dd462144637635") def run_test(self): self.test_muhash_implementation() diff --git a/test/functional/mempool_compatibility.py b/test/functional/mempool_compatibility.py index 5263920dae7..d450b40582e 100755 --- a/test/functional/mempool_compatibility.py +++ b/test/functional/mempool_compatibility.py @@ -7,14 +7,17 @@ NOTE: The test is designed to prevent cases when compatibility is broken accidentally. In case we need to break mempool compatibility we can continue to use the test by just bumping the version number. -The previous release v0.15.2 is required by this test, see test/README.md. +The previous release v0.19.1 is required by this test, see test/README.md. """ import os from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework -from test_framework.wallet import MiniWallet +from test_framework.wallet import ( + MiniWallet, + MiniWalletMode, +) class MempoolCompatibilityTest(BitcoinTestFramework): @@ -37,7 +40,7 @@ def run_test(self): self.log.info("Test that mempool.dat is compatible between versions") old_node, new_node = self.nodes - new_wallet = MiniWallet(new_node) + new_wallet = MiniWallet(new_node, mode=MiniWalletMode.RAW_P2PK) self.generate(new_wallet, 1, sync_fun=self.no_op) self.generate(new_node, COINBASE_MATURITY, sync_fun=self.no_op) # Sync the nodes to ensure old_node has the block that contains the coinbase that new_wallet will spend. diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py index fe733e9368d..89839c9bab3 100644 --- a/test/functional/test_framework/address.py +++ b/test/functional/test_framework/address.py @@ -5,12 +5,21 @@ """Encode and decode Bitcoin addresses. - base58 P2PKH and P2SH addresses. -- bech32 segwit v0 P2WPKH and P2WSH addresses.""" +- bech32 segwit v0 P2WPKH and P2WSH addresses. +- bech32m segwit v1 P2TR addresses.""" import enum import unittest -from .script import hash256, hash160, sha256, CScript, OP_0 +from .script import ( + CScript, + OP_0, + OP_TRUE, + hash160, + hash256, + sha256, + taproot_construct, +) from .segwit_addr import encode_segwit_address from .util import assert_equal @@ -29,6 +38,21 @@ class AddressType(enum.Enum): chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' +def create_deterministic_address_bcrt1_p2tr_op_true(): + """ + Generates a deterministic bech32m address (segwit v1 output) that + can be spent with a witness stack of OP_TRUE and the control block + with internal public key (script-path spending). + + Returns a tuple with the generated address and the internal key. + """ + internal_key = (1).to_bytes(32, 'big') + scriptPubKey = taproot_construct(internal_key, [(None, CScript([OP_TRUE]))]).scriptPubKey + address = encode_segwit_address("bcrt", 1, scriptPubKey[2:]) + assert_equal(address, 'bcrt1p9yfmy5h72durp7zrhlw9lf7jpwjgvwdg0jr0lqmmjtgg83266lqsekaqka') + return (address, internal_key) + + def byte_to_base58(b, version): result = '' str = b.hex() diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 84d94b34f7e..b18c050e0ac 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -19,7 +19,7 @@ import time from typing import List -from .address import ADDRESS_BCRT1_P2WSH_OP_TRUE +from .address import create_deterministic_address_bcrt1_p2tr_op_true from .authproxy import JSONRPCException from . import coverage from .p2p import NetworkThread @@ -777,7 +777,7 @@ def _initialize_chain(self): # block in the cache does not age too much (have an old tip age). # This is needed so that we are out of IBD when the test starts, # see the tip age check in IsInitialBlockDownload(). - gen_addresses = [k.address for k in TestNode.PRIV_KEYS][:3] + [ADDRESS_BCRT1_P2WSH_OP_TRUE] + gen_addresses = [k.address for k in TestNode.PRIV_KEYS][:3] + [create_deterministic_address_bcrt1_p2tr_op_true()[0]] assert_equal(len(gen_addresses), 4) for i in range(8): self.generatetoaddress( diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py index d2c21f35258..7de69947358 100644 --- a/test/functional/test_framework/wallet.py +++ b/test/functional/test_framework/wallet.py @@ -9,7 +9,7 @@ from enum import Enum from random import choice from typing import Optional -from test_framework.address import ADDRESS_BCRT1_P2WSH_OP_TRUE +from test_framework.address import create_deterministic_address_bcrt1_p2tr_op_true from test_framework.descriptors import descsum_create from test_framework.key import ECKey from test_framework.messages import ( @@ -24,8 +24,9 @@ from test_framework.script import ( CScript, LegacySignatureHash, - OP_TRUE, + LEAF_VERSION_TAPSCRIPT, OP_NOP, + OP_TRUE, SIGHASH_ALL, ) from test_framework.script_util import ( @@ -43,7 +44,7 @@ class MiniWalletMode(Enum): """Determines the transaction type the MiniWallet is creating and spending. For most purposes, the default mode ADDRESS_OP_TRUE should be sufficient; - it simply uses a fixed bech32 P2WSH address whose coins are spent with a + it simply uses a fixed bech32m P2TR address whose coins are spent with a witness stack of OP_TRUE, i.e. following an anyone-can-spend policy. However, if the transactions need to be modified by the user (e.g. prepending scriptSig for testing opcodes that are activated by a soft-fork), or the txs @@ -53,7 +54,7 @@ class MiniWalletMode(Enum): | output | | tx is | can modify | needs mode | description | address | standard | scriptSig | signing ----------------+-------------------+-----------+----------+------------+---------- - ADDRESS_OP_TRUE | anyone-can-spend | bech32 | yes | no | no + ADDRESS_OP_TRUE | anyone-can-spend | bech32m | yes | no | no RAW_OP_TRUE | anyone-can-spend | - (raw) | no | yes | no RAW_P2PK | pay-to-public-key | - (raw) | yes | yes | yes """ @@ -79,7 +80,7 @@ def __init__(self, test_node, *, mode=MiniWalletMode.ADDRESS_OP_TRUE): pub_key = self._priv_key.get_pubkey() self._scriptPubKey = key_to_p2pk_script(pub_key.get_bytes()) elif mode == MiniWalletMode.ADDRESS_OP_TRUE: - self._address = ADDRESS_BCRT1_P2WSH_OP_TRUE + self._address, self._internal_key = create_deterministic_address_bcrt1_p2tr_op_true() self._scriptPubKey = bytes.fromhex(self._test_node.validateaddress(self._address)['scriptPubKey']) def rescan_utxos(self): @@ -174,7 +175,7 @@ def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_ self._utxos = sorted(self._utxos, key=lambda k: (k['value'], -k['height'])) utxo_to_spend = utxo_to_spend or self._utxos.pop() # Pick the largest utxo (if none provided) and hope it covers the fee if self._priv_key is None: - vsize = Decimal(96) # anyone-can-spend + vsize = Decimal(104) # anyone-can-spend else: vsize = Decimal(168) # P2PK (73 bytes scriptSig + 35 bytes scriptPubKey + 60 bytes other) send_value = int(COIN * (utxo_to_spend['value'] - fee_rate * (vsize / 1000))) @@ -191,10 +192,10 @@ def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_ self.sign_tx(tx) else: # anyone-can-spend - tx.vin[0].scriptSig = CScript([OP_NOP] * 35) # pad to identical size + tx.vin[0].scriptSig = CScript([OP_NOP] * 43) # pad to identical size else: tx.wit.vtxinwit = [CTxInWitness()] - tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])] + tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), bytes([LEAF_VERSION_TAPSCRIPT]) + self._internal_key] tx_hex = tx.serialize().hex() tx_info = from_node.testmempoolaccept([tx_hex])[0]