diff options
Diffstat (limited to 'test/functional/test_framework/wallet.py')
-rw-r--r-- | test/functional/test_framework/wallet.py | 45 |
1 files changed, 27 insertions, 18 deletions
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py index 93f3ea9e81..7249e53676 100644 --- a/test/functional/test_framework/wallet.py +++ b/test/functional/test_framework/wallet.py @@ -19,9 +19,13 @@ from test_framework.address import ( key_to_p2pkh, key_to_p2sh_p2wpkh, key_to_p2wpkh, + output_key_to_p2tr, ) from test_framework.descriptors import descsum_create -from test_framework.key import ECKey +from test_framework.key import ( + ECKey, + compute_xonly_pubkey, +) from test_framework.messages import ( COIN, COutPoint, @@ -38,6 +42,7 @@ from test_framework.script import ( OP_NOP, OP_TRUE, SIGHASH_ALL, + taproot_construct, ) from test_framework.script_util import ( key_to_p2pk_script, @@ -81,8 +86,7 @@ class MiniWallet: def __init__(self, test_node, *, mode=MiniWalletMode.ADDRESS_OP_TRUE): self._test_node = test_node self._utxos = [] - self._priv_key = None - self._address = None + self._mode = mode assert isinstance(mode, MiniWalletMode) if mode == MiniWalletMode.RAW_OP_TRUE: @@ -116,7 +120,7 @@ class MiniWallet: def sign_tx(self, tx, fixed_length=True): """Sign tx that has been created by MiniWallet in P2PK mode""" - assert self._priv_key is not None + assert_equal(self._mode, MiniWalletMode.RAW_P2PK) (sighash, err) = LegacySignatureHash(CScript(self._scriptPubKey), tx, 0, SIGHASH_ALL) assert err is None # for exact fee calculation, create only signatures with fixed size by default (>49.89% probability): @@ -146,6 +150,7 @@ class MiniWallet: return descsum_create(f'raw({self._scriptPubKey.hex()})') def get_address(self): + assert_equal(self._mode, MiniWalletMode.ADDRESS_OP_TRUE) return self._address def get_utxo(self, *, txid: str = '', vout: Optional[int] = None, mark_as_spent=True) -> dict: @@ -252,10 +257,12 @@ class MiniWallet: """Create and return a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed.""" from_node = from_node or self._test_node utxo_to_spend = utxo_to_spend or self.get_utxo() - if self._priv_key is None: + if self._mode in (MiniWalletMode.RAW_OP_TRUE, MiniWalletMode.ADDRESS_OP_TRUE): vsize = Decimal(104) # anyone-can-spend - else: + elif self._mode == MiniWalletMode.RAW_P2PK: vsize = Decimal(168) # P2PK (73 bytes scriptSig + 35 bytes scriptPubKey + 60 bytes other) + else: + assert False send_value = int(COIN * (utxo_to_spend['value'] - fee_rate * (vsize / 1000))) assert send_value > 0 @@ -263,17 +270,15 @@ class MiniWallet: tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']), nSequence=sequence)] tx.vout = [CTxOut(send_value, self._scriptPubKey)] tx.nLockTime = locktime - if not self._address: - # raw script - if self._priv_key is not None: - # P2PK, need to sign - self.sign_tx(tx) - else: - # anyone-can-spend - tx.vin[0].scriptSig = CScript([OP_NOP] * 43) # pad to identical size - else: + if self._mode == MiniWalletMode.RAW_P2PK: + self.sign_tx(tx) + elif self._mode == MiniWalletMode.RAW_OP_TRUE: + tx.vin[0].scriptSig = CScript([OP_NOP] * 43) # pad to identical size + elif self._mode == MiniWalletMode.ADDRESS_OP_TRUE: tx.wit.vtxinwit = [CTxInWitness()] tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), bytes([LEAF_VERSION_TAPSCRIPT]) + self._internal_key] + else: + assert False tx_hex = tx.serialize().hex() assert_equal(tx.get_vsize(), vsize) @@ -286,10 +291,10 @@ class MiniWallet: return txid -def getnewdestination(address_type='bech32'): +def getnewdestination(address_type='bech32m'): """Generate a random destination of the specified type and return the corresponding public key, scriptPubKey and address. Supported types are - 'legacy', 'p2sh-segwit' and 'bech32'. Can be used when a random + 'legacy', 'p2sh-segwit', 'bech32' and 'bech32m'. Can be used when a random destination is needed, but no compiled wallet is available (e.g. as replacement to the getnewaddress/getaddressinfo RPCs).""" key = ECKey() @@ -304,7 +309,11 @@ def getnewdestination(address_type='bech32'): elif address_type == 'bech32': scriptpubkey = key_to_p2wpkh_script(pubkey) address = key_to_p2wpkh(pubkey) - # TODO: also support bech32m (need to generate x-only-pubkey) + elif address_type == 'bech32m': + tap = taproot_construct(compute_xonly_pubkey(key.get_bytes())[0]) + pubkey = tap.output_pubkey + scriptpubkey = tap.scriptPubKey + address = output_key_to_p2tr(pubkey) else: assert False return pubkey, scriptpubkey, address |