2020-08-25 08:56:24 -04:00
#!/usr/bin/env python3
2021-07-28 07:57:16 -04:00
# Copyright (c) 2020-2021 The Bitcoin Core developers
2020-08-25 08:56:24 -04:00
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
""" A limited-functionality wallet, which may replace a real wallet in tests """
2021-08-05 09:01:51 -04:00
from copy import deepcopy
2020-08-25 08:56:24 -04:00
from decimal import Decimal
2021-05-24 09:54:52 -04:00
from enum import Enum
2022-03-17 16:07:47 -03:00
from typing import (
Any ,
2022-05-27 13:40:06 -04:00
List ,
2022-03-17 16:07:47 -03:00
Optional ,
)
2021-12-25 17:31:49 -03:00
from test_framework . address import (
2021-12-25 22:31:11 -03:00
base58_to_byte ,
2021-12-25 17:31:49 -03:00
create_deterministic_address_bcrt1_p2tr_op_true ,
key_to_p2pkh ,
key_to_p2sh_p2wpkh ,
key_to_p2wpkh ,
2022-06-06 19:47:54 -04:00
output_key_to_p2tr ,
2021-12-25 17:31:49 -03:00
)
2021-10-06 09:55:00 -03:00
from test_framework . descriptors import descsum_create
2022-06-06 19:47:54 -04:00
from test_framework . key import (
ECKey ,
compute_xonly_pubkey ,
)
2020-08-25 08:56:24 -04:00
from test_framework . messages import (
COIN ,
COutPoint ,
CTransaction ,
CTxIn ,
CTxInWitness ,
CTxOut ,
)
from test_framework . script import (
CScript ,
2021-05-13 12:56:38 -04:00
LegacySignatureHash ,
2021-10-27 06:18:57 -03:00
LEAF_VERSION_TAPSCRIPT ,
2021-04-22 12:04:57 -04:00
OP_NOP ,
2022-08-03 06:10:52 -04:00
OP_RETURN ,
2021-10-27 06:18:57 -03:00
OP_TRUE ,
2021-05-13 12:56:38 -04:00
SIGHASH_ALL ,
2022-06-06 19:47:54 -04:00
taproot_construct ,
2020-08-25 08:56:24 -04:00
)
2021-09-28 08:37:46 -03:00
from test_framework . script_util import (
key_to_p2pk_script ,
2021-12-25 17:31:49 -03:00
key_to_p2pkh_script ,
key_to_p2sh_p2wpkh_script ,
2021-09-28 08:37:46 -03:00
key_to_p2wpkh_script ,
2021-12-25 22:31:11 -03:00
keyhash_to_p2pkh_script ,
scripthash_to_p2sh_script ,
2021-09-28 08:37:46 -03:00
)
2020-08-25 08:56:24 -04:00
from test_framework . util import (
assert_equal ,
2021-08-05 09:01:51 -04:00
assert_greater_than_or_equal ,
2020-08-25 08:56:24 -04:00
)
2021-08-05 10:30:25 -04:00
DEFAULT_FEE = Decimal ( " 0.0001 " )
2020-08-25 08:56:24 -04:00
2021-05-24 09:54:52 -04:00
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 ;
2021-10-27 06:18:57 -03:00
it simply uses a fixed bech32m P2TR address whose coins are spent with a
2021-05-24 09:54:52 -04:00
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
should contain an actual signature , the raw modes RAW_OP_TRUE and RAW_P2PK
can be useful . Summary of modes :
| output | | tx is | can modify | needs
mode | description | address | standard | scriptSig | signing
- - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - + - - - - - - - - - - + - - - - - - - - - - - - + - - - - - - - - - -
2021-10-27 06:18:57 -03:00
ADDRESS_OP_TRUE | anyone - can - spend | bech32m | yes | no | no
2021-05-24 09:54:52 -04:00
RAW_OP_TRUE | anyone - can - spend | - ( raw ) | no | yes | no
RAW_P2PK | pay - to - public - key | - ( raw ) | yes | yes | yes
"""
ADDRESS_OP_TRUE = 1
RAW_OP_TRUE = 2
RAW_P2PK = 3
2020-08-25 08:56:24 -04:00
class MiniWallet :
2021-05-24 09:54:52 -04:00
def __init__ ( self , test_node , * , mode = MiniWalletMode . ADDRESS_OP_TRUE ) :
2020-08-25 08:56:24 -04:00
self . _test_node = test_node
self . _utxos = [ ]
2022-06-20 11:34:55 -04:00
self . _mode = mode
2021-05-13 12:56:38 -04:00
2021-05-24 09:54:52 -04:00
assert isinstance ( mode , MiniWalletMode )
if mode == MiniWalletMode . RAW_OP_TRUE :
2021-04-22 12:04:57 -04:00
self . _scriptPubKey = bytes ( CScript ( [ OP_TRUE ] ) )
2021-05-24 09:54:52 -04:00
elif mode == MiniWalletMode . RAW_P2PK :
2021-05-13 12:56:38 -04:00
# use simple deterministic private key (k=1)
self . _priv_key = ECKey ( )
self . _priv_key . set ( ( 1 ) . to_bytes ( 32 , ' big ' ) , True )
pub_key = self . _priv_key . get_pubkey ( )
2021-09-28 08:37:46 -03:00
self . _scriptPubKey = key_to_p2pk_script ( pub_key . get_bytes ( ) )
2021-05-24 09:54:52 -04:00
elif mode == MiniWalletMode . ADDRESS_OP_TRUE :
2021-10-27 06:18:57 -03:00
self . _address , self . _internal_key = create_deterministic_address_bcrt1_p2tr_op_true ( )
2021-07-31 15:23:16 -04:00
self . _scriptPubKey = bytes . fromhex ( self . _test_node . validateaddress ( self . _address ) [ ' scriptPubKey ' ] )
2020-08-25 08:56:24 -04:00
2022-06-22 04:50:47 -04:00
def _create_utxo ( self , * , txid , vout , value , height ) :
return { " txid " : txid , " vout " : vout , " value " : value , " height " : height }
2022-06-15 08:43:56 -04:00
def _bulk_tx ( self , tx , target_weight ) :
""" Pad a transaction with extra outputs until it reaches a target weight (or higher).
returns the tx
"""
2022-08-03 06:10:52 -04:00
tx . vout . append ( CTxOut ( nValue = 0 , scriptPubKey = CScript ( [ OP_RETURN , b ' a ' ] ) ) )
dummy_vbytes = ( target_weight - tx . get_weight ( ) + 3 ) / / 4
tx . vout [ - 1 ] . scriptPubKey = CScript ( [ OP_RETURN , b ' a ' * dummy_vbytes ] )
# Lower bound should always be off by at most 3
assert_greater_than_or_equal ( tx . get_weight ( ) , target_weight )
# Higher bound should always be off by at most 3 + 12 weight (for encoding the length)
assert_greater_than_or_equal ( target_weight + 15 , tx . get_weight ( ) )
2022-06-15 08:43:56 -04:00
2022-03-22 05:47:51 -03:00
def get_balance ( self ) :
return sum ( u [ ' value ' ] for u in self . _utxos )
2021-09-12 06:03:56 -03:00
def rescan_utxos ( self ) :
""" Drop all utxos and rescan the utxo set """
self . _utxos = [ ]
2021-09-20 10:22:15 -03:00
res = self . _test_node . scantxoutset ( action = " start " , scanobjects = [ self . get_descriptor ( ) ] )
2021-09-12 06:03:56 -03:00
assert_equal ( True , res [ ' success ' ] )
for utxo in res [ ' unspents ' ] :
2022-06-22 04:50:47 -04:00
self . _utxos . append ( self . _create_utxo ( txid = utxo [ " txid " ] , vout = utxo [ " vout " ] , value = utxo [ " amount " ] , height = utxo [ " height " ] ) )
2021-09-12 06:03:56 -03:00
2021-04-22 07:34:26 -04:00
def scan_tx ( self , tx ) :
2022-06-23 06:24:51 -04:00
""" Scan the tx and adjust the internal list of owned utxos """
for spent in tx [ " vin " ] :
# Mark spent. This may happen when the caller has ownership of a
# utxo that remained in this wallet. For example, by passing
# mark_as_spent=False to get_utxo or by using an utxo returned by a
# create_self_transfer* call.
try :
self . get_utxo ( txid = spent [ " txid " ] , vout = spent [ " vout " ] )
except StopIteration :
pass
2021-04-22 07:34:26 -04:00
for out in tx [ ' vout ' ] :
if out [ ' scriptPubKey ' ] [ ' hex ' ] == self . _scriptPubKey . hex ( ) :
2022-06-22 04:50:47 -04:00
self . _utxos . append ( self . _create_utxo ( txid = tx [ " txid " ] , vout = out [ " n " ] , value = out [ " value " ] , height = 0 ) )
2021-02-16 13:48:01 -03:00
2021-05-27 12:09:07 -04:00
def sign_tx ( self , tx , fixed_length = True ) :
2021-05-13 12:56:38 -04:00
""" Sign tx that has been created by MiniWallet in P2PK mode """
2022-06-20 11:34:55 -04:00
assert_equal ( self . _mode , MiniWalletMode . RAW_P2PK )
2021-05-13 12:56:38 -04:00
( sighash , err ) = LegacySignatureHash ( CScript ( self . _scriptPubKey ) , tx , 0 , SIGHASH_ALL )
assert err is None
2021-05-27 12:09:07 -04:00
# for exact fee calculation, create only signatures with fixed size by default (>49.89% probability):
# 65 bytes: high-R val (33 bytes) + low-S val (32 bytes)
# with the DER header/skeleton data of 6 bytes added, this leads to a target size of 71 bytes
der_sig = b ' '
while not len ( der_sig ) == 71 :
der_sig = self . _priv_key . sign_ecdsa ( sighash )
if not fixed_length :
break
tx . vin [ 0 ] . scriptSig = CScript ( [ der_sig + bytes ( bytearray ( [ SIGHASH_ALL ] ) ) ] )
2022-04-22 08:50:54 -04:00
tx . rehash ( )
2021-05-13 12:56:38 -04:00
2021-07-27 07:59:55 -04:00
def generate ( self , num_blocks , * * kwargs ) :
2022-06-23 06:23:42 -04:00
""" Generate blocks with coinbase outputs to the internal address, and call rescan_utxos """
2021-07-27 07:59:55 -04:00
blocks = self . _test_node . generatetodescriptor ( num_blocks , self . get_descriptor ( ) , * * kwargs )
2022-06-23 06:23:42 -04:00
# Calling rescan_utxos here makes sure that after a generate the utxo
# set is in a clean state. For example, the wallet will update
# - if the caller consumed utxos, but never used them
# - if the caller sent a transaction that is not mined or got rbf'd
# - after block re-orgs
# - the utxo height for mined mempool txs
# - However, the wallet will not consider remaining mempool txs
self . rescan_utxos ( )
2020-08-25 08:56:24 -04:00
return blocks
2022-03-17 15:54:45 -03:00
def get_scriptPubKey ( self ) :
return self . _scriptPubKey
2021-09-20 10:22:15 -03:00
def get_descriptor ( self ) :
2021-10-06 09:55:00 -03:00
return descsum_create ( f ' raw( { self . _scriptPubKey . hex ( ) } ) ' )
2021-09-20 10:22:15 -03:00
2021-02-22 20:16:50 -03:00
def get_address ( self ) :
2022-06-20 11:34:55 -04:00
assert_equal ( self . _mode , MiniWalletMode . ADDRESS_OP_TRUE )
2021-02-22 20:16:50 -03:00
return self . _address
2022-05-27 13:40:06 -04:00
def get_utxo ( self , * , txid : str = ' ' , vout : Optional [ int ] = None , mark_as_spent = True ) - > dict :
2020-11-13 19:55:20 -03:00
"""
Returns a utxo and marks it as spent ( pops it from the internal list )
Args :
2021-05-28 01:21:14 -04:00
txid : get the first utxo we find from a specific transaction
2020-11-13 19:55:20 -03:00
"""
2021-11-15 09:19:58 -03:00
self . _utxos = sorted ( self . _utxos , key = lambda k : ( k [ ' value ' ] , - k [ ' height ' ] ) ) # Put the largest utxo last
2020-11-13 19:55:20 -03:00
if txid :
2022-03-17 16:07:47 -03:00
utxo_filter : Any = filter ( lambda utxo : txid == utxo [ ' txid ' ] , self . _utxos )
else :
utxo_filter = reversed ( self . _utxos ) # By default the largest utxo
2022-03-17 15:54:45 -03:00
if vout is not None :
utxo_filter = filter ( lambda utxo : vout == utxo [ ' vout ' ] , utxo_filter )
2022-03-17 16:07:47 -03:00
index = self . _utxos . index ( next ( utxo_filter ) )
2021-05-09 17:22:27 -04:00
if mark_as_spent :
return self . _utxos . pop ( index )
else :
return self . _utxos [ index ]
2020-09-09 05:38:19 -03:00
2022-05-08 18:38:17 -04:00
def get_utxos ( self , * , mark_as_spent = True ) :
""" Returns the list of all utxos and optionally mark them as spent """
utxos = deepcopy ( self . _utxos )
if mark_as_spent :
self . _utxos = [ ]
return utxos
2022-06-21 05:25:54 -04:00
def send_self_transfer ( self , * , from_node , * * kwargs ) :
2022-07-01 06:07:55 -04:00
""" Call create_self_transfer and send the transaction. """
2021-06-10 06:57:15 -04:00
tx = self . create_self_transfer ( * * kwargs )
2022-06-21 05:25:54 -04:00
self . sendrawtransaction ( from_node = from_node , tx_hex = tx [ ' hex ' ] )
2021-04-22 07:44:05 -04:00
return tx
2021-09-23 20:01:52 -03:00
def send_to ( self , * , from_node , scriptPubKey , amount , fee = 1000 ) :
"""
Create and send a tx with an output to a given scriptPubKey / amount ,
plus a change output to our internal address . To keep things simple , a
fixed fee given in Satoshi is used .
Note that this method fails if there is no single internal utxo
available that can cover the cost for the amount and the fixed fee
( the utxo with the largest value is taken ) .
Returns a tuple ( txid , n ) referring to the created external utxo outpoint .
"""
2022-06-21 05:25:54 -04:00
tx = self . create_self_transfer ( fee_rate = 0 ) [ " tx " ]
2021-09-23 20:01:52 -03:00
assert_greater_than_or_equal ( tx . vout [ 0 ] . nValue , amount + fee )
tx . vout [ 0 ] . nValue - = ( amount + fee ) # change output -> MiniWallet
tx . vout . append ( CTxOut ( amount , scriptPubKey ) ) # arbitrary output -> to be returned
txid = self . sendrawtransaction ( from_node = from_node , tx_hex = tx . serialize ( ) . hex ( ) )
return txid , 1
2022-06-21 05:25:54 -04:00
def send_self_transfer_multi ( self , * , from_node , * * kwargs ) :
2022-06-23 04:50:29 -04:00
""" Call create_self_transfer_multi and send the transaction. """
2022-03-21 20:34:55 -03:00
tx = self . create_self_transfer_multi ( * * kwargs )
2022-06-23 04:50:29 -04:00
self . sendrawtransaction ( from_node = from_node , tx_hex = tx [ " hex " ] )
return tx
2022-03-21 20:34:55 -03:00
2022-05-27 13:40:06 -04:00
def create_self_transfer_multi (
2022-06-21 05:25:54 -04:00
self ,
* ,
utxos_to_spend : Optional [ List [ dict ] ] = None ,
num_outputs = 1 ,
2022-07-01 06:09:56 -04:00
amount_per_output = 0 ,
2022-10-28 10:19:55 -03:00
locktime = 0 ,
2022-06-21 05:25:54 -04:00
sequence = 0 ,
fee_per_output = 1000 ,
2022-06-15 08:43:56 -04:00
target_weight = 0
2022-06-21 05:25:54 -04:00
) :
2022-03-21 20:34:55 -03:00
"""
Create and return a transaction that spends the given UTXOs and creates a
2022-07-01 06:09:56 -04:00
certain number of outputs with equal amounts . The output amounts can be
set by amount_per_output or automatically calculated with a fee_per_output .
2022-03-21 20:34:55 -03:00
"""
2022-03-24 10:33:52 -03:00
utxos_to_spend = utxos_to_spend or [ self . get_utxo ( ) ]
2022-07-01 06:27:59 -04:00
sequence = [ sequence ] * len ( utxos_to_spend ) if type ( sequence ) is int else sequence
assert_equal ( len ( utxos_to_spend ) , len ( sequence ) )
2022-10-28 10:19:55 -03:00
# calculate output amount
2022-03-21 20:34:55 -03:00
inputs_value_total = sum ( [ int ( COIN * utxo [ ' value ' ] ) for utxo in utxos_to_spend ] )
outputs_value_total = inputs_value_total - fee_per_output * num_outputs
2022-10-28 10:19:55 -03:00
amount_per_output = amount_per_output or ( outputs_value_total / / num_outputs )
# create tx
tx = CTransaction ( )
tx . vin = [ CTxIn ( COutPoint ( int ( utxo_to_spend [ ' txid ' ] , 16 ) , utxo_to_spend [ ' vout ' ] ) , nSequence = seq ) for utxo_to_spend , seq in zip ( utxos_to_spend , sequence ) ]
tx . vout = [ CTxOut ( amount_per_output , bytearray ( self . _scriptPubKey ) ) for _ in range ( num_outputs ) ]
tx . nLockTime = locktime
if self . _mode == MiniWalletMode . RAW_P2PK :
self . sign_tx ( tx )
elif self . _mode == MiniWalletMode . RAW_OP_TRUE :
for i in range ( len ( utxos_to_spend ) ) :
tx . vin [ i ] . scriptSig = CScript ( [ OP_NOP ] * 43 ) # pad to identical size
elif self . _mode == MiniWalletMode . ADDRESS_OP_TRUE :
tx . wit . vtxinwit = [ CTxInWitness ( ) ] * len ( utxos_to_spend )
for i in range ( len ( utxos_to_spend ) ) :
tx . wit . vtxinwit [ i ] . scriptWitness . stack = [ CScript ( [ OP_TRUE ] ) , bytes ( [ LEAF_VERSION_TAPSCRIPT ] ) + self . _internal_key ]
else :
assert False
2022-06-15 08:43:56 -04:00
if target_weight :
self . _bulk_tx ( tx , target_weight )
2022-06-23 04:50:29 -04:00
txid = tx . rehash ( )
return {
" new_utxos " : [ self . _create_utxo (
txid = txid ,
vout = i ,
value = Decimal ( tx . vout [ i ] . nValue ) / COIN ,
height = 0 ,
) for i in range ( len ( tx . vout ) ) ] ,
" txid " : txid ,
" hex " : tx . serialize ( ) . hex ( ) ,
" tx " : tx ,
}
2022-03-21 20:34:55 -03:00
2022-06-15 08:43:56 -04:00
def create_self_transfer ( self , * , fee_rate = Decimal ( " 0.003 " ) , fee = Decimal ( " 0 " ) , utxo_to_spend = None , locktime = 0 , sequence = 0 , target_weight = 0 ) :
2022-07-01 06:07:55 -04:00
""" 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. """
2021-11-15 09:19:58 -03:00
utxo_to_spend = utxo_to_spend or self . get_utxo ( )
2022-07-01 06:07:55 -04:00
assert fee_rate > = 0
assert fee > = 0
2022-10-28 10:19:55 -03:00
# calculate fee
2022-06-20 11:34:55 -04:00
if self . _mode in ( MiniWalletMode . RAW_OP_TRUE , MiniWalletMode . ADDRESS_OP_TRUE ) :
2021-10-27 06:18:57 -03:00
vsize = Decimal ( 104 ) # anyone-can-spend
2022-06-20 11:34:55 -04:00
elif self . _mode == MiniWalletMode . RAW_P2PK :
2021-05-27 14:15:02 -04:00
vsize = Decimal ( 168 ) # P2PK (73 bytes scriptSig + 35 bytes scriptPubKey + 60 bytes other)
2022-06-20 11:34:55 -04:00
else :
assert False
2022-07-01 06:07:55 -04:00
send_value = utxo_to_spend [ " value " ] - ( fee or ( fee_rate * vsize / 1000 ) )
2020-09-09 05:07:05 -03:00
assert send_value > 0
2020-08-25 08:56:24 -04:00
2022-10-28 10:19:55 -03:00
# create tx
tx = self . create_self_transfer_multi ( utxos_to_spend = [ utxo_to_spend ] , locktime = locktime , sequence = sequence , amount_per_output = int ( COIN * send_value ) , target_weight = target_weight )
if not target_weight :
assert_equal ( tx [ " tx " ] . get_vsize ( ) , vsize )
2022-04-21 20:48:38 -04:00
2022-10-28 10:19:55 -03:00
return { " txid " : tx [ " txid " ] , " wtxid " : tx [ " tx " ] . getwtxid ( ) , " hex " : tx [ " hex " ] , " tx " : tx [ " tx " ] , " new_utxo " : tx [ " new_utxos " ] [ 0 ] }
2021-04-22 07:34:26 -04:00
2022-06-01 11:05:13 -04:00
def sendrawtransaction ( self , * , from_node , tx_hex , maxfeerate = 0 , * * kwargs ) :
txid = from_node . sendrawtransaction ( hexstring = tx_hex , maxfeerate = maxfeerate , * * kwargs )
2021-04-22 07:34:26 -04:00
self . scan_tx ( from_node . decoderawtransaction ( tx_hex ) )
2021-09-16 09:42:50 -03:00
return txid
2022-09-02 11:54:26 -04:00
def create_self_transfer_chain ( self , * , chain_length ) :
"""
Create a " chain " of chain_length transactions . The nth transaction in
the chain is a child of the n - 1 th transaction and parent of the n + 1 th transaction .
Returns a dic { " chain_hex " : chain_hex , " chain_txns " : chain_txns }
" chain_hex " is a list representing the chain ' s transactions in hexadecimal.
" chain_txns " is a list representing the chain ' s transactions in the CTransaction object.
"""
chaintip_utxo = self . get_utxo ( )
chain_hex = [ ]
chain_txns = [ ]
for _ in range ( chain_length ) :
tx = self . create_self_transfer ( utxo_to_spend = chaintip_utxo )
chaintip_utxo = tx [ " new_utxo " ]
chain_hex . append ( tx [ " hex " ] )
chain_txns . append ( tx [ " tx " ] )
return { " chain_hex " : chain_hex , " chain_txns " : chain_txns }
2022-06-28 07:23:45 -04:00
def send_self_transfer_chain ( self , * , from_node , chain_length , utxo_to_spend = None ) :
""" Create and send a " chain " of chain_length transactions. The nth transaction in
the chain is a child of the n - 1 th transaction and parent of the n + 1 th transaction .
Returns the chaintip ( nth ) utxo
"""
chaintip_utxo = utxo_to_spend or self . get_utxo ( )
for _ in range ( chain_length ) :
chaintip_utxo = self . send_self_transfer ( utxo_to_spend = chaintip_utxo , from_node = from_node ) [ " new_utxo " ]
return chaintip_utxo
2022-06-06 19:47:54 -04:00
def getnewdestination ( address_type = ' bech32m ' ) :
2021-12-25 17:31:49 -03:00
""" Generate a random destination of the specified type and return the
corresponding public key , scriptPubKey and address . Supported types are
2022-06-06 19:47:54 -04:00
' legacy ' , ' p2sh-segwit ' , ' bech32 ' and ' bech32m ' . Can be used when a random
2021-12-25 17:31:49 -03:00
destination is needed , but no compiled wallet is available ( e . g . as
replacement to the getnewaddress / getaddressinfo RPCs ) . """
2021-09-24 12:26:27 -03:00
key = ECKey ( )
key . generate ( )
2021-12-25 17:31:49 -03:00
pubkey = key . get_pubkey ( ) . get_bytes ( )
if address_type == ' legacy ' :
scriptpubkey = key_to_p2pkh_script ( pubkey )
address = key_to_p2pkh ( pubkey )
elif address_type == ' p2sh-segwit ' :
scriptpubkey = key_to_p2sh_p2wpkh_script ( pubkey )
address = key_to_p2sh_p2wpkh ( pubkey )
elif address_type == ' bech32 ' :
scriptpubkey = key_to_p2wpkh_script ( pubkey )
address = key_to_p2wpkh ( pubkey )
2022-06-06 19:47:54 -04:00
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 )
2021-12-25 17:31:49 -03:00
else :
assert False
return pubkey , scriptpubkey , address
2021-09-24 12:26:27 -03:00
2021-12-25 22:31:11 -03:00
def address_to_scriptpubkey ( address ) :
""" Converts a given address to the corresponding output script (scriptPubKey). """
payload , version = base58_to_byte ( address )
if version == 111 : # testnet pubkey hash
return keyhash_to_p2pkh_script ( payload )
elif version == 196 : # testnet script hash
return scripthash_to_p2sh_script ( payload )
# TODO: also support other address formats
else :
assert False