@ -9,6 +9,7 @@ from itertools import product
from test_framework . authproxy import JSONRPCException
from test_framework . descriptors import descsum_create
from test_framework . key import ECKey
from test_framework . test_framework import BitcoinTestFramework
from test_framework . util import (
assert_equal ,
@ -16,6 +17,7 @@ from test_framework.util import (
assert_greater_than ,
assert_raises_rpc_error ,
)
from test_framework . wallet_util import bytes_to_wif
class WalletSendTest ( BitcoinTestFramework ) :
def set_test_params ( self ) :
@ -35,7 +37,7 @@ class WalletSendTest(BitcoinTestFramework):
conf_target = None , estimate_mode = None , fee_rate = None , add_to_wallet = None , psbt = None ,
inputs = None , add_inputs = None , include_unsafe = None , change_address = None , change_position = None , change_type = None ,
include_watching = None , locktime = None , lock_unspents = None , replaceable = None , subtract_fee_from_outputs = None ,
expect_error = None ):
expect_error = None , solving_data = None ):
assert ( amount is None ) != ( data is None )
from_balance_before = from_wallet . getbalances ( ) [ " mine " ] [ " trusted " ]
@ -94,6 +96,8 @@ class WalletSendTest(BitcoinTestFramework):
options [ " replaceable " ] = replaceable
if subtract_fee_from_outputs is not None :
options [ " subtract_fee_from_outputs " ] = subtract_fee_from_outputs
if solving_data is not None :
options [ " solving_data " ] = solving_data
if len ( options . keys ( ) ) == 0 :
options = None
@ -476,6 +480,46 @@ class WalletSendTest(BitcoinTestFramework):
res = self . test_send ( from_wallet = w5 , to_wallet = w0 , amount = 1 , include_unsafe = True )
assert res [ " complete " ]
self . log . info ( " External outputs " )
eckey = ECKey ( )
eckey . generate ( )
privkey = bytes_to_wif ( eckey . get_bytes ( ) )
self . nodes [ 1 ] . createwallet ( " extsend " )
ext_wallet = self . nodes [ 1 ] . get_wallet_rpc ( " extsend " )
self . nodes [ 1 ] . createwallet ( " extfund " )
ext_fund = self . nodes [ 1 ] . get_wallet_rpc ( " extfund " )
# Make a weird but signable script. sh(pkh()) descriptor accomplishes this
desc = descsum_create ( " sh(pkh( {} )) " . format ( privkey ) )
if self . options . descriptors :
res = ext_fund . importdescriptors ( [ { " desc " : desc , " timestamp " : " now " } ] )
else :
res = ext_fund . importmulti ( [ { " desc " : desc , " timestamp " : " now " } ] )
assert res [ 0 ] [ " success " ]
addr = self . nodes [ 0 ] . deriveaddresses ( desc ) [ 0 ]
addr_info = ext_fund . getaddressinfo ( addr )
self . nodes [ 0 ] . sendtoaddress ( addr , 10 )
self . nodes [ 0 ] . sendtoaddress ( ext_wallet . getnewaddress ( ) , 10 )
self . nodes [ 0 ] . generate ( 6 )
ext_utxo = ext_fund . listunspent ( addresses = [ addr ] ) [ 0 ]
# An external input without solving data should result in an error
self . test_send ( from_wallet = ext_wallet , to_wallet = self . nodes [ 0 ] , amount = 15 , inputs = [ ext_utxo ] , add_inputs = True , psbt = True , include_watching = True , expect_error = ( - 4 , " Insufficient funds " ) )
# But funding should work when the solving data is provided
res = self . test_send ( from_wallet = ext_wallet , to_wallet = self . nodes [ 0 ] , amount = 15 , inputs = [ ext_utxo ] , add_inputs = True , psbt = True , include_watching = True , solving_data = { " pubkeys " : [ addr_info [ ' pubkey ' ] ] , " scripts " : [ addr_info [ " embedded " ] [ " scriptPubKey " ] ] } )
signed = ext_wallet . walletprocesspsbt ( res [ " psbt " ] )
signed = ext_fund . walletprocesspsbt ( res [ " psbt " ] )
assert signed [ " complete " ]
self . nodes [ 0 ] . finalizepsbt ( signed [ " psbt " ] )
res = self . test_send ( from_wallet = ext_wallet , to_wallet = self . nodes [ 0 ] , amount = 15 , inputs = [ ext_utxo ] , add_inputs = True , psbt = True , include_watching = True , solving_data = { " descriptors " : [ desc ] } )
signed = ext_wallet . walletprocesspsbt ( res [ " psbt " ] )
signed = ext_fund . walletprocesspsbt ( res [ " psbt " ] )
assert signed [ " complete " ]
self . nodes [ 0 ] . finalizepsbt ( signed [ " psbt " ] )
if __name__ == ' __main__ ' :
WalletSendTest ( ) . main ( )