2016-05-06 11:23:48 +02:00
#!/usr/bin/env python3
2023-08-16 19:27:31 +02:00
# Copyright (c) 2014-2020 The Bitcoin Core developers
2015-04-25 03:26:30 +02:00
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
2019-01-07 10:55:35 +01:00
""" Test the fundrawtransaction RPC. """
2015-04-25 03:26:30 +02:00
2018-05-09 10:12:45 +02:00
from decimal import Decimal
2017-09-06 20:02:08 +02:00
from test_framework . test_framework import BitcoinTestFramework
2018-05-09 10:12:45 +02:00
from test_framework . util import (
assert_equal ,
assert_fee_amount ,
assert_greater_than ,
assert_greater_than_or_equal ,
assert_raises_rpc_error ,
count_bytes ,
find_vout_for_address ,
2023-11-03 16:05:37 +01:00
satoshi_round ,
2018-05-09 10:12:45 +02:00
)
2015-04-25 03:26:30 +02:00
2016-06-21 10:24:09 +02: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-25 03:26:30 +02:00
class RawTransactionsTest ( BitcoinTestFramework ) :
2017-09-01 18:47:13 +02:00
def set_test_params ( self ) :
2016-05-20 15:16:51 +02:00
self . num_nodes = 4
2017-09-01 18:47:13 +02:00
self . setup_clean_chain = True
2019-11-06 21:18:34 +01:00
# This test isn't testing tx relay. Set whitelist on the peers for
# instant tx relay.
2024-02-28 10:02:21 +01:00
self . extra_args = [ [ f ' -usehd= { not self . options . nohd } ' , ' -whitelist=noban@127.0.0.1 ' ] ] * self . num_nodes
2015-04-25 03:26:30 +02:00
2018-09-13 12:33:15 +02:00
def skip_test_if_missing_module ( self ) :
self . skip_if_no_wallet ( )
2023-05-24 19:38:33 +02:00
def add_options ( self , parser ) :
2024-02-28 10:02:21 +01:00
parser . add_argument ( " --nohd " , dest = " nohd " , default = False , action = " store_true " ,
help = " Test with -nohd enabled " )
2023-05-24 19:38:33 +02:00
2018-12-29 20:18:43 +01:00
def setup_network ( self ) :
2019-06-20 18:37:09 +02:00
self . setup_nodes ( )
2015-04-25 03:26:30 +02:00
2022-09-24 14:36:35 +02:00
self . connect_nodes ( 0 , 1 )
self . connect_nodes ( 1 , 2 )
self . connect_nodes ( 0 , 2 )
self . connect_nodes ( 0 , 3 )
2015-04-25 03:26:30 +02:00
def run_test ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Connect nodes, set fees, generate blocks, and sync " )
2019-08-01 00:03:43 +02:00
self . min_relay_tx_fee = self . nodes [ 0 ] . getnetworkinfo ( ) [ ' relayfee ' ]
2016-01-05 19:10:19 +01: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-08-01 00:03:43 +02:00
node . settxfee ( self . min_relay_tx_fee )
2016-01-05 19:10:19 +01:00
2015-10-14 14:27:03 +02: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-08-01 00:03:43 +02:00
self . fee_tolerance = 2 * self . min_relay_tx_fee / 1000
2015-04-25 03:26:30 +02:00
self . nodes [ 2 ] . generate ( 1 )
2015-07-10 20:11:44 +02:00
self . sync_all ( )
2015-04-24 06:42:49 +02:00
self . nodes [ 0 ] . generate ( 121 )
2015-04-25 03:26:30 +02:00
self . sync_all ( )
2015-04-24 06:42:49 +02:00
2019-08-01 00:03:43 +02: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_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-12-01 17:56:52 +01:00
self . test_subtract_fee_with_presets ( )
2019-08-01 00:03:43 +02:00
def test_change_position ( self ) :
2019-11-01 16:06:12 +01:00
""" Ensure setting changePosition in fundraw with an exact match is handled properly. """
self . log . info ( " Test fundrawtxn changePosition option " )
2018-01-25 22:07:35 +01:00
rawmatch = self . nodes [ 2 ] . createrawtransaction ( [ ] , { self . nodes [ 2 ] . getnewaddress ( ) : 500 } )
2017-05-01 15:19:47 +02:00
rawmatch = self . nodes [ 2 ] . fundrawtransaction ( rawmatch , { " changePosition " : 1 , " subtractFeeFromOutputs " : [ 0 ] } )
assert_equal ( rawmatch [ " changepos " ] , - 1 )
2015-04-24 06:42:49 +02:00
watchonly_address = self . nodes [ 0 ] . getnewaddress ( )
2020-12-17 13:46:20 +01:00
watchonly_pubkey = self . nodes [ 0 ] . getaddressinfo ( watchonly_address ) [ " pubkey " ]
2019-08-01 00:03:43 +02:00
self . watchonly_amount = Decimal ( 2000 )
2015-04-24 06:42:49 +02:00
self . nodes [ 3 ] . importpubkey ( watchonly_pubkey , " " , True )
2019-08-01 00:03:43 +02:00
self . watchonly_txid = self . nodes [ 0 ] . sendtoaddress ( watchonly_address , self . watchonly_amount )
2018-05-09 10:12:45 +02:00
# Lock UTXO so nodes[0] doesn't accidentally spend it
2019-08-01 00:03:43 +02: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-05-09 10:12:45 +02:00
2019-08-01 00:03:43 +02:00
self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 3 ] . getnewaddress ( ) , self . watchonly_amount / 10 )
2015-04-24 06:42:49 +02:00
2016-03-06 16:14:39 +01:00
self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 2 ] . getnewaddress ( ) , 15 )
self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 2 ] . getnewaddress ( ) , 10 )
self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 2 ] . getnewaddress ( ) , 50 )
2015-04-24 06:42:49 +02:00
2015-04-25 03:26:30 +02:00
self . nodes [ 0 ] . generate ( 1 )
self . sync_all ( )
2019-08-01 00:03:43 +02:00
def test_simple ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn " )
2015-04-25 03:26:30 +02:00
inputs = [ ]
2016-03-06 16:14:39 +01:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 10 }
2015-04-25 03:26:30 +02:00
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 ' ] )
2021-08-27 21:03:02 +02:00
assert len ( dec_tx [ ' vin ' ] ) > 0 #test that we have enough inputs
2015-04-25 03:26:30 +02:00
2019-08-01 00:03:43 +02:00
def test_simple_two_coins ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn with 2 coins " )
2015-04-25 03:26:30 +02:00
inputs = [ ]
2016-03-06 16:14:39 +01:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 22 }
2015-04-25 03:26:30 +02:00
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 ' ] )
2021-08-27 21:03:02 +02:00
assert len ( dec_tx [ ' vin ' ] ) > 0 #test if we have enough inputs
2015-04-25 03:26:30 +02:00
assert_equal ( dec_tx [ ' vin ' ] [ 0 ] [ ' scriptSig ' ] [ ' hex ' ] , ' ' )
2019-08-01 00:03:43 +02:00
def test_simple_two_outputs ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn with 2 outputs " )
2015-04-25 03:26:30 +02:00
inputs = [ ]
2016-03-06 16:14:39 +01:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 26 , self . nodes [ 1 ] . getnewaddress ( ) : 25 }
2015-04-25 03:26:30 +02:00
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 ' ]
2023-11-03 16:05:37 +01:00
address = out [ ' scriptPubKey ' ] [ ' addresses ' ] [ 0 ]
if address in outputs . keys ( ) :
assert_equal ( satoshi_round ( outputs [ address ] ) , out [ ' value ' ] )
2015-04-25 03:26:30 +02:00
2021-08-27 21:03:02 +02:00
assert len ( dec_tx [ ' vin ' ] ) > 0
2015-04-25 03:26:30 +02:00
assert_equal ( dec_tx [ ' vin ' ] [ 0 ] [ ' scriptSig ' ] [ ' hex ' ] , ' ' )
2019-08-01 00:03:43 +02:00
def test_change ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn with a vin > required amount " )
2016-06-21 10:24:09 +02:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 50 )
2015-04-25 03:26:30 +02:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } ]
2016-03-06 16:14:39 +01:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 10 }
2015-04-25 03:26:30 +02: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 ' ]
2019-08-01 00:03:43 +02:00
self . test_no_change_fee = fee # Use the same fee for the next tx
2015-04-25 03:26:30 +02: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-08-01 00:03:43 +02:00
def test_no_change ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn not having a change output " )
2016-06-21 10:24:09 +02:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 50 )
2015-04-25 03:26:30 +02:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } ]
2019-08-01 00:03:43 +02:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : Decimal ( 50 ) - self . test_no_change_fee - self . fee_tolerance }
2015-04-25 03:26:30 +02: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-08-01 00:03:43 +02:00
def test_invalid_option ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn with an invalid option " )
2016-06-21 10:24:09 +02:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 50 )
2016-04-15 16:23:16 +02:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } ]
2017-12-20 21:43:27 +01:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : Decimal ( 40 ) }
2016-04-15 16:23:16 +02:00
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtx )
assert_equal ( utx [ ' txid ' ] , dec_tx [ ' vin ' ] [ 0 ] [ ' txid ' ] )
2019-09-25 11:34:51 +02:00
assert_raises_rpc_error ( - 3 , " Unexpected key foo " , self . nodes [ 2 ] . fundrawtransaction , rawtx , { ' foo ' : ' bar ' } )
2016-04-15 16:23:16 +02:00
2018-02-14 16:42:40 +01: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-08-01 00:03:43 +02:00
def test_invalid_change_address ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn with an invalid change address " )
2016-06-21 10:24:09 +02:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 50 )
2016-04-15 16:23:16 +02:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } ]
2017-12-20 21:43:27 +01:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : Decimal ( 40 ) }
2016-04-15 16:23:16 +02:00
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtx )
assert_equal ( utx [ ' txid ' ] , dec_tx [ ' vin ' ] [ 0 ] [ ' txid ' ] )
trivial: add missing rpc help messages, remove segwit references, dashify help text, undashify code comments (#5852)
## Issue being fixed or feature implemented
This pull request is a follow-up to
[some](https://github.com/dashpay/dash/pull/5834#discussion_r1470105685)
[feedback](https://github.com/dashpay/dash/pull/5834#discussion_r1467009815)
received on [dash#5834](https://github.com/dashpay/dash/pull/5834) as
the patterns highlighted were present in different parts of the codebase
and hence not corrected within the PR itself but addressed separately.
This is that separate PR 🙂 (with some additional cleanup of my own)
## What was done?
* This pull request will remain a draft until
[dash#5834](https://github.com/dashpay/dash/pull/5834) as it will
introduce more changes that will need to be corrected in this PR.
* Code introduced that is unique to Dash Core (CoinJoin, InstantSend,
etc.) has been excluded from un-Dashification as the purpose of it is to
reduce backport conflicts, which don't apply in those cases.
* `CWallet::CreateTransaction` and the `CreateTransactionTest` fixture
have been excluded as the former originates from
[dash#3668](https://github.com/dashpay/dash/pull/3668) and the latter
from [dash#3667](https://github.com/dashpay/dash/pull/3667) and are
distinct enough to be unique to Dash Core.
* There are certain Dashifications and SegWit-removals that prove
frustrating as it would break compatibility with programs that rely on
the naming of certain keys
* `getrawmempool`, `getmempoolancestors`, `getmempooldescendants` and
`getmempoolentry` return `vsize` which is currently an alias of `size`.
I have been advised to retain `vsize` in lieu of potential future
developments. (this was originally remedied in
219a1d08973e7ccda6e778218b9a8218b4aae034 but has since been dropped)
* `getaddressmempool`, `getaddressutxos` and `getaddressdeltas` all
return a value with the key `satoshis`. This is frustrating to rename to
`duffs` for compatibility reasons.
* `decodepsbt` returns (if applicable) `non_witness_utxo` which is
frustrating to rename simply to `utxo` for the same reason.
* `analyzepsbt` returns (if applicable) `estimated_vsize` which
frustrating to rename to `estimated_size` for the same reason.
## How Has This Been Tested?
## Breaking Changes
None
## Checklist:
- [x] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have added or updated relevant unit/integration/functional/e2e
tests
- [ ] I have made corresponding changes to the documentation
- [x] I have assigned this pull request to a milestone _(for repository
code-owners and collaborators only)_
2024-02-09 18:40:38 +01:00
assert_raises_rpc_error ( - 5 , " changeAddress must be a valid Dash address " , self . nodes [ 2 ] . fundrawtransaction , rawtx , { ' changeAddress ' : ' foobar ' } )
2016-04-15 16:23:16 +02:00
2019-08-01 00:03:43 +02:00
def test_valid_change_address ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn with a provided change address " )
2016-06-21 10:24:09 +02:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 50 )
2016-04-15 16:23:16 +02:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } ]
2017-12-20 21:43:27 +01:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : Decimal ( 40 ) }
2016-04-15 16:23:16 +02:00
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 ( )
2019-09-25 11:34:51 +02:00
assert_raises_rpc_error ( - 8 , " changePosition out of bounds " , self . nodes [ 2 ] . fundrawtransaction , rawtx , { ' changeAddress ' : change , ' changePosition ' : 2 } )
2016-04-15 16:23:16 +02:00
rawtxfund = self . nodes [ 2 ] . fundrawtransaction ( rawtx , { ' changeAddress ' : change , ' changePosition ' : 0 } )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtxfund [ ' hex ' ] )
2017-01-23 13:22:32 +01:00
out = dec_tx [ ' vout ' ] [ 0 ]
2016-04-15 16:23:16 +02:00
assert_equal ( change , out [ ' scriptPubKey ' ] [ ' addresses ' ] [ 0 ] )
2019-08-01 00:03:43 +02:00
def test_coin_selection ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn with a vin < required amount " )
2016-06-21 10:24:09 +02:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 10 )
2015-04-25 03:26:30 +02:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } ]
2016-03-06 16:14:39 +01:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 10 }
2015-04-25 03:26:30 +02:00
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 21:36:32 +01:00
if out [ ' scriptPubKey ' ] [ ' addresses ' ] [ 0 ] in outputs :
2015-04-25 03:26:30 +02: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-08-01 00:03:43 +02:00
def test_two_vin ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn with 2 vins " )
2016-06-21 10:24:09 +02:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 10 )
utx2 = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 50 )
2015-04-25 03:26:30 +02:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } , { ' txid ' : utx2 [ ' txid ' ] , ' vout ' : utx2 [ ' vout ' ] } ]
2016-03-06 16:14:39 +01:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 60 }
2015-04-25 03:26:30 +02: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 )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtxfund [ ' hex ' ] )
totalOut = 0
matchingOuts = 0
for out in dec_tx [ ' vout ' ] :
totalOut + = out [ ' value ' ]
2016-03-19 21:36:32 +01:00
if out [ ' scriptPubKey ' ] [ ' addresses ' ] [ 0 ] in outputs :
2015-04-25 03:26:30 +02: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-08-01 00:03:43 +02:00
def test_two_vin_two_vout ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn with 2 vins and 2 vouts " )
2016-06-21 10:24:09 +02:00
utx = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 10 )
utx2 = get_unspent ( self . nodes [ 2 ] . listunspent ( ) , 50 )
2015-04-25 03:26:30 +02:00
inputs = [ { ' txid ' : utx [ ' txid ' ] , ' vout ' : utx [ ' vout ' ] } , { ' txid ' : utx2 [ ' txid ' ] , ' vout ' : utx2 [ ' vout ' ] } ]
2016-03-06 16:14:39 +01:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 60 , self . nodes [ 0 ] . getnewaddress ( ) : 10 }
2015-04-25 03:26:30 +02: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 )
dec_tx = self . nodes [ 2 ] . decoderawtransaction ( rawtxfund [ ' hex ' ] )
totalOut = 0
matchingOuts = 0
for out in dec_tx [ ' vout ' ] :
totalOut + = out [ ' value ' ]
2016-03-19 21:36:32 +01:00
if out [ ' scriptPubKey ' ] [ ' addresses ' ] [ 0 ] in outputs :
2015-04-25 03:26:30 +02:00
matchingOuts + = 1
assert_equal ( matchingOuts , 2 )
assert_equal ( len ( dec_tx [ ' vout ' ] ) , 3 )
2019-08-01 00:03:43 +02:00
def test_invalid_input ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn with an invalid vin " )
2015-04-25 03:26:30 +02:00
inputs = [ { ' txid ' : " 1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1 " , ' vout ' : 0 } ] #invalid vin!
2016-03-06 16:14:39 +01:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 10 }
2015-04-25 03:26:30 +02:00
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
2019-09-25 11:34:51 +02:00
assert_raises_rpc_error ( - 4 , " Insufficient funds " , self . nodes [ 2 ] . fundrawtransaction , rawtx )
2015-04-25 03:26:30 +02:00
2019-08-01 00:03:43 +02:00
def test_fee_p2pkh ( self ) :
2019-11-01 16:06:12 +01:00
""" Compare fee of a standard pubkeyhash transaction. """
self . log . info ( " Test fundrawtxn p2pkh fee " )
2015-04-25 03:26:30 +02:00
inputs = [ ]
2016-03-06 16:14:39 +01:00
outputs = { self . nodes [ 1 ] . getnewaddress ( ) : 11 }
2017-03-27 09:10:37 +02:00
rawtx = self . nodes [ 0 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 0 ] . fundrawtransaction ( rawtx )
2015-04-25 03:26:30 +02:00
2019-11-01 16:06:12 +01:00
# Create same transaction over sendtoaddress.
2016-03-06 16:14:39 +01:00
txId = self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 1 ] . getnewaddress ( ) , 11 )
2015-04-25 03:26:30 +02:00
signedFee = self . nodes [ 0 ] . getrawmempool ( True ) [ txId ] [ ' fee ' ]
2019-11-01 16:06:12 +01:00
# Compare fee.
2015-12-02 18:12:23 +01:00
feeDelta = Decimal ( fundedTx [ ' fee ' ] ) - Decimal ( signedFee )
2019-08-01 00:03:43 +02:00
assert feeDelta > = 0 and feeDelta < = self . fee_tolerance
2015-04-25 03:26:30 +02:00
2019-08-01 00:03:43 +02:00
def test_fee_p2pkh_multi_out ( self ) :
2019-11-01 16:06:12 +01:00
""" Compare fee of a standard pubkeyhash transaction with multiple outputs. """
self . log . info ( " Test fundrawtxn p2pkh fee with multiple outputs " )
2015-04-25 03:26:30 +02:00
inputs = [ ]
2019-11-01 16:06:12 +01:00
outputs = {
self . nodes [ 1 ] . getnewaddress ( ) : 11 ,
self . nodes [ 1 ] . getnewaddress ( ) : 12 ,
self . nodes [ 1 ] . getnewaddress ( ) : 1 ,
self . nodes [ 1 ] . getnewaddress ( ) : 13 ,
self . nodes [ 1 ] . getnewaddress ( ) : 2 ,
self . nodes [ 1 ] . getnewaddress ( ) : 3 ,
}
2017-03-27 09:10:37 +02:00
rawtx = self . nodes [ 0 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 0 ] . fundrawtransaction ( rawtx )
2019-11-01 16:06:12 +01:00
# Create same transaction over sendtoaddress.
2015-12-02 18:12:23 +01:00
txId = self . nodes [ 0 ] . sendmany ( " " , outputs )
2015-04-25 03:26:30 +02:00
signedFee = self . nodes [ 0 ] . getrawmempool ( True ) [ txId ] [ ' fee ' ]
2019-11-01 16:06:12 +01:00
# Compare fee.
2015-12-02 18:12:23 +01:00
feeDelta = Decimal ( fundedTx [ ' fee ' ] ) - Decimal ( signedFee )
2019-08-01 00:03:43 +02:00
assert feeDelta > = 0 and feeDelta < = self . fee_tolerance
2015-04-25 03:26:30 +02:00
2019-08-01 00:03:43 +02:00
def test_fee_p2sh ( self ) :
2019-11-01 16:06:12 +01:00
""" Compare fee of a 2-of-2 multisig p2sh transaction. """
# Create 2-of-2 addr.
2015-04-25 03:26:30 +02:00
addr1 = self . nodes [ 1 ] . getnewaddress ( )
addr2 = self . nodes [ 1 ] . getnewaddress ( )
2020-12-17 13:46:20 +01:00
addr1Obj = self . nodes [ 1 ] . getaddressinfo ( addr1 )
addr2Obj = self . nodes [ 1 ] . getaddressinfo ( addr2 )
2015-04-25 03:26:30 +02:00
2020-05-15 11:34:41 +02:00
mSigObj = self . nodes [ 1 ] . addmultisigaddress ( 2 , [ addr1Obj [ ' pubkey ' ] , addr2Obj [ ' pubkey ' ] ] ) [ ' address ' ]
2015-04-25 03:26:30 +02:00
inputs = [ ]
2016-03-06 16:14:39 +01:00
outputs = { mSigObj : 11 }
2017-03-27 09:10:37 +02:00
rawtx = self . nodes [ 0 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 0 ] . fundrawtransaction ( rawtx )
2015-04-25 03:26:30 +02:00
2019-11-01 16:06:12 +01:00
# Create same transaction over sendtoaddress.
2016-03-06 16:14:39 +01:00
txId = self . nodes [ 0 ] . sendtoaddress ( mSigObj , 11 )
2015-04-25 03:26:30 +02:00
signedFee = self . nodes [ 0 ] . getrawmempool ( True ) [ txId ] [ ' fee ' ]
2019-11-01 16:06:12 +01:00
# Compare fee.
2015-12-02 18:12:23 +01:00
feeDelta = Decimal ( fundedTx [ ' fee ' ] ) - Decimal ( signedFee )
2019-08-01 00:03:43 +02:00
assert feeDelta > = 0 and feeDelta < = self . fee_tolerance
2015-04-25 03:26:30 +02:00
2019-08-01 00:03:43 +02:00
def test_fee_4of5 ( self ) :
2019-11-01 16:06:12 +01:00
""" Compare fee of a standard pubkeyhash transaction. """
self . log . info ( " Test fundrawtxn fee with 4-of-5 addresses " )
2015-04-25 03:26:30 +02:00
2019-11-01 16:06:12 +01:00
# Create 4-of-5 addr.
2015-04-25 03:26:30 +02: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 ( )
2020-12-17 13:46:20 +01: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-25 03:26:30 +02:00
2019-11-01 16:06:12 +01:00
mSigObj = self . nodes [ 1 ] . addmultisigaddress (
4 ,
[
addr1Obj [ ' pubkey ' ] ,
addr2Obj [ ' pubkey ' ] ,
addr3Obj [ ' pubkey ' ] ,
addr4Obj [ ' pubkey ' ] ,
addr5Obj [ ' pubkey ' ] ,
]
) [ ' address ' ]
2015-04-25 03:26:30 +02:00
inputs = [ ]
2016-03-06 16:14:39 +01:00
outputs = { mSigObj : 11 }
2017-03-27 09:10:37 +02:00
rawtx = self . nodes [ 0 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 0 ] . fundrawtransaction ( rawtx )
2015-04-25 03:26:30 +02:00
2019-11-01 16:06:12 +01:00
# Create same transaction over sendtoaddress.
2016-03-06 16:14:39 +01:00
txId = self . nodes [ 0 ] . sendtoaddress ( mSigObj , 11 )
2015-04-25 03:26:30 +02:00
signedFee = self . nodes [ 0 ] . getrawmempool ( True ) [ txId ] [ ' fee ' ]
2019-11-01 16:06:12 +01:00
# Compare fee.
2015-12-02 18:12:23 +01:00
feeDelta = Decimal ( fundedTx [ ' fee ' ] ) - Decimal ( signedFee )
2019-08-01 00:03:43 +02:00
assert feeDelta > = 0 and feeDelta < = self . fee_tolerance
2015-04-25 03:26:30 +02:00
2019-08-01 00:03:43 +02:00
def test_spend_2of2 ( self ) :
2019-11-01 16:06:12 +01:00
""" Spend a 2-of-2 multisig transaction over fundraw. """
self . log . info ( " Test fundrawtxn spending 2-of-2 multisig " )
2015-04-25 03:26:30 +02:00
2019-11-01 16:06:12 +01:00
# Create 2-of-2 addr.
2015-04-25 03:26:30 +02:00
addr1 = self . nodes [ 2 ] . getnewaddress ( )
addr2 = self . nodes [ 2 ] . getnewaddress ( )
2020-12-17 13:46:20 +01:00
addr1Obj = self . nodes [ 2 ] . getaddressinfo ( addr1 )
addr2Obj = self . nodes [ 2 ] . getaddressinfo ( addr2 )
2015-04-25 03:26:30 +02:00
2019-11-01 16:06:12 +01:00
mSigObj = self . nodes [ 2 ] . addmultisigaddress (
2 ,
[
addr1Obj [ ' pubkey ' ] ,
addr2Obj [ ' pubkey ' ] ,
]
) [ ' address ' ]
2015-04-25 03:26:30 +02:00
2016-03-06 16:14:39 +01:00
# send 12 DASH to msig addr
2019-08-01 00:03:43 +02:00
self . nodes [ 0 ] . sendtoaddress ( mSigObj , 12 )
2019-11-06 21:18:34 +01:00
self . nodes [ 0 ] . generate ( 1 )
2015-04-25 03:26:30 +02:00
self . sync_all ( )
oldBalance = self . nodes [ 1 ] . getbalance ( )
inputs = [ ]
2016-03-06 16:14:39 +01:00
outputs = { self . nodes [ 1 ] . getnewaddress ( ) : 11 }
2017-03-27 09:10:37 +02:00
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 2 ] . fundrawtransaction ( rawtx )
2015-04-25 03:26:30 +02:00
2018-02-20 03:29:22 +01:00
signedTx = self . nodes [ 2 ] . signrawtransactionwithwallet ( fundedTx [ ' hex ' ] )
2019-08-01 00:03:43 +02:00
self . nodes [ 2 ] . sendrawtransaction ( signedTx [ ' hex ' ] )
2019-11-06 21:18:34 +01:00
self . nodes [ 2 ] . generate ( 1 )
2015-04-25 03:26:30 +02:00
self . sync_all ( )
2019-11-01 16:06:12 +01:00
# Make sure funds are received at node1.
2016-03-06 16:14:39 +01:00
assert_equal ( oldBalance + Decimal ( ' 11.0000000 ' ) , self . nodes [ 1 ] . getbalance ( ) )
2015-04-25 03:26:30 +02:00
2019-08-01 00:03:43 +02:00
def test_locked_wallet ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn with locked wallet " )
2018-09-14 10:28:27 +02:00
self . nodes [ 1 ] . encryptwallet ( " test " )
2015-04-25 03:26:30 +02:00
2019-11-01 16:06:12 +01:00
# Drain the keypool.
2017-04-11 12:53:54 +02:00
self . nodes [ 1 ] . getnewaddress ( )
2020-04-18 11:37:20 +02:00
inputs = self . nodes [ 1 ] . listunspent ( )
# Deduce fee to produce a changeless transaction
# bnb doesn't work same way as in bitcoin, so, `value` is also calculated by different way
value = sum ( input_it [ " amount " ] for input_it in inputs ) - Decimal ( " 0.00002200 " )
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : value }
2017-03-27 09:10:37 +02:00
rawtx = self . nodes [ 1 ] . createrawtransaction ( inputs , outputs )
2020-04-18 11:37:20 +02:00
# fund a transaction that does not require a new key for the change output
self . nodes [ 1 ] . fundrawtransaction ( rawtx )
2017-04-11 12:53:54 +02:00
# fund a transaction that requires a new key for the change output
# creating the key must be impossible because the wallet is locked
2020-04-18 11:37:20 +02: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 )
2017-04-11 12:53:54 +02:00
2019-11-01 16:06:12 +01:00
# Refill the keypool.
2017-04-11 12:53:54 +02:00
self . nodes [ 1 ] . walletpassphrase ( " test " , 100 )
self . nodes [ 1 ] . walletlock ( )
2019-09-25 11:34:51 +02:00
assert_raises_rpc_error ( - 13 , " walletpassphrase " , self . nodes [ 1 ] . sendtoaddress , self . nodes [ 0 ] . getnewaddress ( ) , 12 )
2015-04-25 03:26:30 +02:00
oldBalance = self . nodes [ 0 ] . getbalance ( )
inputs = [ ]
2016-03-06 16:14:39 +01:00
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 11 }
2017-03-27 09:10:37 +02:00
rawtx = self . nodes [ 1 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 1 ] . fundrawtransaction ( rawtx )
2015-04-25 03:26:30 +02:00
2019-11-01 16:06:12 +01:00
# Now we need to unlock.
2016-12-10 18:47:33 +01:00
self . nodes [ 1 ] . walletpassphrase ( " test " , 600 )
2018-02-20 03:29:22 +01:00
signedTx = self . nodes [ 1 ] . signrawtransactionwithwallet ( fundedTx [ ' hex ' ] )
2019-08-01 00:03:43 +02:00
self . nodes [ 1 ] . sendrawtransaction ( signedTx [ ' hex ' ] )
2015-04-25 03:26:30 +02:00
self . nodes [ 1 ] . generate ( 1 )
self . sync_all ( )
2019-11-01 16:06:12 +01:00
# Make sure funds are received at node1.
2016-03-06 16:14:39 +01:00
assert_equal ( oldBalance + Decimal ( ' 511.0000000 ' ) , self . nodes [ 0 ] . getbalance ( ) )
2015-04-25 03:26:30 +02:00
2019-08-01 00:03:43 +02:00
def test_many_inputs_fee ( self ) :
2019-11-01 16:06:12 +01:00
""" Multiple (~19) inputs tx test | Compare fee. """
self . log . info ( " Test fundrawtxn fee with many inputs " )
2015-04-25 03:26:30 +02:00
2019-11-01 16:06:12 +01:00
# Empty node1, send some small coins from node0 to node1.
2015-12-02 18:12:23 +01:00
self . nodes [ 1 ] . sendtoaddress ( self . nodes [ 0 ] . getnewaddress ( ) , self . nodes [ 1 ] . getbalance ( ) , " " , " " , True )
2019-11-06 21:18:34 +01:00
self . nodes [ 1 ] . generate ( 1 )
2015-04-25 03:26:30 +02:00
self . sync_all ( )
2020-08-11 02:50:34 +02:00
for _ in range ( 20 ) :
2015-12-02 18:12:23 +01:00
self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 1 ] . getnewaddress ( ) , 0.01 )
2015-04-25 03:26:30 +02:00
self . nodes [ 0 ] . generate ( 1 )
self . sync_all ( )
2019-11-01 16:06:12 +01:00
# Fund a tx with ~20 small inputs.
2015-04-25 03:26:30 +02:00
inputs = [ ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 0.15 , self . nodes [ 0 ] . getnewaddress ( ) : 0.04 }
2017-03-27 09:10:37 +02:00
rawtx = self . nodes [ 1 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 1 ] . fundrawtransaction ( rawtx )
2015-04-25 03:26:30 +02:00
2019-11-01 16:06:12 +01:00
# Create same transaction over sendtoaddress.
2015-12-02 18:12:23 +01:00
txId = self . nodes [ 1 ] . sendmany ( " " , outputs )
2015-04-25 03:26:30 +02:00
signedFee = self . nodes [ 1 ] . getrawmempool ( True ) [ txId ] [ ' fee ' ]
2019-11-01 16:06:12 +01:00
# Compare fee.
2015-12-02 18:12:23 +01:00
feeDelta = Decimal ( fundedTx [ ' fee ' ] ) - Decimal ( signedFee )
2019-08-01 00:03:43 +02:00
assert feeDelta > = 0 and feeDelta < = self . fee_tolerance * 19 #~19 inputs
2015-04-25 03:26:30 +02:00
2019-08-01 00:03:43 +02:00
def test_many_inputs_send ( self ) :
2019-11-01 16:06:12 +01:00
""" Multiple (~19) inputs tx test | sign/send. """
self . log . info ( " Test fundrawtxn sign+send with many inputs " )
2015-04-25 03:26:30 +02:00
2019-11-01 16:06:12 +01:00
# Again, empty node1, send some small coins from node0 to node1.
2015-12-02 18:12:23 +01:00
self . nodes [ 1 ] . sendtoaddress ( self . nodes [ 0 ] . getnewaddress ( ) , self . nodes [ 1 ] . getbalance ( ) , " " , " " , True )
2019-11-06 21:18:34 +01:00
self . nodes [ 1 ] . generate ( 1 )
2015-04-25 03:26:30 +02:00
self . sync_all ( )
2020-08-11 02:50:34 +02:00
for _ in range ( 20 ) :
2015-12-02 18:12:23 +01:00
self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 1 ] . getnewaddress ( ) , 0.01 )
2015-04-25 03:26:30 +02:00
self . nodes [ 0 ] . generate ( 1 )
self . sync_all ( )
2019-11-01 16:06:12 +01:00
# Fund a tx with ~20 small inputs.
2015-04-25 03:26:30 +02:00
oldBalance = self . nodes [ 0 ] . getbalance ( )
inputs = [ ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 0.15 , self . nodes [ 0 ] . getnewaddress ( ) : 0.04 }
2017-03-27 09:10:37 +02:00
rawtx = self . nodes [ 1 ] . createrawtransaction ( inputs , outputs )
fundedTx = self . nodes [ 1 ] . fundrawtransaction ( rawtx )
2018-02-20 03:29:22 +01:00
fundedAndSignedTx = self . nodes [ 1 ] . signrawtransactionwithwallet ( fundedTx [ ' hex ' ] )
2019-08-01 00:03:43 +02:00
self . nodes [ 1 ] . sendrawtransaction ( fundedAndSignedTx [ ' hex ' ] )
2019-11-06 21:18:34 +01:00
self . nodes [ 1 ] . generate ( 1 )
2015-04-25 03:26:30 +02:00
self . sync_all ( )
2016-03-06 16:14:39 +01:00
assert_equal ( oldBalance + Decimal ( ' 500.19000000 ' ) , self . nodes [ 0 ] . getbalance ( ) ) #0.19+block reward
2015-04-25 03:26:30 +02:00
2019-08-01 00:03:43 +02:00
def test_op_return ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn with OP_RETURN and no vin " )
2015-03-25 10:04:02 +01: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-08-01 00:03:43 +02:00
def test_watchonly ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn using only watchonly " )
2015-04-24 06:42:49 +02:00
inputs = [ ]
2019-08-01 00:03:43 +02:00
outputs = { self . nodes [ 2 ] . getnewaddress ( ) : self . watchonly_amount / 2 }
2015-04-24 06:42:49 +02:00
rawtx = self . nodes [ 3 ] . createrawtransaction ( inputs , outputs )
2016-04-15 16:23:16 +02:00
result = self . nodes [ 3 ] . fundrawtransaction ( rawtx , { ' includeWatching ' : True } )
2015-04-24 06:42:49 +02:00
res_dec = self . nodes [ 0 ] . decoderawtransaction ( result [ " hex " ] )
assert_equal ( len ( res_dec [ " vin " ] ) , 1 )
2019-08-01 00:03:43 +02:00
assert_equal ( res_dec [ " vin " ] [ 0 ] [ " txid " ] , self . watchonly_txid )
2015-04-24 06:42:49 +02:00
2021-08-27 21:03:02 +02:00
assert " fee " in result . keys ( )
2015-04-24 06:42:49 +02:00
assert_greater_than ( result [ " changepos " ] , - 1 )
2019-08-01 00:03:43 +02:00
def test_all_watched_funds ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn using entirety of watched funds " )
2015-04-24 06:42:49 +02:00
inputs = [ ]
2019-08-01 00:03:43 +02:00
outputs = { self . nodes [ 2 ] . getnewaddress ( ) : self . watchonly_amount }
2015-04-24 06:42:49 +02:00
rawtx = self . nodes [ 3 ] . createrawtransaction ( inputs , outputs )
2019-11-01 16:06:12 +01:00
# Backward compatibility test (2nd param is includeWatching).
2015-04-24 06:42:49 +02:00
result = self . nodes [ 3 ] . fundrawtransaction ( rawtx , True )
res_dec = self . nodes [ 0 ] . decoderawtransaction ( result [ " hex " ] )
assert_equal ( len ( res_dec [ " vin " ] ) , 2 )
2019-08-01 00:03:43 +02:00
assert res_dec [ " vin " ] [ 0 ] [ " txid " ] == self . watchonly_txid or res_dec [ " vin " ] [ 1 ] [ " txid " ] == self . watchonly_txid
2015-04-24 06:42:49 +02:00
assert_greater_than ( result [ " fee " ] , 0 )
assert_greater_than ( result [ " changepos " ] , - 1 )
2019-08-01 00:03:43 +02:00
assert_equal ( result [ " fee " ] + res_dec [ " vout " ] [ result [ " changepos " ] ] [ " value " ] , self . watchonly_amount / 10 )
2015-04-24 06:42:49 +02:00
2018-02-20 03:29:22 +01:00
signedtx = self . nodes [ 3 ] . signrawtransactionwithwallet ( result [ " hex " ] )
2021-08-27 21:03:02 +02:00
assert not signedtx [ " complete " ]
2018-02-20 03:29:22 +01:00
signedtx = self . nodes [ 0 ] . signrawtransactionwithwallet ( signedtx [ " hex " ] )
2021-08-27 21:03:02 +02:00
assert signedtx [ " complete " ]
2015-04-24 06:42:49 +02:00
self . nodes [ 0 ] . sendrawtransaction ( signedtx [ " hex " ] )
2016-06-14 08:23:31 +02:00
self . nodes [ 0 ] . generate ( 1 )
self . sync_all ( )
2019-08-01 00:03:43 +02:00
def test_option_feerate ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn feeRate option " )
2016-06-14 08:23:31 +02:00
2019-11-01 16:06:12 +01:00
# Make sure there is exactly one input so coin selection can't skew the result.
2016-06-14 08:23:31 +02:00
assert_equal ( len ( self . nodes [ 3 ] . listunspent ( 1 ) ) , 1 )
2015-04-24 06:42:49 +02:00
2016-06-03 15:31:49 +02:00
inputs = [ ]
2017-01-20 14:32:09 +01:00
outputs = { self . nodes [ 3 ] . getnewaddress ( ) : 1 }
2016-06-03 15:31:49 +02:00
rawtx = self . nodes [ 3 ] . createrawtransaction ( inputs , outputs )
2019-08-01 00:03:43 +02: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 } )
2024-01-25 07:53:18 +01:00
assert_raises_rpc_error ( - 4 , " Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate) " , self . nodes [ 3 ] . fundrawtransaction , rawtx , { " feeRate " : 1 } )
2016-06-14 08:23:31 +02: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 06:42:49 +02:00
2019-08-01 00:03:43 +02:00
def test_address_reuse ( self ) :
2019-11-01 16:06:12 +01:00
""" Test no address reuse occurs. """
self . log . info ( " Test fundrawtxn does not reuse addresses " )
2017-01-20 14:32:09 +01:00
2019-08-01 00:03:43 +02:00
rawtx = self . nodes [ 3 ] . createrawtransaction ( inputs = [ ] , outputs = { self . nodes [ 3 ] . getnewaddress ( ) : 1 } )
2017-01-20 14:32:09 +01: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 ]
2021-08-27 21:03:02 +02:00
assert changeaddress != " "
2017-01-20 14:32:09 +01:00
nextaddr = self . nodes [ 3 ] . getnewaddress ( )
2019-11-01 16:06:12 +01:00
# Now the change address key should be removed from the keypool.
2021-08-27 21:03:02 +02:00
assert changeaddress != nextaddr
2017-01-20 14:32:09 +01:00
2019-08-01 00:03:43 +02:00
def test_option_subtract_fee_from_outputs ( self ) :
2019-11-01 16:06:12 +01:00
self . log . info ( " Test fundrawtxn subtractFeeFromOutputs option " )
2017-01-12 12:49:06 +01:00
2019-11-01 16:06:12 +01:00
# Make sure there is exactly one input so coin selection can't skew the result.
2017-01-12 12:49:06 +01: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-08-01 00:03:43 +02: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 ] } ) , ]
2017-01-12 12:49:06 +01:00
2018-02-08 15:52:01 +01:00
dec_tx = [ self . nodes [ 3 ] . decoderawtransaction ( tx_ [ ' hex ' ] ) for tx_ in result ]
2017-01-12 12:49:06 +01: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 )
2019-09-22 22:47:17 +02:00
# Add changePosition=4 to circumvent BIP69 input/output sorting
result = [ self . nodes [ 3 ] . fundrawtransaction ( rawtx , { " changePosition " : 4 } ) ,
2019-11-01 16:06:12 +01:00
# Split the fee between outputs 0, 2, and 3, but not output 1.
2019-09-22 22:47:17 +02:00
self . nodes [ 3 ] . fundrawtransaction ( rawtx , { " subtractFeeFromOutputs " : [ 0 , 2 , 3 ] , " changePosition " : 4 } ) ]
2017-01-12 12:49:06 +01:00
dec_tx = [ self . nodes [ 3 ] . decoderawtransaction ( result [ 0 ] [ ' hex ' ] ) ,
self . nodes [ 3 ] . decoderawtransaction ( result [ 1 ] [ ' hex ' ] ) ]
2019-11-01 16:06:12 +01:00
# Nested list of non-change output amounts for each transaction.
2017-01-12 12:49:06 +01: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 16:06:12 +01:00
# List of differences in output amounts between normal and subtractFee transactions.
2017-01-12 12:49:06 +01:00
share = [ o0 - o1 for o0 , o1 in zip ( output [ 0 ] , output [ 1 ] ) ]
2019-11-01 16:06:12 +01:00
# Output 1 is the same in both transactions.
2017-01-12 12:49:06 +01:00
assert_equal ( share [ 1 ] , 0 )
2019-11-01 16:06:12 +01:00
# The other 3 outputs are smaller as a result of subtractFeeFromOutputs.
2017-01-12 12:49:06 +01:00
assert_greater_than ( share [ 0 ] , 0 )
assert_greater_than ( share [ 2 ] , 0 )
assert_greater_than ( share [ 3 ] , 0 )
2019-11-01 16:06:12 +01:00
# Outputs 2 and 3 take the same share of the fee.
2017-01-12 12:49:06 +01:00
assert_equal ( share [ 2 ] , share [ 3 ] )
2019-11-01 16:06:12 +01:00
# Output 0 takes at least as much share of the fee, and no more than 2
# satoshis more, than outputs 2 and 3.
2017-01-12 12:49:06 +01: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 16:06:12 +01:00
# The fee is the same in both transactions.
2017-01-12 12:49:06 +01:00
assert_equal ( result [ 0 ] [ ' fee ' ] , result [ 1 ] [ ' fee ' ] )
2019-11-01 16:06:12 +01:00
# The total subtracted from the outputs is equal to the fee.
2017-01-12 12:49:06 +01:00
assert_equal ( share [ 0 ] + share [ 2 ] + share [ 3 ] , result [ 0 ] [ ' fee ' ] )
2019-12-01 17:56:52 +01: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-25 03:26:30 +02:00
if __name__ == ' __main__ ' :
RawTransactionsTest ( ) . main ( )