2016-03-19 16:58:06 -03:00
#!/usr/bin/env python3
2020-04-16 13:14:08 -04:00
# Copyright (c) 2014-2020 The Bitcoin Core developers
2015-04-24 22:26:30 -03:00
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-01-17 20:34:40 -03:00
""" Test the fundrawtransaction RPC. """
2015-04-24 22:26:30 -03:00
2018-01-25 07:03:05 -03:00
from decimal import Decimal
2017-08-16 12:52:24 -03:00
from test_framework . test_framework import BitcoinTestFramework
2018-01-25 07:03:05 -03:00
from test_framework . util import (
assert_equal ,
assert_fee_amount ,
assert_greater_than ,
assert_greater_than_or_equal ,
assert_raises_rpc_error ,
2019-08-27 15:13:56 -04:00
connect_nodes ,
2018-01-25 07:03:05 -03:00
count_bytes ,
find_vout_for_address ,
)
2015-04-24 22:26:30 -03:00
2016-04-16 13:36:39 -03:00
def get_unspent ( listunspent , amount ) :
for utx in listunspent :
if utx [ ' amount ' ] == amount :
return utx
raise AssertionError ( ' Could not find unspent with amount= {} ' . format ( amount ) )
2015-04-24 22:26:30 -03:00
class RawTransactionsTest ( BitcoinTestFramework ) :
2017-06-09 18:21:21 -04:00
def set_test_params ( self ) :
2016-05-14 08:01:31 -03:00
self . num_nodes = 4
self . setup_clean_chain = True
2019-11-01 18:38:19 -03:00
# This test isn't testing tx relay. Set whitelist on the peers for
# instant tx relay.
2020-02-25 13:38:56 -03:00
self . extra_args = [ [ ' -whitelist=noban@127.0.0.1 ' ] ] * self . num_nodes
2015-04-24 22:26:30 -03:00
2018-09-09 14:32:37 -03:00
def skip_test_if_missing_module ( self ) :
self . skip_if_no_wallet ( )
2018-12-22 13:19:50 -03:00
def setup_network ( self ) :
2017-04-03 10:34:04 -03:00
self . setup_nodes ( )
2015-04-24 22:26:30 -03:00
2019-08-27 15:13:56 -04:00
connect_nodes ( self . nodes [ 0 ] , 1 )
connect_nodes ( self . nodes [ 1 ] , 2 )
connect_nodes ( self . nodes [ 0 ] , 2 )
connect_nodes ( self . nodes [ 0 ] , 3 )
2015-04-24 22:26:30 -03:00
def run_test ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Connect nodes, set fees, generate blocks, and sync " )
2019-06-26 12:42:11 -04:00
self . min_relay_tx_fee = self . nodes [ 0 ] . getnetworkinfo ( ) [ ' relayfee ' ]
2016-01-05 19:47:04 -03:00
# This test is not meant to test fee estimation and we'd like
# to be sure all txs are sent at a consistent desired feerate
for node in self . nodes :
2019-06-26 12:42:11 -04:00
node . settxfee ( self . min_relay_tx_fee )
2016-01-05 19:47:04 -03:00
2015-10-14 09:27:03 -03:00
# if the fee's positive delta is higher than this value tests will fail,
# neg. delta always fail the tests.
# The size of the signature of every input may be at most 2 bytes larger
# than a minimum sized signature.
# = 2 bytes * minRelayTxFeePerByte
2019-06-26 12:42:11 -04:00
self . fee_tolerance = 2 * self . min_relay_tx_fee / 1000
2015-04-24 22:26:30 -03:00
self . nodes [ 2 ] . generate ( 1 )
2015-07-10 15:11:44 -03:00
self . sync_all ( )
2015-04-24 01:42:49 -03:00
self . nodes [ 0 ] . generate ( 121 )
2015-04-24 22:26:30 -03:00
self . sync_all ( )
2015-04-24 01:42:49 -03:00
2019-06-26 13:49:11 -04:00
self . test_change_position ( )
self . test_simple ( )
self . test_simple_two_coins ( )
self . test_simple_two_outputs ( )
self . test_change ( )
self . test_no_change ( )
self . test_invalid_option ( )
self . test_invalid_change_address ( )
self . test_valid_change_address ( )
self . test_change_type ( )
self . test_coin_selection ( )
self . test_two_vin ( )
self . test_two_vin_two_vout ( )
self . test_invalid_input ( )
self . test_fee_p2pkh ( )
self . test_fee_p2pkh_multi_out ( )
self . test_fee_p2sh ( )
self . test_fee_4of5 ( )
self . test_spend_2of2 ( )
self . test_locked_wallet ( )
self . test_many_inputs_fee ( )
self . test_many_inputs_send ( )
self . test_op_return ( )
self . test_watchonly ( )
self . test_all_watched_funds ( )
self . test_option_feerate ( )
self . test_address_reuse ( )
self . test_option_subtract_fee_from_outputs ( )
2019-11-23 00:21:36 -03:00
self . test_subtract_fee_with_presets ( )
2019-06-26 13:49:11 -04:00
def test_change_position ( self ) :
2019-11-01 07:51:49 -03:00
""" Ensure setting changePosition in fundraw with an exact match is handled properly. """
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn changePosition option " )
2017-04-28 18:22:37 -03:00
rawmatch = self . nodes [ 2 ] . createrawtransaction ( [ ] , { self . nodes [ 2 ] . getnewaddress ( ) : 50 } )
rawmatch = self . nodes [ 2 ] . fundrawtransaction ( rawmatch , { " changePosition " : 1 , " subtractFeeFromOutputs " : [ 0 ] } )
assert_equal ( rawmatch [ " changepos " ] , - 1 )
2015-04-24 01:42:49 -03:00
watchonly_address = self . nodes [ 0 ] . getnewaddress ( )
2018-02-09 13:12:27 -03:00
watchonly_pubkey = self . nodes [ 0 ] . getaddressinfo ( watchonly_address ) [ " pubkey " ]
2019-06-26 12:42:11 -04:00
self . watchonly_amount = Decimal ( 200 )
2015-04-24 01:42:49 -03:00
self . nodes [ 3 ] . importpubkey ( watchonly_pubkey , " " , True )
2019-06-26 12:42:11 -04:00
self . watchonly_txid = self . nodes [ 0 ] . sendtoaddress ( watchonly_address , self . watchonly_amount )
2018-01-25 07:03:05 -03:00
# Lock UTXO so nodes[0] doesn't accidentally spend it
2019-06-26 12:42:11 -04:00
self . watchonly_vout = find_vout_for_address ( self . nodes [ 0 ] , self . watchonly_txid , watchonly_address )
self . nodes [ 0 ] . lockunspent ( False , [ { " txid " : self . watchonly_txid , " vout " : self . watchonly_vout } ] )
2018-01-25 07:03:05 -03:00
2019-06-26 12:42:11 -04:00
self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 3 ] . getnewaddress ( ) , self . watchonly_amount / 10 )
2015-04-24 01:42:49 -03:00
2015-12-02 14:12:23 -03:00
self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 2 ] . getnewaddress ( ) , 1.5 )
self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 2 ] . getnewaddress ( ) , 1.0 )
self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 2 ] . getnewaddress ( ) , 5.0 )
2015-04-24 01:42:49 -03:00
2015-04-24 22:26:30 -03:00
self . nodes [ 0 ] . generate ( 1 )
self . sync_all ( )
2019-06-26 13:49:11 -04:00
def test_simple ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn " )
2015-04-24 22:26:30 -03:00
inputs = [ ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 1.0 }
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtx )
rawtxfund = self . nodes [ 2 ] . fundrawtransaction ( rawtx )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtxfund [ ' hex ' ] )
2019-02-19 19:43:44 -03:00
assert len ( dec_tx [ ' vin ' ] ) > 0 #test that we have enough inputs
2015-04-24 22:26:30 -03:00
2019-06-26 13:49:11 -04:00
def test_simple_two_coins ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn with 2 coins " )
2015-04-24 22:26:30 -03:00
inputs = [ ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 2.2 }
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtx )
rawtxfund = self . nodes [ 2 ] . fundrawtransaction ( rawtx )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtxfund [ ' hex ' ] )
2019-02-19 19:43:44 -03:00
assert len ( dec_tx [ ' vin ' ] ) > 0 #test if we have enough inputs
2015-04-24 22:26:30 -03:00
assert_equal ( dec_tx [ ' vin ' ] [ 0 ] [ ' scriptSig ' ] [ ' hex ' ] , ' ' )
2019-06-26 13:49:11 -04:00
def test_simple_two_outputs ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn with 2 outputs " )
2015-04-24 22:26:30 -03:00
inputs = [ ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 2.6 , self . nodes [ 1 ] . getnewaddress ( ) : 2.5 }
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtx )
rawtxfund = self . nodes [ 2 ] . fundrawtransaction ( rawtx )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtxfund [ ' hex ' ] )
totalOut = 0
for out in dec_tx [ ' vout ' ] :
totalOut + = out [ ' value ' ]
2019-02-19 19:43:44 -03:00
assert len ( dec_tx [ ' vin ' ] ) > 0
2015-04-24 22:26:30 -03:00
assert_equal ( dec_tx [ ' vin ' ] [ 0 ] [ ' scriptSig ' ] [ ' hex ' ] , ' ' )
2019-06-26 13:49:11 -04:00
def test_change ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn with a vin > required amount " )
2016-04-16 13:36:39 -03:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 5 )
2015-04-24 22:26:30 -03:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 1.0 }
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtx )
assert_equal ( utx [ ' txid ' ] , dec_tx [ ' vin ' ] [ 0 ] [ ' txid ' ] )
rawtxfund = self . nodes [ 2 ] . fundrawtransaction ( rawtx )
fee = rawtxfund [ ' fee ' ]
2019-06-26 12:42:11 -04:00
self . test_no_change_fee = fee # Use the same fee for the next tx
2015-04-24 22:26:30 -03:00
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtxfund [ ' hex ' ] )
totalOut = 0
for out in dec_tx [ ' vout ' ] :
totalOut + = out [ ' value ' ]
assert_equal ( fee + totalOut , utx [ ' amount ' ] ) #compare vin total and totalout+fee
2019-06-26 13:49:11 -04:00
def test_no_change ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn not having a change output " )
2016-04-16 13:36:39 -03:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 5 )
2015-04-24 22:26:30 -03:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } ]
2019-06-26 12:42:11 -04:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : Decimal ( 5.0 ) - self . test_no_change_fee - self . fee_tolerance }
2015-04-24 22:26:30 -03:00
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtx )
assert_equal ( utx [ ' txid ' ] , dec_tx [ ' vin ' ] [ 0 ] [ ' txid ' ] )
rawtxfund = self . nodes [ 2 ] . fundrawtransaction ( rawtx )
fee = rawtxfund [ ' fee ' ]
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtxfund [ ' hex ' ] )
totalOut = 0
for out in dec_tx [ ' vout ' ] :
totalOut + = out [ ' value ' ]
assert_equal ( rawtxfund [ ' changepos ' ] , - 1 )
assert_equal ( fee + totalOut , utx [ ' amount ' ] ) #compare vin total and totalout+fee
2019-06-26 13:49:11 -04:00
def test_invalid_option ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn with an invalid option " )
2016-04-16 13:36:39 -03:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 5 )
2016-03-29 22:04:22 -03:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : Decimal ( 4.0 ) }
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtx )
assert_equal ( utx [ ' txid ' ] , dec_tx [ ' vin ' ] [ 0 ] [ ' txid ' ] )
2017-07-12 10:33:46 -04:00
assert_raises_rpc_error ( - 3 , " Unexpected key foo " , self . nodes [ 2 ] . fundrawtransaction , rawtx , { ' foo ' : ' bar ' } )
2016-03-29 22:04:22 -03:00
2018-02-11 00:12:43 -03:00
# reserveChangeKey was deprecated and is now removed
assert_raises_rpc_error ( - 3 , " Unexpected key reserveChangeKey " , lambda : self . nodes [ 2 ] . fundrawtransaction ( hexstring = rawtx , options = { ' reserveChangeKey ' : True } ) )
2019-06-26 13:49:11 -04:00
def test_invalid_change_address ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn with an invalid change address " )
2016-04-16 13:36:39 -03:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 5 )
2016-03-29 22:04:22 -03:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : Decimal ( 4.0 ) }
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtx )
assert_equal ( utx [ ' txid ' ] , dec_tx [ ' vin ' ] [ 0 ] [ ' txid ' ] )
2017-07-12 10:33:46 -04:00
assert_raises_rpc_error ( - 5 , " changeAddress must be a valid bitcoin address " , self . nodes [ 2 ] . fundrawtransaction , rawtx , { ' changeAddress ' : ' foobar ' } )
2016-03-29 22:04:22 -03:00
2019-06-26 13:49:11 -04:00
def test_valid_change_address ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn with a provided change address " )
2016-04-16 13:36:39 -03:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 5 )
2016-03-29 22:04:22 -03:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : Decimal ( 4.0 ) }
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtx )
assert_equal ( utx [ ' txid ' ] , dec_tx [ ' vin ' ] [ 0 ] [ ' txid ' ] )
change = self . nodes [ 2 ] . getnewaddress ( )
2017-07-12 10:33:46 -04:00
assert_raises_rpc_error ( - 8 , " changePosition out of bounds " , self . nodes [ 2 ] . fundrawtransaction , rawtx , { ' changeAddress ' : change , ' changePosition ' : 2 } )
2016-03-29 22:04:22 -03:00
rawtxfund = self . nodes [ 2 ] . fundrawtransaction ( rawtx , { ' changeAddress ' : change , ' changePosition ' : 0 } )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtxfund [ ' hex ' ] )
2017-01-20 18:55:26 -03:00
out = dec_tx [ ' vout ' ] [ 0 ]
2016-03-29 22:04:22 -03:00
assert_equal ( change , out [ ' scriptPubKey ' ] [ ' addresses ' ] [ 0 ] )
2019-06-26 13:49:11 -04:00
def test_change_type ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn with a provided change type " )
2018-01-24 12:28:15 -03:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 5 )
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : Decimal ( 4.0 ) }
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
assert_raises_rpc_error ( - 1 , " JSON value is not a string as expected " , self . nodes [ 2 ] . fundrawtransaction , rawtx , { ' change_type ' : None } )
2018-03-19 16:57:11 -03:00
assert_raises_rpc_error ( - 5 , " Unknown change type ' ' " , self . nodes [ 2 ] . fundrawtransaction , rawtx , { ' change_type ' : ' ' } )
2018-01-24 12:28:15 -03:00
rawtx = self . nodes [ 2 ] . fundrawtransaction ( rawtx , { ' change_type ' : ' bech32 ' } )
2018-01-29 16:25:40 -03:00
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtx [ ' hex ' ] )
assert_equal ( ' witness_v0_keyhash ' , dec_tx [ ' vout ' ] [ rawtx [ ' changepos ' ] ] [ ' scriptPubKey ' ] [ ' type ' ] )
2016-03-29 22:04:22 -03:00
2019-06-26 13:49:11 -04:00
def test_coin_selection ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn with a vin < required amount " )
2016-04-16 13:36:39 -03:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 1 )
2015-04-24 22:26:30 -03:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 1.0 }
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
# 4-byte version + 1-byte vin count + 36-byte prevout then script_len
rawtx = rawtx [ : 82 ] + " 0100 " + rawtx [ 84 : ]
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtx )
assert_equal ( utx [ ' txid ' ] , dec_tx [ ' vin ' ] [ 0 ] [ ' txid ' ] )
assert_equal ( " 00 " , dec_tx [ ' vin ' ] [ 0 ] [ ' scriptSig ' ] [ ' hex ' ] )
rawtxfund = self . nodes [ 2 ] . fundrawtransaction ( rawtx )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtxfund [ ' hex ' ] )
totalOut = 0
matchingOuts = 0
for i , out in enumerate ( dec_tx [ ' vout ' ] ) :
totalOut + = out [ ' value ' ]
2016-03-19 17:36:32 -03:00
if out [ ' scriptPubKey ' ] [ ' addresses ' ] [ 0 ] in outputs :
2015-04-24 22:26:30 -03:00
matchingOuts + = 1
else :
assert_equal ( i , rawtxfund [ ' changepos ' ] )
assert_equal ( utx [ ' txid ' ] , dec_tx [ ' vin ' ] [ 0 ] [ ' txid ' ] )
assert_equal ( " 00 " , dec_tx [ ' vin ' ] [ 0 ] [ ' scriptSig ' ] [ ' hex ' ] )
assert_equal ( matchingOuts , 1 )
assert_equal ( len ( dec_tx [ ' vout ' ] ) , 2 )
2019-06-26 13:49:11 -04:00
def test_two_vin ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn with 2 vins " )
2016-04-16 13:36:39 -03:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 1 )
utx2 = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 5 )
2015-04-24 22:26:30 -03:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } , { ' txid ' : utx2 [ ' txid ' ] , ' vout ' : utx2 [ ' vout ' ] } ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 6.0 }
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtx )
assert_equal ( utx [ ' txid ' ] , dec_tx [ ' vin ' ] [ 0 ] [ ' txid ' ] )
rawtxfund = self . nodes [ 2 ] . fundrawtransaction ( rawtx )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtxfund [ ' hex ' ] )
totalOut = 0
matchingOuts = 0
for out in dec_tx [ ' vout ' ] :
totalOut + = out [ ' value ' ]
2016-03-19 17:36:32 -03:00
if out [ ' scriptPubKey ' ] [ ' addresses ' ] [ 0 ] in outputs :
2015-04-24 22:26:30 -03:00
matchingOuts + = 1
assert_equal ( matchingOuts , 1 )
assert_equal ( len ( dec_tx [ ' vout ' ] ) , 2 )
matchingIns = 0
for vinOut in dec_tx [ ' vin ' ] :
for vinIn in inputs :
if vinIn [ ' txid ' ] == vinOut [ ' txid ' ] :
matchingIns + = 1
assert_equal ( matchingIns , 2 ) #we now must see two vins identical to vins given as params
2019-06-26 13:49:11 -04:00
def test_two_vin_two_vout ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn with 2 vins and 2 vouts " )
2016-04-16 13:36:39 -03:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 1 )
utx2 = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 5 )
2015-04-24 22:26:30 -03:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } , { ' txid ' : utx2 [ ' txid ' ] , ' vout ' : utx2 [ ' vout ' ] } ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 6.0 , self . nodes [ 0 ] . getnewaddress ( ) : 1.0 }
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtx )
assert_equal ( utx [ ' txid ' ] , dec_tx [ ' vin ' ] [ 0 ] [ ' txid ' ] )
rawtxfund = self . nodes [ 2 ] . fundrawtransaction ( rawtx )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtxfund [ ' hex ' ] )
totalOut = 0
matchingOuts = 0
for out in dec_tx [ ' vout ' ] :
totalOut + = out [ ' value ' ]
2016-03-19 17:36:32 -03:00
if out [ ' scriptPubKey ' ] [ ' addresses ' ] [ 0 ] in outputs :
2015-04-24 22:26:30 -03:00
matchingOuts + = 1
assert_equal ( matchingOuts , 2 )
assert_equal ( len ( dec_tx [ ' vout ' ] ) , 3 )
2019-06-26 13:49:11 -04:00
def test_invalid_input ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn with an invalid vin " )
2015-04-24 22:26:30 -03:00
inputs = [ { ' txid ' : " 1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1 " , ' vout ' : 0 } ] #invalid vin!
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 1.0 }
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
2017-07-12 10:33:46 -04:00
assert_raises_rpc_error ( - 4 , " Insufficient funds " , self . nodes [ 2 ] . fundrawtransaction , rawtx )
2015-04-24 22:26:30 -03:00
2019-06-26 13:49:11 -04:00
def test_fee_p2pkh ( self ) :
2019-11-01 07:51:49 -03:00
""" Compare fee of a standard pubkeyhash transaction. """
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn p2pkh fee " )
2015-04-24 22:26:30 -03:00
inputs = [ ]
outputs = { self . nodes [ 1 ] . getnewaddress ( ) : 1.1 }
2017-03-26 02:47:27 -03:00
rawtx = self . nodes [ 0 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 0 ] . fundrawtransaction ( rawtx )
2015-04-24 22:26:30 -03:00
2019-11-01 07:51:49 -03:00
# Create same transaction over sendtoaddress.
2015-12-02 14:12:23 -03:00
txId = self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 1 ] . getnewaddress ( ) , 1.1 )
2015-04-24 22:26:30 -03:00
signedFee = self . nodes [ 0 ] . getrawmempool ( True ) [ txId ] [ ' fee ' ]
2019-11-01 07:51:49 -03:00
# Compare fee.
2015-12-02 14:12:23 -03:00
feeDelta = Decimal ( fundedTx [ ' fee ' ] ) - Decimal ( signedFee )
2019-06-26 12:42:11 -04:00
assert feeDelta > = 0 and feeDelta < = self . fee_tolerance
2015-04-24 22:26:30 -03:00
2019-06-26 13:49:11 -04:00
def test_fee_p2pkh_multi_out ( self ) :
2019-11-01 07:51:49 -03:00
""" Compare fee of a standard pubkeyhash transaction with multiple outputs. """
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn p2pkh fee with multiple outputs " )
2015-04-24 22:26:30 -03:00
inputs = [ ]
2019-10-31 07:46:57 -03:00
outputs = {
self . nodes [ 1 ] . getnewaddress ( ) : 1.1 ,
self . nodes [ 1 ] . getnewaddress ( ) : 1.2 ,
self . nodes [ 1 ] . getnewaddress ( ) : 0.1 ,
self . nodes [ 1 ] . getnewaddress ( ) : 1.3 ,
self . nodes [ 1 ] . getnewaddress ( ) : 0.2 ,
self . nodes [ 1 ] . getnewaddress ( ) : 0.3 ,
}
2017-03-26 02:47:27 -03:00
rawtx = self . nodes [ 0 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 0 ] . fundrawtransaction ( rawtx )
2019-11-01 07:51:49 -03:00
# Create same transaction over sendtoaddress.
2015-12-02 14:12:23 -03:00
txId = self . nodes [ 0 ] . sendmany ( " " , outputs )
2015-04-24 22:26:30 -03:00
signedFee = self . nodes [ 0 ] . getrawmempool ( True ) [ txId ] [ ' fee ' ]
2019-11-01 07:51:49 -03:00
# Compare fee.
2015-12-02 14:12:23 -03:00
feeDelta = Decimal ( fundedTx [ ' fee ' ] ) - Decimal ( signedFee )
2019-06-26 12:42:11 -04:00
assert feeDelta > = 0 and feeDelta < = self . fee_tolerance
2015-04-24 22:26:30 -03:00
2019-06-26 13:49:11 -04:00
def test_fee_p2sh ( self ) :
2019-11-01 07:51:49 -03:00
""" Compare fee of a 2-of-2 multisig p2sh transaction. """
# Create 2-of-2 addr.
2015-04-24 22:26:30 -03:00
addr1 = self . nodes [ 1 ] . getnewaddress ( )
addr2 = self . nodes [ 1 ] . getnewaddress ( )
2018-02-09 13:12:27 -03:00
addr1Obj = self . nodes [ 1 ] . getaddressinfo ( addr1 )
addr2Obj = self . nodes [ 1 ] . getaddressinfo ( addr2 )
2015-04-24 22:26:30 -03:00
2017-09-29 01:21:28 -03:00
mSigObj = self . nodes [ 1 ] . addmultisigaddress ( 2 , [ addr1Obj [ ' pubkey ' ] , addr2Obj [ ' pubkey ' ] ] ) [ ' address ' ]
2015-04-24 22:26:30 -03:00
inputs = [ ]
outputs = { mSigObj : 1.1 }
2017-03-26 02:47:27 -03:00
rawtx = self . nodes [ 0 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 0 ] . fundrawtransaction ( rawtx )
2015-04-24 22:26:30 -03:00
2019-11-01 07:51:49 -03:00
# Create same transaction over sendtoaddress.
2015-12-02 14:12:23 -03:00
txId = self . nodes [ 0 ] . sendtoaddress ( mSigObj , 1.1 )
2015-04-24 22:26:30 -03:00
signedFee = self . nodes [ 0 ] . getrawmempool ( True ) [ txId ] [ ' fee ' ]
2019-11-01 07:51:49 -03:00
# Compare fee.
2015-12-02 14:12:23 -03:00
feeDelta = Decimal ( fundedTx [ ' fee ' ] ) - Decimal ( signedFee )
2019-06-26 12:42:11 -04:00
assert feeDelta > = 0 and feeDelta < = self . fee_tolerance
2015-04-24 22:26:30 -03:00
2019-06-26 13:49:11 -04:00
def test_fee_4of5 ( self ) :
2019-11-01 07:51:49 -03:00
""" Compare fee of a standard pubkeyhash transaction. """
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn fee with 4-of-5 addresses " )
2015-04-24 22:26:30 -03:00
2019-11-01 07:51:49 -03:00
# Create 4-of-5 addr.
2015-04-24 22:26:30 -03:00
addr1 = self . nodes [ 1 ] . getnewaddress ( )
addr2 = self . nodes [ 1 ] . getnewaddress ( )
addr3 = self . nodes [ 1 ] . getnewaddress ( )
addr4 = self . nodes [ 1 ] . getnewaddress ( )
addr5 = self . nodes [ 1 ] . getnewaddress ( )
2018-02-09 13:12:27 -03:00
addr1Obj = self . nodes [ 1 ] . getaddressinfo ( addr1 )
addr2Obj = self . nodes [ 1 ] . getaddressinfo ( addr2 )
addr3Obj = self . nodes [ 1 ] . getaddressinfo ( addr3 )
addr4Obj = self . nodes [ 1 ] . getaddressinfo ( addr4 )
addr5Obj = self . nodes [ 1 ] . getaddressinfo ( addr5 )
2015-04-24 22:26:30 -03:00
2019-10-31 07:46:57 -03:00
mSigObj = self . nodes [ 1 ] . addmultisigaddress (
4 ,
[
addr1Obj [ ' pubkey ' ] ,
addr2Obj [ ' pubkey ' ] ,
addr3Obj [ ' pubkey ' ] ,
addr4Obj [ ' pubkey ' ] ,
addr5Obj [ ' pubkey ' ] ,
]
) [ ' address ' ]
2015-04-24 22:26:30 -03:00
inputs = [ ]
outputs = { mSigObj : 1.1 }
2017-03-26 02:47:27 -03:00
rawtx = self . nodes [ 0 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 0 ] . fundrawtransaction ( rawtx )
2015-04-24 22:26:30 -03:00
2019-11-01 07:51:49 -03:00
# Create same transaction over sendtoaddress.
2015-12-02 14:12:23 -03:00
txId = self . nodes [ 0 ] . sendtoaddress ( mSigObj , 1.1 )
2015-04-24 22:26:30 -03:00
signedFee = self . nodes [ 0 ] . getrawmempool ( True ) [ txId ] [ ' fee ' ]
2019-11-01 07:51:49 -03:00
# Compare fee.
2015-12-02 14:12:23 -03:00
feeDelta = Decimal ( fundedTx [ ' fee ' ] ) - Decimal ( signedFee )
2019-06-26 12:42:11 -04:00
assert feeDelta > = 0 and feeDelta < = self . fee_tolerance
2015-04-24 22:26:30 -03:00
2019-06-26 13:49:11 -04:00
def test_spend_2of2 ( self ) :
2019-11-01 07:51:49 -03:00
""" Spend a 2-of-2 multisig transaction over fundraw. """
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn spending 2-of-2 multisig " )
2015-04-24 22:26:30 -03:00
2019-11-01 07:51:49 -03:00
# Create 2-of-2 addr.
2015-04-24 22:26:30 -03:00
addr1 = self . nodes [ 2 ] . getnewaddress ( )
addr2 = self . nodes [ 2 ] . getnewaddress ( )
2018-02-09 13:12:27 -03:00
addr1Obj = self . nodes [ 2 ] . getaddressinfo ( addr1 )
addr2Obj = self . nodes [ 2 ] . getaddressinfo ( addr2 )
2015-04-24 22:26:30 -03:00
2019-10-31 07:46:57 -03:00
mSigObj = self . nodes [ 2 ] . addmultisigaddress (
2 ,
[
addr1Obj [ ' pubkey ' ] ,
addr2Obj [ ' pubkey ' ] ,
]
) [ ' address ' ]
2015-04-24 22:26:30 -03:00
2019-11-01 07:51:49 -03:00
# Send 1.2 BTC to msig addr.
2019-06-26 13:49:11 -04:00
self . nodes [ 0 ] . sendtoaddress ( mSigObj , 1.2 )
2019-11-01 11:21:01 -03:00
self . nodes [ 0 ] . generate ( 1 )
2015-04-24 22:26:30 -03:00
self . sync_all ( )
oldBalance = self . nodes [ 1 ] . getbalance ( )
inputs = [ ]
outputs = { self . nodes [ 1 ] . getnewaddress ( ) : 1.1 }
2017-03-26 02:47:27 -03:00
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 2 ] . fundrawtransaction ( rawtx )
2015-04-24 22:26:30 -03:00
2017-09-05 20:49:18 -03:00
signedTx = self . nodes [ 2 ] . signrawtransactionwithwallet ( fundedTx [ ' hex ' ] )
2019-06-26 13:49:11 -04:00
self . nodes [ 2 ] . sendrawtransaction ( signedTx [ ' hex ' ] )
2019-11-01 11:21:01 -03:00
self . nodes [ 2 ] . generate ( 1 )
2015-04-24 22:26:30 -03:00
self . sync_all ( )
2019-11-01 07:51:49 -03:00
# Make sure funds are received at node1.
2015-04-24 22:26:30 -03:00
assert_equal ( oldBalance + Decimal ( ' 1.10000000 ' ) , self . nodes [ 1 ] . getbalance ( ) )
2019-06-26 13:49:11 -04:00
def test_locked_wallet ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn with locked wallet " )
2018-02-20 18:09:51 -03:00
self . nodes [ 1 ] . encryptwallet ( " test " )
2015-04-24 22:26:30 -03:00
2019-11-01 07:51:49 -03:00
# Drain the keypool.
2016-12-07 11:20:40 -03:00
self . nodes [ 1 ] . getnewaddress ( )
2017-01-10 12:45:30 -03:00
self . nodes [ 1 ] . getrawchangeaddress ( )
2016-12-07 11:20:40 -03:00
inputs = [ ]
2019-10-23 10:21:50 -03:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 1.09999500 }
2017-03-26 02:47:27 -03:00
rawtx = self . nodes [ 1 ] . createrawtransaction ( inputs , outputs )
2019-10-23 10:21:50 -03:00
# fund a transaction that does not require a new key for the change output
self . nodes [ 1 ] . fundrawtransaction ( rawtx )
2016-12-07 11:20:40 -03:00
# fund a transaction that requires a new key for the change output
# creating the key must be impossible because the wallet is locked
2019-10-23 10:21:50 -03:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 1.1 }
rawtx = self . nodes [ 1 ] . createrawtransaction ( inputs , outputs )
assert_raises_rpc_error ( - 4 , " Transaction needs a change address, but we can ' t generate it. Please call keypoolrefill first. " , self . nodes [ 1 ] . fundrawtransaction , rawtx )
2016-12-07 11:20:40 -03:00
2019-11-01 07:51:49 -03:00
# Refill the keypool.
2016-12-07 11:20:40 -03:00
self . nodes [ 1 ] . walletpassphrase ( " test " , 100 )
2017-01-10 12:45:30 -03:00
self . nodes [ 1 ] . keypoolrefill ( 8 ) #need to refill the keypool to get an internal change address
2016-12-07 11:20:40 -03:00
self . nodes [ 1 ] . walletlock ( )
2017-07-12 10:33:46 -04:00
assert_raises_rpc_error ( - 13 , " walletpassphrase " , self . nodes [ 1 ] . sendtoaddress , self . nodes [ 0 ] . getnewaddress ( ) , 1.2 )
2015-04-24 22:26:30 -03:00
oldBalance = self . nodes [ 0 ] . getbalance ( )
inputs = [ ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 1.1 }
2017-03-26 02:47:27 -03:00
rawtx = self . nodes [ 1 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 1 ] . fundrawtransaction ( rawtx )
2015-04-24 22:26:30 -03:00
2019-11-01 07:51:49 -03:00
# Now we need to unlock.
2016-12-09 13:42:23 -03:00
self . nodes [ 1 ] . walletpassphrase ( " test " , 600 )
2017-09-05 20:49:18 -03:00
signedTx = self . nodes [ 1 ] . signrawtransactionwithwallet ( fundedTx [ ' hex ' ] )
2019-06-26 13:49:11 -04:00
self . nodes [ 1 ] . sendrawtransaction ( signedTx [ ' hex ' ] )
2015-04-24 22:26:30 -03:00
self . nodes [ 1 ] . generate ( 1 )
self . sync_all ( )
2019-11-01 07:51:49 -03:00
# Make sure funds are received at node1.
2015-04-24 22:26:30 -03:00
assert_equal ( oldBalance + Decimal ( ' 51.10000000 ' ) , self . nodes [ 0 ] . getbalance ( ) )
2019-06-26 13:49:11 -04:00
def test_many_inputs_fee ( self ) :
2019-11-01 07:51:49 -03:00
""" Multiple (~19) inputs tx test | Compare fee. """
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn fee with many inputs " )
2015-04-24 22:26:30 -03:00
2019-11-01 07:51:49 -03:00
# Empty node1, send some small coins from node0 to node1.
2015-12-02 14:12:23 -03:00
self . nodes [ 1 ] . sendtoaddress ( self . nodes [ 0 ] . getnewaddress ( ) , self . nodes [ 1 ] . getbalance ( ) , " " , " " , True )
2019-11-01 11:21:01 -03:00
self . nodes [ 1 ] . generate ( 1 )
2015-04-24 22:26:30 -03:00
self . sync_all ( )
for i in range ( 0 , 20 ) :
2015-12-02 14:12:23 -03:00
self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 1 ] . getnewaddress ( ) , 0.01 )
2015-04-24 22:26:30 -03:00
self . nodes [ 0 ] . generate ( 1 )
self . sync_all ( )
2019-11-01 07:51:49 -03:00
# Fund a tx with ~20 small inputs.
2015-04-24 22:26:30 -03:00
inputs = [ ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 0.15 , self . nodes [ 0 ] . getnewaddress ( ) : 0.04 }
2017-03-26 02:47:27 -03:00
rawtx = self . nodes [ 1 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 1 ] . fundrawtransaction ( rawtx )
2015-04-24 22:26:30 -03:00
2019-11-01 07:51:49 -03:00
# Create same transaction over sendtoaddress.
2015-12-02 14:12:23 -03:00
txId = self . nodes [ 1 ] . sendmany ( " " , outputs )
2015-04-24 22:26:30 -03:00
signedFee = self . nodes [ 1 ] . getrawmempool ( True ) [ txId ] [ ' fee ' ]
2019-11-01 07:51:49 -03:00
# Compare fee.
2015-12-02 14:12:23 -03:00
feeDelta = Decimal ( fundedTx [ ' fee ' ] ) - Decimal ( signedFee )
2019-06-26 12:42:11 -04:00
assert feeDelta > = 0 and feeDelta < = self . fee_tolerance * 19 #~19 inputs
2015-04-24 22:26:30 -03:00
2019-06-26 13:49:11 -04:00
def test_many_inputs_send ( self ) :
2019-11-01 07:51:49 -03:00
""" Multiple (~19) inputs tx test | sign/send. """
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn sign+send with many inputs " )
2015-04-24 22:26:30 -03:00
2019-11-01 07:51:49 -03:00
# Again, empty node1, send some small coins from node0 to node1.
2015-12-02 14:12:23 -03:00
self . nodes [ 1 ] . sendtoaddress ( self . nodes [ 0 ] . getnewaddress ( ) , self . nodes [ 1 ] . getbalance ( ) , " " , " " , True )
2019-11-01 11:21:01 -03:00
self . nodes [ 1 ] . generate ( 1 )
2015-04-24 22:26:30 -03:00
self . sync_all ( )
for i in range ( 0 , 20 ) :
2015-12-02 14:12:23 -03:00
self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 1 ] . getnewaddress ( ) , 0.01 )
2015-04-24 22:26:30 -03:00
self . nodes [ 0 ] . generate ( 1 )
self . sync_all ( )
2019-11-01 07:51:49 -03:00
# Fund a tx with ~20 small inputs.
2015-04-24 22:26:30 -03:00
oldBalance = self . nodes [ 0 ] . getbalance ( )
inputs = [ ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 0.15 , self . nodes [ 0 ] . getnewaddress ( ) : 0.04 }
2017-03-26 02:47:27 -03:00
rawtx = self . nodes [ 1 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 1 ] . fundrawtransaction ( rawtx )
2017-09-05 20:49:18 -03:00
fundedAndSignedTx = self . nodes [ 1 ] . signrawtransactionwithwallet ( fundedTx [ ' hex ' ] )
2019-06-26 13:49:11 -04:00
self . nodes [ 1 ] . sendrawtransaction ( fundedAndSignedTx [ ' hex ' ] )
2019-11-01 11:21:01 -03:00
self . nodes [ 1 ] . generate ( 1 )
2015-04-24 22:26:30 -03:00
self . sync_all ( )
assert_equal ( oldBalance + Decimal ( ' 50.19000000 ' ) , self . nodes [ 0 ] . getbalance ( ) ) #0.19+block reward
2019-06-26 13:49:11 -04:00
def test_op_return ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn with OP_RETURN and no vin " )
2015-03-25 06:04:02 -03:00
rawtx = " 0100000000010000000000000000066a047465737400000000 "
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtx )
assert_equal ( len ( dec_tx [ ' vin ' ] ) , 0 )
assert_equal ( len ( dec_tx [ ' vout ' ] ) , 1 )
rawtxfund = self . nodes [ 2 ] . fundrawtransaction ( rawtx )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtxfund [ ' hex ' ] )
assert_greater_than ( len ( dec_tx [ ' vin ' ] ) , 0 ) # at least one vin
assert_equal ( len ( dec_tx [ ' vout ' ] ) , 2 ) # one change output added
2019-06-26 13:49:11 -04:00
def test_watchonly ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn using only watchonly " )
2015-04-24 01:42:49 -03:00
inputs = [ ]
2019-06-26 12:42:11 -04:00
outputs = { self . nodes [ 2 ] . getnewaddress ( ) : self . watchonly_amount / 2 }
2015-04-24 01:42:49 -03:00
rawtx = self . nodes [ 3 ] . createrawtransaction ( inputs , outputs )
2016-03-29 22:04:22 -03:00
result = self . nodes [ 3 ] . fundrawtransaction ( rawtx , { ' includeWatching ' : True } )
2015-04-24 01:42:49 -03:00
res_dec = self . nodes [ 0 ] . decoderawtransaction ( result [ " hex " ] )
assert_equal ( len ( res_dec [ " vin " ] ) , 1 )
2019-06-26 12:42:11 -04:00
assert_equal ( res_dec [ " vin " ] [ 0 ] [ " txid " ] , self . watchonly_txid )
2015-04-24 01:42:49 -03:00
2019-02-19 19:43:44 -03:00
assert " fee " in result . keys ( )
2015-04-24 01:42:49 -03:00
assert_greater_than ( result [ " changepos " ] , - 1 )
2019-06-26 13:49:11 -04:00
def test_all_watched_funds ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn using entirety of watched funds " )
2015-04-24 01:42:49 -03:00
inputs = [ ]
2019-06-26 12:42:11 -04:00
outputs = { self . nodes [ 2 ] . getnewaddress ( ) : self . watchonly_amount }
2015-04-24 01:42:49 -03:00
rawtx = self . nodes [ 3 ] . createrawtransaction ( inputs , outputs )
2019-11-01 07:51:49 -03:00
# Backward compatibility test (2nd param is includeWatching).
2015-04-24 01:42:49 -03:00
result = self . nodes [ 3 ] . fundrawtransaction ( rawtx , True )
res_dec = self . nodes [ 0 ] . decoderawtransaction ( result [ " hex " ] )
assert_equal ( len ( res_dec [ " vin " ] ) , 2 )
2019-06-26 12:42:11 -04:00
assert res_dec [ " vin " ] [ 0 ] [ " txid " ] == self . watchonly_txid or res_dec [ " vin " ] [ 1 ] [ " txid " ] == self . watchonly_txid
2015-04-24 01:42:49 -03:00
assert_greater_than ( result [ " fee " ] , 0 )
assert_greater_than ( result [ " changepos " ] , - 1 )
2019-06-26 12:42:11 -04:00
assert_equal ( result [ " fee " ] + res_dec [ " vout " ] [ result [ " changepos " ] ] [ " value " ] , self . watchonly_amount / 10 )
2015-04-24 01:42:49 -03:00
2017-09-05 20:49:18 -03:00
signedtx = self . nodes [ 3 ] . signrawtransactionwithwallet ( result [ " hex " ] )
2019-02-19 19:43:44 -03:00
assert not signedtx [ " complete " ]
2017-09-05 20:49:18 -03:00
signedtx = self . nodes [ 0 ] . signrawtransactionwithwallet ( signedtx [ " hex " ] )
2019-02-19 19:43:44 -03:00
assert signedtx [ " complete " ]
2015-04-24 01:42:49 -03:00
self . nodes [ 0 ] . sendrawtransaction ( signedtx [ " hex " ] )
2016-06-13 13:52:01 -04:00
self . nodes [ 0 ] . generate ( 1 )
self . sync_all ( )
2019-06-26 13:49:11 -04:00
def test_option_feerate ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn feeRate option " )
2016-06-13 13:52:01 -04:00
2019-11-01 07:51:49 -03:00
# Make sure there is exactly one input so coin selection can't skew the result.
2016-06-13 13:52:01 -04:00
assert_equal ( len ( self . nodes [ 3 ] . listunspent ( 1 ) ) , 1 )
2015-04-24 01:42:49 -03:00
2016-04-28 17:04:07 -03:00
inputs = [ ]
2016-12-19 05:10:33 -03:00
outputs = { self . nodes [ 3 ] . getnewaddress ( ) : 1 }
2016-04-28 17:04:07 -03:00
rawtx = self . nodes [ 3 ] . createrawtransaction ( inputs , outputs )
2019-06-26 12:42:11 -04:00
result = self . nodes [ 3 ] . fundrawtransaction ( rawtx ) # uses self.min_relay_tx_fee (set by settxfee)
result2 = self . nodes [ 3 ] . fundrawtransaction ( rawtx , { " feeRate " : 2 * self . min_relay_tx_fee } )
result3 = self . nodes [ 3 ] . fundrawtransaction ( rawtx , { " feeRate " : 10 * self . min_relay_tx_fee } )
2019-06-28 22:44:38 -04:00
assert_raises_rpc_error ( - 4 , " Fee exceeds maximum configured by -maxtxfee " , self . nodes [ 3 ] . fundrawtransaction , rawtx , { " feeRate " : 1 } )
2016-06-13 13:52:01 -04:00
result_fee_rate = result [ ' fee ' ] * 1000 / count_bytes ( result [ ' hex ' ] )
assert_fee_amount ( result2 [ ' fee ' ] , count_bytes ( result2 [ ' hex ' ] ) , 2 * result_fee_rate )
assert_fee_amount ( result3 [ ' fee ' ] , count_bytes ( result3 [ ' hex ' ] ) , 10 * result_fee_rate )
2015-04-24 01:42:49 -03:00
2019-06-26 13:49:11 -04:00
def test_address_reuse ( self ) :
2019-11-01 07:51:49 -03:00
""" Test no address reuse occurs. """
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn does not reuse addresses " )
2016-12-19 05:10:33 -03:00
2019-06-26 12:42:11 -04:00
rawtx = self . nodes [ 3 ] . createrawtransaction ( inputs = [ ] , outputs = { self . nodes [ 3 ] . getnewaddress ( ) : 1 } )
2016-12-19 05:10:33 -03:00
result3 = self . nodes [ 3 ] . fundrawtransaction ( rawtx )
res_dec = self . nodes [ 0 ] . decoderawtransaction ( result3 [ " hex " ] )
changeaddress = " "
for out in res_dec [ ' vout ' ] :
if out [ ' value ' ] > 1.0 :
changeaddress + = out [ ' scriptPubKey ' ] [ ' addresses ' ] [ 0 ]
2019-02-19 19:43:44 -03:00
assert changeaddress != " "
2016-12-19 05:10:33 -03:00
nextaddr = self . nodes [ 3 ] . getnewaddress ( )
2019-11-01 07:51:49 -03:00
# Now the change address key should be removed from the keypool.
2019-02-19 19:43:44 -03:00
assert changeaddress != nextaddr
2016-12-19 05:10:33 -03:00
2019-06-26 13:49:11 -04:00
def test_option_subtract_fee_from_outputs ( self ) :
2019-10-31 07:46:57 -03:00
self . log . info ( " Test fundrawtxn subtractFeeFromOutputs option " )
2016-12-13 18:36:23 -03:00
2019-11-01 07:51:49 -03:00
# Make sure there is exactly one input so coin selection can't skew the result.
2016-12-13 18:36:23 -03:00
assert_equal ( len ( self . nodes [ 3 ] . listunspent ( 1 ) ) , 1 )
inputs = [ ]
outputs = { self . nodes [ 2 ] . getnewaddress ( ) : 1 }
rawtx = self . nodes [ 3 ] . createrawtransaction ( inputs , outputs )
2019-06-26 12:42:11 -04:00
result = [ self . nodes [ 3 ] . fundrawtransaction ( rawtx ) , # uses self.min_relay_tx_fee (set by settxfee)
self . nodes [ 3 ] . fundrawtransaction ( rawtx , { " subtractFeeFromOutputs " : [ ] } ) , # empty subtraction list
self . nodes [ 3 ] . fundrawtransaction ( rawtx , { " subtractFeeFromOutputs " : [ 0 ] } ) , # uses self.min_relay_tx_fee (set by settxfee)
self . nodes [ 3 ] . fundrawtransaction ( rawtx , { " feeRate " : 2 * self . min_relay_tx_fee } ) ,
self . nodes [ 3 ] . fundrawtransaction ( rawtx , { " feeRate " : 2 * self . min_relay_tx_fee , " subtractFeeFromOutputs " : [ 0 ] } ) , ]
2016-12-13 18:36:23 -03:00
2018-01-29 16:25:40 -03:00
dec_tx = [ self . nodes [ 3 ] . decoderawtransaction ( tx_ [ ' hex ' ] ) for tx_ in result ]
2016-12-13 18:36:23 -03:00
output = [ d [ ' vout ' ] [ 1 - r [ ' changepos ' ] ] [ ' value ' ] for d , r in zip ( dec_tx , result ) ]
change = [ d [ ' vout ' ] [ r [ ' changepos ' ] ] [ ' value ' ] for d , r in zip ( dec_tx , result ) ]
assert_equal ( result [ 0 ] [ ' fee ' ] , result [ 1 ] [ ' fee ' ] , result [ 2 ] [ ' fee ' ] )
assert_equal ( result [ 3 ] [ ' fee ' ] , result [ 4 ] [ ' fee ' ] )
assert_equal ( change [ 0 ] , change [ 1 ] )
assert_equal ( output [ 0 ] , output [ 1 ] )
assert_equal ( output [ 0 ] , output [ 2 ] + result [ 2 ] [ ' fee ' ] )
assert_equal ( change [ 0 ] + result [ 0 ] [ ' fee ' ] , change [ 2 ] )
assert_equal ( output [ 3 ] , output [ 4 ] + result [ 4 ] [ ' fee ' ] )
assert_equal ( change [ 3 ] + result [ 3 ] [ ' fee ' ] , change [ 4 ] )
inputs = [ ]
outputs = { self . nodes [ 2 ] . getnewaddress ( ) : value for value in ( 1.0 , 1.1 , 1.2 , 1.3 ) }
rawtx = self . nodes [ 3 ] . createrawtransaction ( inputs , outputs )
result = [ self . nodes [ 3 ] . fundrawtransaction ( rawtx ) ,
2019-11-01 07:51:49 -03:00
# Split the fee between outputs 0, 2, and 3, but not output 1.
2016-12-13 18:36:23 -03:00
self . nodes [ 3 ] . fundrawtransaction ( rawtx , { " subtractFeeFromOutputs " : [ 0 , 2 , 3 ] } ) ]
dec_tx = [ self . nodes [ 3 ] . decoderawtransaction ( result [ 0 ] [ ' hex ' ] ) ,
self . nodes [ 3 ] . decoderawtransaction ( result [ 1 ] [ ' hex ' ] ) ]
2019-11-01 07:51:49 -03:00
# Nested list of non-change output amounts for each transaction.
2016-12-13 18:36:23 -03:00
output = [ [ out [ ' value ' ] for i , out in enumerate ( d [ ' vout ' ] ) if i != r [ ' changepos ' ] ]
for d , r in zip ( dec_tx , result ) ]
2019-11-01 07:51:49 -03:00
# List of differences in output amounts between normal and subtractFee transactions.
2016-12-13 18:36:23 -03:00
share = [ o0 - o1 for o0 , o1 in zip ( output [ 0 ] , output [ 1 ] ) ]
2019-11-01 07:51:49 -03:00
# Output 1 is the same in both transactions.
2016-12-13 18:36:23 -03:00
assert_equal ( share [ 1 ] , 0 )
2019-11-01 07:51:49 -03:00
# The other 3 outputs are smaller as a result of subtractFeeFromOutputs.
2016-12-13 18:36:23 -03:00
assert_greater_than ( share [ 0 ] , 0 )
assert_greater_than ( share [ 2 ] , 0 )
assert_greater_than ( share [ 3 ] , 0 )
2019-11-01 07:51:49 -03:00
# Outputs 2 and 3 take the same share of the fee.
2016-12-13 18:36:23 -03:00
assert_equal ( share [ 2 ] , share [ 3 ] )
2019-11-01 07:51:49 -03:00
# Output 0 takes at least as much share of the fee, and no more than 2
# satoshis more, than outputs 2 and 3.
2016-12-13 18:36:23 -03:00
assert_greater_than_or_equal ( share [ 0 ] , share [ 2 ] )
assert_greater_than_or_equal ( share [ 2 ] + Decimal ( 2e-8 ) , share [ 0 ] )
2019-11-01 07:51:49 -03:00
# The fee is the same in both transactions.
2016-12-13 18:36:23 -03:00
assert_equal ( result [ 0 ] [ ' fee ' ] , result [ 1 ] [ ' fee ' ] )
2019-11-01 07:51:49 -03:00
# The total subtracted from the outputs is equal to the fee.
2016-12-13 18:36:23 -03:00
assert_equal ( share [ 0 ] + share [ 2 ] + share [ 3 ] , result [ 0 ] [ ' fee ' ] )
2019-11-23 00:21:36 -03:00
def test_subtract_fee_with_presets ( self ) :
self . log . info ( " Test fundrawtxn subtract fee from outputs with preset inputs that are sufficient " )
addr = self . nodes [ 0 ] . getnewaddress ( )
txid = self . nodes [ 0 ] . sendtoaddress ( addr , 10 )
vout = find_vout_for_address ( self . nodes [ 0 ] , txid , addr )
rawtx = self . nodes [ 0 ] . createrawtransaction ( [ { ' txid ' : txid , ' vout ' : vout } ] , [ { self . nodes [ 0 ] . getnewaddress ( ) : 5 } ] )
fundedtx = self . nodes [ 0 ] . fundrawtransaction ( rawtx , { ' subtractFeeFromOutputs ' : [ 0 ] } )
signedtx = self . nodes [ 0 ] . signrawtransactionwithwallet ( fundedtx [ ' hex ' ] )
self . nodes [ 0 ] . sendrawtransaction ( signedtx [ ' hex ' ] )
2015-04-24 22:26:30 -03:00
if __name__ == ' __main__ ' :
RawTransactionsTest ( ) . main ( )