diff --git a/test/functional/feature_coinstatsindex.py b/test/functional/feature_coinstatsindex.py index 8db201e644..bbf8be877a 100755 --- a/test/functional/feature_coinstatsindex.py +++ b/test/functional/feature_coinstatsindex.py @@ -129,17 +129,17 @@ def _test_coin_stats_index(self): # Test an older block height that included a normal tx res5 = index_node.gettxoutsetinfo(hash_option, 102) - assert_equal(Decimal(res5['total_unspendable_amount']), Decimal('200.0002592')) + assert_equal(Decimal(res5['total_unspendable_amount']), Decimal('200.00028080')) assert_equal(res5['block_info'], { - 'unspendable': Decimal('0.00025920'), + 'unspendable': Decimal('0.00028080'), 'prevout_spent': 200, - 'new_outputs_ex_coinbase': Decimal('199.99971200'), - 'coinbase': Decimal('200.00002880'), + 'new_outputs_ex_coinbase': Decimal('199.99968800'), + 'coinbase': Decimal('200.00003120'), 'unspendables': { 'genesis_block': 0, 'bip30': 0, 'scripts': 0, - 'unclaimed_rewards': Decimal('0.00025920'), + 'unclaimed_rewards': Decimal('0.00028080'), } }) self.block_sanity_check(res5['block_info']) @@ -166,7 +166,7 @@ def _test_coin_stats_index(self): for hash_option in index_hash_options: # Check all amounts were registered correctly res6 = index_node.gettxoutsetinfo(hash_option, 108) - assert_equal(res6['total_unspendable_amount'], Decimal('220.99976820')) + assert_equal(res6['total_unspendable_amount'], Decimal('220.99978980')) assert_equal(res6['block_info'], { 'unspendable': Decimal('20.99950900'), 'prevout_spent': Decimal('221.00000000'), @@ -197,7 +197,7 @@ def _test_coin_stats_index(self): for hash_option in index_hash_options: res7 = index_node.gettxoutsetinfo(hash_option, 109) - assert_equal(res7['total_unspendable_amount'], Decimal('380.99976820')) + assert_equal(res7['total_unspendable_amount'], Decimal('380.99978980')) assert_equal(res7['block_info'], { 'unspendable': Decimal('160.00000000'), 'prevout_spent': 0, diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py index da8c4220a7..344dccfc7e 100755 --- a/test/functional/feature_maxuploadtarget.py +++ b/test/functional/feature_maxuploadtarget.py @@ -106,7 +106,7 @@ def run_test(self): assert_equal(len(self.nodes[0].getpeerinfo()), 3) # At most a couple more tries should succeed (depending on how long # the test has been running so far). - for _ in range(10): + for _ in range(100): p2p_conns[0].send_message(getdata_request) p2p_conns[0].wait_for_disconnect() assert_equal(len(self.nodes[0].getpeerinfo()), 2) diff --git a/test/functional/feature_utxo_set_hash.py b/test/functional/feature_utxo_set_hash.py index 4a97dbbe5a..86d4f7f442 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'], "f4edcc42a569bfef13f56306cf32821774ce36b0868cabbf698859d453b3ee0a") - assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "6aebab920c5c6102e2ae8fe94122c0cf6546e48eb167a9278693c00f7b348436") + assert_equal(node.gettxoutsetinfo()['hash_serialized_2'], "4b7ea0bd09947f5d0d9f983dfce3f590a5a2e1a83aa2ab252561b849d3f23d73") + assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "88f5d8f48b36504974ce92cfd1f91a7000a5bb28288126b81d4788b7250b5b00") def run_test(self): self.test_muhash_implementation() diff --git a/test/functional/mempool_compatibility.py b/test/functional/mempool_compatibility.py index 39d18ca716..dbc09dc885 100755 --- a/test/functional/mempool_compatibility.py +++ b/test/functional/mempool_compatibility.py @@ -7,17 +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. -Download node binaries: -test/get_previous_releases.py -b v0.19.1 v0.18.1 v0.17.2 v0.16.3 v0.15.2 - -Only v0.15.2 is required by this test. The rest is used in other backwards compatibility tests. +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 BGLTestFramework -from test_framework.wallet import MiniWallet +from test_framework.wallet import ( + MiniWallet, + MiniWalletMode, +) class MempoolCompatibilityTest(BGLTestFramework): @@ -40,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 98a96cf8d6..c2d9db6f65 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 import sha3 -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("rbgl", 1, scriptPubKey[2:]) + assert_equal(address, 'rbgl1p9yfmy5h72durp7zrhlw9lf7jpwjgvwdg0jr0lqmmjtgg83266lqsylg5sy') + 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 1ad75314b3..613a80fbf6 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,8 @@ 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( cache_node, diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py index c87fd98584..d29620f49b 100644 --- a/test/functional/test_framework/wallet.py +++ b/test/functional/test_framework/wallet.py @@ -7,7 +7,6 @@ from copy import deepcopy from decimal import Decimal from enum import Enum -from random import choice from typing import ( Any, List, @@ -15,13 +14,14 @@ ) from test_framework.address import ( base58_to_byte, - ADDRESS_BCRT1_P2WSH_OP_TRUE, + create_deterministic_address_bcrt1_p2tr_op_true, key_to_p2pkh, key_to_p2sh_p2wpkh, key_to_p2wpkh, output_key_to_p2tr, ) - +from random import choice +from typing import Optional from test_framework.descriptors import descsum_create from test_framework.key import ( ECKey, @@ -39,8 +39,9 @@ from test_framework.script import ( CScript, LegacySignatureHash, - OP_TRUE, + LEAF_VERSION_TAPSCRIPT, OP_NOP, + OP_TRUE, SIGHASH_ALL, taproot_construct, ) @@ -56,7 +57,6 @@ assert_equal, assert_greater_than_or_equal, ) -from enum import Enum DEFAULT_FEE = Decimal("0.0001") @@ -64,7 +64,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 @@ -74,7 +74,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 """ @@ -100,7 +100,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 _create_utxo(self, *, txid, vout, value, height): @@ -283,7 +283,7 @@ def create_self_transfer(self, *, fee_rate=Decimal("0.003"), fee=Decimal("0"), u """Create and return a tx with the specified fee. If fee is 0, use fee_rate, where the resulting fee may be exact or at most one satoshi higher than needed.""" utxo_to_spend = utxo_to_spend or self.get_utxo() 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 = utxo_to_spend["value"] - (fee or (fee_rate * vsize / 1000)) @@ -300,10 +300,10 @@ def create_self_transfer(self, *, fee_rate=Decimal("0.003"), fee=Decimal("0"), u 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() assert_equal(tx.get_vsize(), vsize)