test: add MiniWallet tagging support to avoid UTXO mixing

Note that this commit doesn't change behaviour yet, as tagging isn't
used in any MiniWallet instance.
This commit is contained in:
Sebastian Falbesoner 2024-04-16 01:32:44 +02:00
parent c8e6d08236
commit b2037ad4ae
2 changed files with 14 additions and 6 deletions

View File

@ -47,7 +47,7 @@ class AddressType(enum.Enum):
b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
def create_deterministic_address_bcrt1_p2tr_op_true(): def create_deterministic_address_bcrt1_p2tr_op_true(explicit_internal_key=None):
""" """
Generates a deterministic bech32m address (segwit v1 output) that Generates a deterministic bech32m address (segwit v1 output) that
can be spent with a witness stack of OP_TRUE and the control block can be spent with a witness stack of OP_TRUE and the control block
@ -55,9 +55,10 @@ def create_deterministic_address_bcrt1_p2tr_op_true():
Returns a tuple with the generated address and the internal key. Returns a tuple with the generated address and the internal key.
""" """
internal_key = (1).to_bytes(32, 'big') internal_key = explicit_internal_key or (1).to_bytes(32, 'big')
address = output_key_to_p2tr(taproot_construct(internal_key, [(None, CScript([OP_TRUE]))]).output_pubkey) address = output_key_to_p2tr(taproot_construct(internal_key, [(None, CScript([OP_TRUE]))]).output_pubkey)
assert_equal(address, 'bcrt1p9yfmy5h72durp7zrhlw9lf7jpwjgvwdg0jr0lqmmjtgg83266lqsekaqka') if explicit_internal_key is None:
assert_equal(address, 'bcrt1p9yfmy5h72durp7zrhlw9lf7jpwjgvwdg0jr0lqmmjtgg83266lqsekaqka')
return (address, internal_key) return (address, internal_key)

View File

@ -32,6 +32,7 @@ from test_framework.messages import (
CTxIn, CTxIn,
CTxInWitness, CTxInWitness,
CTxOut, CTxOut,
hash256,
) )
from test_framework.script import ( from test_framework.script import (
CScript, CScript,
@ -65,7 +66,10 @@ class MiniWalletMode(Enum):
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
should contain an actual signature, the raw modes RAW_OP_TRUE and RAW_P2PK should contain an actual signature, the raw modes RAW_OP_TRUE and RAW_P2PK
can be useful. Summary of modes: can be useful. In order to avoid mixing of UTXOs between different MiniWallet
instances, a tag name can be passed to the default mode, to create different
output scripts. Note that the UTXOs from the pre-generated test chain can
only be spent if no tag is passed. Summary of modes:
| output | | tx is | can modify | needs | output | | tx is | can modify | needs
mode | description | address | standard | scriptSig | signing mode | description | address | standard | scriptSig | signing
@ -80,22 +84,25 @@ class MiniWalletMode(Enum):
class MiniWallet: class MiniWallet:
def __init__(self, test_node, *, mode=MiniWalletMode.ADDRESS_OP_TRUE): def __init__(self, test_node, *, mode=MiniWalletMode.ADDRESS_OP_TRUE, tag_name=None):
self._test_node = test_node self._test_node = test_node
self._utxos = [] self._utxos = []
self._mode = mode self._mode = mode
assert isinstance(mode, MiniWalletMode) assert isinstance(mode, MiniWalletMode)
if mode == MiniWalletMode.RAW_OP_TRUE: if mode == MiniWalletMode.RAW_OP_TRUE:
assert tag_name is None
self._scriptPubKey = bytes(CScript([OP_TRUE])) self._scriptPubKey = bytes(CScript([OP_TRUE]))
elif mode == MiniWalletMode.RAW_P2PK: elif mode == MiniWalletMode.RAW_P2PK:
# use simple deterministic private key (k=1) # use simple deterministic private key (k=1)
assert tag_name is None
self._priv_key = ECKey() self._priv_key = ECKey()
self._priv_key.set((1).to_bytes(32, 'big'), True) self._priv_key.set((1).to_bytes(32, 'big'), True)
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, self._internal_key = create_deterministic_address_bcrt1_p2tr_op_true() internal_key = None if tag_name is None else hash256(tag_name.encode())
self._address, self._internal_key = create_deterministic_address_bcrt1_p2tr_op_true(internal_key)
self._scriptPubKey = address_to_scriptpubkey(self._address) self._scriptPubKey = address_to_scriptpubkey(self._address)
# When the pre-mined test framework chain is used, it contains coinbase # When the pre-mined test framework chain is used, it contains coinbase