mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-04 13:55:23 -05:00
test: MiniWallet: add P2TR support and use it per default
This commit is contained in:
parent
4a2edf2bf7
commit
041abfebe4
6 changed files with 47 additions and 19 deletions
|
@ -47,8 +47,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
self.wallet = MiniWallet(self.nodes[0])
|
self.wallet = MiniWallet(self.nodes[0])
|
||||||
# the pre-mined test framework chain contains coinbase outputs to the
|
# the pre-mined test framework chain contains coinbase outputs to the
|
||||||
# MiniWallet's default address ADDRESS_BCRT1_P2WSH_OP_TRUE in blocks
|
# MiniWallet's default address in blocks 76-100 (see method
|
||||||
# 76-100 (see method BitcoinTestFramework._initialize_chain())
|
# BitcoinTestFramework._initialize_chain())
|
||||||
self.wallet.rescan_utxos()
|
self.wallet.rescan_utxos()
|
||||||
|
|
||||||
self.log.info("Running test simple doublespend...")
|
self.log.info("Running test simple doublespend...")
|
||||||
|
|
|
@ -69,8 +69,8 @@ class UTXOSetHashTest(BitcoinTestFramework):
|
||||||
assert_equal(finalized[::-1].hex(), node_muhash)
|
assert_equal(finalized[::-1].hex(), node_muhash)
|
||||||
|
|
||||||
self.log.info("Test deterministic UTXO set hash results")
|
self.log.info("Test deterministic UTXO set hash results")
|
||||||
assert_equal(node.gettxoutsetinfo()['hash_serialized_2'], "5b1b44097406226c0eb8e1362cd17a1f346522cf9390a8175a57a5262cb1963f")
|
assert_equal(node.gettxoutsetinfo()['hash_serialized_2'], "221f245cf4c9010eeb7f5183d342c002ae6c1c27e98aa357dccb788c21d98049")
|
||||||
assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "4b8803075d7151d06fad3e88b68ba726886794873fbfa841d12aefb2cc2b881b")
|
assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "7c0890c68501f7630d36aeb3999dc924e63af084ae1bbfba11dd462144637635")
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
self.test_muhash_implementation()
|
self.test_muhash_implementation()
|
||||||
|
|
|
@ -7,14 +7,17 @@
|
||||||
NOTE: The test is designed to prevent cases when compatibility is broken accidentally.
|
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.
|
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
|
import os
|
||||||
|
|
||||||
from test_framework.blocktools import COINBASE_MATURITY
|
from test_framework.blocktools import COINBASE_MATURITY
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.wallet import MiniWallet
|
from test_framework.wallet import (
|
||||||
|
MiniWallet,
|
||||||
|
MiniWalletMode,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MempoolCompatibilityTest(BitcoinTestFramework):
|
class MempoolCompatibilityTest(BitcoinTestFramework):
|
||||||
|
@ -37,7 +40,7 @@ class MempoolCompatibilityTest(BitcoinTestFramework):
|
||||||
self.log.info("Test that mempool.dat is compatible between versions")
|
self.log.info("Test that mempool.dat is compatible between versions")
|
||||||
|
|
||||||
old_node, new_node = self.nodes
|
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_wallet, 1, sync_fun=self.no_op)
|
||||||
self.generate(new_node, COINBASE_MATURITY, 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.
|
# Sync the nodes to ensure old_node has the block that contains the coinbase that new_wallet will spend.
|
||||||
|
|
|
@ -5,12 +5,21 @@
|
||||||
"""Encode and decode Bitcoin addresses.
|
"""Encode and decode Bitcoin addresses.
|
||||||
|
|
||||||
- base58 P2PKH and P2SH 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 enum
|
||||||
import unittest
|
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 .segwit_addr import encode_segwit_address
|
||||||
from .util import assert_equal
|
from .util import assert_equal
|
||||||
|
|
||||||
|
@ -29,6 +38,21 @@ class AddressType(enum.Enum):
|
||||||
chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
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):
|
def byte_to_base58(b, version):
|
||||||
result = ''
|
result = ''
|
||||||
str = b.hex()
|
str = b.hex()
|
||||||
|
|
|
@ -19,7 +19,7 @@ import tempfile
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from typing import List
|
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 .authproxy import JSONRPCException
|
||||||
from . import coverage
|
from . import coverage
|
||||||
from .p2p import NetworkThread
|
from .p2p import NetworkThread
|
||||||
|
@ -777,7 +777,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||||
# block in the cache does not age too much (have an old tip age).
|
# 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,
|
# This is needed so that we are out of IBD when the test starts,
|
||||||
# see the tip age check in IsInitialBlockDownload().
|
# 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)
|
assert_equal(len(gen_addresses), 4)
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
self.generatetoaddress(
|
self.generatetoaddress(
|
||||||
|
|
|
@ -9,7 +9,7 @@ from decimal import Decimal
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from random import choice
|
from random import choice
|
||||||
from typing import Optional
|
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.descriptors import descsum_create
|
||||||
from test_framework.key import ECKey
|
from test_framework.key import ECKey
|
||||||
from test_framework.messages import (
|
from test_framework.messages import (
|
||||||
|
@ -24,8 +24,9 @@ from test_framework.messages import (
|
||||||
from test_framework.script import (
|
from test_framework.script import (
|
||||||
CScript,
|
CScript,
|
||||||
LegacySignatureHash,
|
LegacySignatureHash,
|
||||||
OP_TRUE,
|
LEAF_VERSION_TAPSCRIPT,
|
||||||
OP_NOP,
|
OP_NOP,
|
||||||
|
OP_TRUE,
|
||||||
SIGHASH_ALL,
|
SIGHASH_ALL,
|
||||||
)
|
)
|
||||||
from test_framework.script_util import (
|
from test_framework.script_util import (
|
||||||
|
@ -43,7 +44,7 @@ class MiniWalletMode(Enum):
|
||||||
"""Determines the transaction type the MiniWallet is creating and spending.
|
"""Determines the transaction type the MiniWallet is creating and spending.
|
||||||
|
|
||||||
For most purposes, the default mode ADDRESS_OP_TRUE should be sufficient;
|
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.
|
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
|
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
|
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
|
| output | | tx is | can modify | needs
|
||||||
mode | description | address | standard | scriptSig | signing
|
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_OP_TRUE | anyone-can-spend | - (raw) | no | yes | no
|
||||||
RAW_P2PK | pay-to-public-key | - (raw) | yes | yes | yes
|
RAW_P2PK | pay-to-public-key | - (raw) | yes | yes | yes
|
||||||
"""
|
"""
|
||||||
|
@ -79,7 +80,7 @@ class MiniWallet:
|
||||||
pub_key = self._priv_key.get_pubkey()
|
pub_key = self._priv_key.get_pubkey()
|
||||||
self._scriptPubKey = key_to_p2pk_script(pub_key.get_bytes())
|
self._scriptPubKey = key_to_p2pk_script(pub_key.get_bytes())
|
||||||
elif mode == MiniWalletMode.ADDRESS_OP_TRUE:
|
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'])
|
self._scriptPubKey = bytes.fromhex(self._test_node.validateaddress(self._address)['scriptPubKey'])
|
||||||
|
|
||||||
def rescan_utxos(self):
|
def rescan_utxos(self):
|
||||||
|
@ -174,7 +175,7 @@ class MiniWallet:
|
||||||
self._utxos = sorted(self._utxos, key=lambda k: (k['value'], -k['height']))
|
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
|
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:
|
if self._priv_key is None:
|
||||||
vsize = Decimal(96) # anyone-can-spend
|
vsize = Decimal(104) # anyone-can-spend
|
||||||
else:
|
else:
|
||||||
vsize = Decimal(168) # P2PK (73 bytes scriptSig + 35 bytes scriptPubKey + 60 bytes other)
|
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)))
|
send_value = int(COIN * (utxo_to_spend['value'] - fee_rate * (vsize / 1000)))
|
||||||
|
@ -191,10 +192,10 @@ class MiniWallet:
|
||||||
self.sign_tx(tx)
|
self.sign_tx(tx)
|
||||||
else:
|
else:
|
||||||
# anyone-can-spend
|
# 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:
|
else:
|
||||||
tx.wit.vtxinwit = [CTxInWitness()]
|
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_hex = tx.serialize().hex()
|
||||||
|
|
||||||
tx_info = from_node.testmempoolaccept([tx_hex])[0]
|
tx_info = from_node.testmempoolaccept([tx_hex])[0]
|
||||||
|
|
Loading…
Add table
Reference in a new issue