2016-05-06 11:23:48 +02:00
#!/usr/bin/env python3
# Copyright (c) 2014-2016 The Bitcoin Core developers
2014-12-29 20:17:21 +01:00
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-08-16 00:35:19 +02:00
""" Test the rawtransaction RPCs.
2014-12-29 20:17:21 +01:00
2019-01-07 10:55:35 +01:00
Test the following RPCs :
- createrawtransaction
- signrawtransaction
- sendrawtransaction
- decoderawtransaction
- getrawtransaction
2016-11-23 07:13:35 +01:00
"""
2014-12-29 20:17:21 +01:00
2015-05-02 13:58:10 +02:00
from test_framework . test_framework import BitcoinTestFramework
from test_framework . util import *
2014-12-29 20:17:21 +01:00
2017-12-13 17:12:12 +01:00
class multidict ( dict ) :
""" Dictionary that allows duplicate keys.
Constructed with a list of ( key , value ) tuples . When dumped by the json module ,
will output invalid json with repeated keys , eg :
>> > json . dumps ( multidict ( [ ( 1 , 2 ) , ( 1 , 2 ) ] )
' { " 1 " : 2, " 1 " : 2} '
Used to test calls to rpc methods with repeated keys in the json object . """
def __init__ ( self , x ) :
dict . __init__ ( self , x )
self . x = x
def items ( self ) :
return self . x
2014-12-29 20:17:21 +01:00
# Create one-input, one-output, no-fee transaction:
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 . setup_clean_chain = True
self . num_nodes = 3
2014-12-29 20:17:21 +01:00
def setup_network ( self , split = False ) :
2017-05-02 20:02:55 +02:00
super ( ) . setup_network ( )
2014-12-29 20:17:21 +01:00
connect_nodes_bi ( self . nodes , 0 , 2 )
2015-04-01 15:08:00 +02:00
2014-12-29 20:17:21 +01:00
def run_test ( self ) :
2015-04-01 15:08:00 +02:00
2014-12-29 20:17:21 +01:00
#prepare some coins for multiple *rawtransaction commands
self . nodes [ 2 ] . generate ( 1 )
2015-07-10 20:11:44 +02:00
self . sync_all ( )
2014-12-29 20:17:21 +01:00
self . nodes [ 0 ] . generate ( 101 )
self . sync_all ( )
2015-12-02 18:12:23 +01: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 )
2014-12-29 20:17:21 +01:00
self . sync_all ( )
self . nodes [ 0 ] . generate ( 5 )
self . sync_all ( )
2018-01-30 09:59:22 +01:00
# Test getrawtransaction on genesis block coinbase returns an error
block = self . nodes [ 0 ] . getblock ( self . nodes [ 0 ] . getblockhash ( 0 ) )
assert_raises_rpc_error ( - 5 , " The genesis block coinbase is not considered an ordinary transaction " , self . nodes [ 0 ] . getrawtransaction , block [ ' merkleroot ' ] )
2017-12-13 17:12:12 +01:00
# Test `createrawtransaction` required parameters
assert_raises_rpc_error ( - 1 , " createrawtransaction " , self . nodes [ 0 ] . createrawtransaction )
assert_raises_rpc_error ( - 1 , " createrawtransaction " , self . nodes [ 0 ] . createrawtransaction , [ ] )
# Test `createrawtransaction` invalid extra parameters
assert_raises_rpc_error ( - 1 , " createrawtransaction " , self . nodes [ 0 ] . createrawtransaction , [ ] , { } , 0 , False , ' foo ' )
# Test `createrawtransaction` invalid `inputs`
txid = ' 1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000 '
assert_raises_rpc_error ( - 3 , " Expected type array " , self . nodes [ 0 ] . createrawtransaction , ' foo ' , { } )
assert_raises_rpc_error ( - 1 , " JSON value is not an object as expected " , self . nodes [ 0 ] . createrawtransaction , [ ' foo ' ] , { } )
assert_raises_rpc_error ( - 8 , " txid must be hexadecimal string " , self . nodes [ 0 ] . createrawtransaction , [ { } ] , { } )
assert_raises_rpc_error ( - 8 , " txid must be hexadecimal string " , self . nodes [ 0 ] . createrawtransaction , [ { ' txid ' : ' foo ' } ] , { } )
assert_raises_rpc_error ( - 8 , " Invalid parameter, missing vout key " , self . nodes [ 0 ] . createrawtransaction , [ { ' txid ' : txid } ] , { } )
assert_raises_rpc_error ( - 8 , " Invalid parameter, missing vout key " , self . nodes [ 0 ] . createrawtransaction , [ { ' txid ' : txid , ' vout ' : ' foo ' } ] , { } )
assert_raises_rpc_error ( - 8 , " Invalid parameter, vout must be positive " , self . nodes [ 0 ] . createrawtransaction , [ { ' txid ' : txid , ' vout ' : - 1 } ] , { } )
assert_raises_rpc_error ( - 8 , " Invalid parameter, sequence number is out of range " , self . nodes [ 0 ] . createrawtransaction , [ { ' txid ' : txid , ' vout ' : 0 , ' sequence ' : - 1 } ] , { } )
# Test `createrawtransaction` invalid `outputs`
address = self . nodes [ 0 ] . getnewaddress ( )
assert_raises_rpc_error ( - 3 , " Expected type object " , self . nodes [ 0 ] . createrawtransaction , [ ] , ' foo ' )
assert_raises_rpc_error ( - 8 , " Data must be hexadecimal string " , self . nodes [ 0 ] . createrawtransaction , [ ] , { ' data ' : ' foo ' } )
2020-01-31 16:38:47 +01:00
assert_raises_rpc_error ( - 5 , " Invalid Dash address " , self . nodes [ 0 ] . createrawtransaction , [ ] , { ' foo ' : 0 } )
2017-12-13 17:12:12 +01:00
assert_raises_rpc_error ( - 3 , " Invalid amount " , self . nodes [ 0 ] . createrawtransaction , [ ] , { address : ' foo ' } )
assert_raises_rpc_error ( - 3 , " Amount out of range " , self . nodes [ 0 ] . createrawtransaction , [ ] , { address : - 1 } )
assert_raises_rpc_error ( - 8 , " Invalid parameter, duplicated address: %s " % address , self . nodes [ 0 ] . createrawtransaction , [ ] , multidict ( [ ( address , 1 ) , ( address , 1 ) ] ) )
# Test `createrawtransaction` invalid `locktime`
assert_raises_rpc_error ( - 3 , " Expected type number " , self . nodes [ 0 ] . createrawtransaction , [ ] , { } , ' foo ' )
assert_raises_rpc_error ( - 8 , " Invalid parameter, locktime out of range " , self . nodes [ 0 ] . createrawtransaction , [ ] , { } , - 1 )
assert_raises_rpc_error ( - 8 , " Invalid parameter, locktime out of range " , self . nodes [ 0 ] . createrawtransaction , [ ] , { } , 4294967296 )
2014-12-29 20:17:21 +01:00
#########################################
# sendrawtransaction with missing input #
#########################################
inputs = [ { ' txid ' : " 1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000 " , ' vout ' : 1 } ] #won't exists
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 4.998 }
rawtx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
rawtx = self . nodes [ 2 ] . signrawtransaction ( rawtx )
2015-04-01 15:08:00 +02:00
2017-03-09 10:02:13 +01:00
# This will raise an exception since there are missing inputs
2019-09-25 11:34:51 +02:00
assert_raises_rpc_error ( - 25 , " Missing inputs " , self . nodes [ 2 ] . sendrawtransaction , rawtx [ ' hex ' ] )
2015-04-01 15:08:00 +02:00
#########################
# RAW TX MULTISIG TESTS #
#########################
# 2of2 test
addr1 = self . nodes [ 2 ] . getnewaddress ( )
addr2 = self . nodes [ 2 ] . getnewaddress ( )
addr1Obj = self . nodes [ 2 ] . validateaddress ( addr1 )
addr2Obj = self . nodes [ 2 ] . validateaddress ( addr2 )
mSigObj = self . nodes [ 2 ] . addmultisigaddress ( 2 , [ addr1Obj [ ' pubkey ' ] , addr2Obj [ ' pubkey ' ] ] )
#use balance deltas instead of absolute values
bal = self . nodes [ 2 ] . getbalance ( )
# send 1.2 BTC to msig adr
2015-12-02 18:12:23 +01:00
txId = self . nodes [ 0 ] . sendtoaddress ( mSigObj , 1.2 )
2015-04-01 15:08:00 +02:00
self . sync_all ( )
self . nodes [ 0 ] . generate ( 1 )
self . sync_all ( )
assert_equal ( self . nodes [ 2 ] . getbalance ( ) , bal + Decimal ( ' 1.20000000 ' ) ) #node2 has both keys of the 2of2 ms addr., tx should affect the balance
# 2of3 test from different nodes
bal = self . nodes [ 2 ] . getbalance ( )
addr1 = self . nodes [ 1 ] . getnewaddress ( )
addr2 = self . nodes [ 2 ] . getnewaddress ( )
addr3 = self . nodes [ 2 ] . getnewaddress ( )
addr1Obj = self . nodes [ 1 ] . validateaddress ( addr1 )
addr2Obj = self . nodes [ 2 ] . validateaddress ( addr2 )
addr3Obj = self . nodes [ 2 ] . validateaddress ( addr3 )
mSigObj = self . nodes [ 2 ] . addmultisigaddress ( 2 , [ addr1Obj [ ' pubkey ' ] , addr2Obj [ ' pubkey ' ] , addr3Obj [ ' pubkey ' ] ] )
2015-12-02 18:12:23 +01:00
txId = self . nodes [ 0 ] . sendtoaddress ( mSigObj , 2.2 )
2015-04-01 15:08:00 +02:00
decTx = self . nodes [ 0 ] . gettransaction ( txId )
rawTx = self . nodes [ 0 ] . decoderawtransaction ( decTx [ ' hex ' ] )
self . sync_all ( )
self . nodes [ 0 ] . generate ( 1 )
self . sync_all ( )
#THIS IS A INCOMPLETE FEATURE
#NODE2 HAS TWO OF THREE KEY AND THE FUNDS SHOULD BE SPENDABLE AND COUNT AT BALANCE CALCULATION
assert_equal ( self . nodes [ 2 ] . getbalance ( ) , bal ) #for now, assume the funds of a 2of3 multisig tx are not marked as spendable
txDetails = self . nodes [ 0 ] . gettransaction ( txId , True )
rawTx = self . nodes [ 0 ] . decoderawtransaction ( txDetails [ ' hex ' ] )
vout = False
for outpoint in rawTx [ ' vout ' ] :
if outpoint [ ' value ' ] == Decimal ( ' 2.20000000 ' ) :
vout = outpoint
2015-12-02 18:12:23 +01:00
break
2015-04-01 15:08:00 +02:00
bal = self . nodes [ 0 ] . getbalance ( )
inputs = [ { " txid " : txId , " vout " : vout [ ' n ' ] , " scriptPubKey " : vout [ ' scriptPubKey ' ] [ ' hex ' ] } ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 2.19 }
rawTx = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
rawTxPartialSigned = self . nodes [ 1 ] . signrawtransaction ( rawTx , inputs )
assert_equal ( rawTxPartialSigned [ ' complete ' ] , False ) #node1 only has one key, can't comp. sign the tx
2017-07-20 16:32:47 +02:00
2015-04-01 15:08:00 +02:00
rawTxSigned = self . nodes [ 2 ] . signrawtransaction ( rawTx , inputs )
assert_equal ( rawTxSigned [ ' complete ' ] , True ) #node2 can sign the tx compl., own two of three keys
self . nodes [ 2 ] . sendrawtransaction ( rawTxSigned [ ' hex ' ] )
rawTx = self . nodes [ 0 ] . decoderawtransaction ( rawTxSigned [ ' hex ' ] )
self . sync_all ( )
self . nodes [ 0 ] . generate ( 1 )
self . sync_all ( )
2016-03-06 16:14:39 +01:00
assert_equal ( self . nodes [ 0 ] . getbalance ( ) , bal + Decimal ( ' 500.00000000 ' ) + Decimal ( ' 2.19000000 ' ) ) #block reward + tx
2014-12-29 20:17:21 +01:00
2017-07-20 16:32:47 +02:00
# 2of2 test for combining transactions
bal = self . nodes [ 2 ] . getbalance ( )
addr1 = self . nodes [ 1 ] . getnewaddress ( )
addr2 = self . nodes [ 2 ] . getnewaddress ( )
addr1Obj = self . nodes [ 1 ] . validateaddress ( addr1 )
addr2Obj = self . nodes [ 2 ] . validateaddress ( addr2 )
self . nodes [ 1 ] . addmultisigaddress ( 2 , [ addr1Obj [ ' pubkey ' ] , addr2Obj [ ' pubkey ' ] ] )
mSigObj = self . nodes [ 2 ] . addmultisigaddress ( 2 , [ addr1Obj [ ' pubkey ' ] , addr2Obj [ ' pubkey ' ] ] )
mSigObjValid = self . nodes [ 2 ] . validateaddress ( mSigObj )
txId = self . nodes [ 0 ] . sendtoaddress ( mSigObj , 2.2 )
decTx = self . nodes [ 0 ] . gettransaction ( txId )
rawTx2 = self . nodes [ 0 ] . decoderawtransaction ( decTx [ ' hex ' ] )
self . sync_all ( )
self . nodes [ 0 ] . generate ( 1 )
self . sync_all ( )
assert_equal ( self . nodes [ 2 ] . getbalance ( ) , bal ) # the funds of a 2of2 multisig tx should not be marked as spendable
txDetails = self . nodes [ 0 ] . gettransaction ( txId , True )
rawTx2 = self . nodes [ 0 ] . decoderawtransaction ( txDetails [ ' hex ' ] )
vout = False
for outpoint in rawTx2 [ ' vout ' ] :
if outpoint [ ' value ' ] == Decimal ( ' 2.20000000 ' ) :
vout = outpoint
break
bal = self . nodes [ 0 ] . getbalance ( )
inputs = [ { " txid " : txId , " vout " : vout [ ' n ' ] , " scriptPubKey " : vout [ ' scriptPubKey ' ] [ ' hex ' ] , " redeemScript " : mSigObjValid [ ' hex ' ] } ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 2.19 }
rawTx2 = self . nodes [ 2 ] . createrawtransaction ( inputs , outputs )
rawTxPartialSigned1 = self . nodes [ 1 ] . signrawtransaction ( rawTx2 , inputs )
self . log . info ( rawTxPartialSigned1 )
assert_equal ( rawTxPartialSigned [ ' complete ' ] , False ) #node1 only has one key, can't comp. sign the tx
rawTxPartialSigned2 = self . nodes [ 2 ] . signrawtransaction ( rawTx2 , inputs )
self . log . info ( rawTxPartialSigned2 )
assert_equal ( rawTxPartialSigned2 [ ' complete ' ] , False ) #node2 only has one key, can't comp. sign the tx
rawTxComb = self . nodes [ 2 ] . combinerawtransaction ( [ rawTxPartialSigned1 [ ' hex ' ] , rawTxPartialSigned2 [ ' hex ' ] ] )
self . log . info ( rawTxComb )
self . nodes [ 2 ] . sendrawtransaction ( rawTxComb )
rawTx2 = self . nodes [ 0 ] . decoderawtransaction ( rawTxComb )
self . sync_all ( )
self . nodes [ 0 ] . generate ( 1 )
self . sync_all ( )
2019-09-22 23:01:49 +02:00
assert_equal ( self . nodes [ 0 ] . getbalance ( ) , bal + Decimal ( ' 500.00000000 ' ) + Decimal ( ' 2.19000000 ' ) ) #block reward + tx
2017-07-20 16:32:47 +02:00
2016-11-23 07:13:35 +01:00
# getrawtransaction tests
# 1. valid parameters - only supply txid
2018-01-15 08:26:15 +01:00
txHash = rawTx [ " txid " ]
2016-11-23 07:13:35 +01:00
assert_equal ( self . nodes [ 0 ] . getrawtransaction ( txHash ) , rawTxSigned [ ' hex ' ] )
# 2. valid parameters - supply txid and 0 for non-verbose
assert_equal ( self . nodes [ 0 ] . getrawtransaction ( txHash , 0 ) , rawTxSigned [ ' hex ' ] )
# 3. valid parameters - supply txid and False for non-verbose
assert_equal ( self . nodes [ 0 ] . getrawtransaction ( txHash , False ) , rawTxSigned [ ' hex ' ] )
# 4. valid parameters - supply txid and 1 for verbose.
# We only check the "hex" field of the output so we don't need to update this test every time the output format changes.
assert_equal ( self . nodes [ 0 ] . getrawtransaction ( txHash , 1 ) [ " hex " ] , rawTxSigned [ ' hex ' ] )
# 5. valid parameters - supply txid and True for non-verbose
assert_equal ( self . nodes [ 0 ] . getrawtransaction ( txHash , True ) [ " hex " ] , rawTxSigned [ ' hex ' ] )
# 6. invalid parameters - supply txid and string "Flase"
2019-09-25 11:34:51 +02:00
assert_raises_rpc_error ( - 3 , " Invalid type " , self . nodes [ 0 ] . getrawtransaction , txHash , " Flase " )
2016-11-23 07:13:35 +01:00
# 7. invalid parameters - supply txid and empty array
2019-09-25 11:34:51 +02:00
assert_raises_rpc_error ( - 3 , " Invalid type " , self . nodes [ 0 ] . getrawtransaction , txHash , [ ] )
2016-11-23 07:13:35 +01:00
# 8. invalid parameters - supply txid and empty dict
2019-09-25 11:34:51 +02:00
assert_raises_rpc_error ( - 3 , " Invalid type " , self . nodes [ 0 ] . getrawtransaction , txHash , { } )
2016-11-23 07:13:35 +01:00
2016-06-07 18:25:10 +02:00
inputs = [ { ' txid ' : " 1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000 " , ' vout ' : 1 , ' sequence ' : 1000 } ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 1 }
rawtx = self . nodes [ 0 ] . createrawtransaction ( inputs , outputs )
decrawtx = self . nodes [ 0 ] . decoderawtransaction ( rawtx )
assert_equal ( decrawtx [ ' vin ' ] [ 0 ] [ ' sequence ' ] , 1000 )
2017-07-20 16:32:47 +02:00
2017-03-09 10:02:13 +01:00
# 9. invalid parameters - sequence number out of range
2016-06-16 11:05:32 +02:00
inputs = [ { ' txid ' : " 1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000 " , ' vout ' : 1 , ' sequence ' : - 1 } ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 1 }
2019-09-25 11:34:51 +02:00
assert_raises_rpc_error ( - 8 , ' Invalid parameter, sequence number is out of range ' , self . nodes [ 0 ] . createrawtransaction , inputs , outputs )
2017-07-20 16:32:47 +02:00
2017-03-09 10:02:13 +01:00
# 10. invalid parameters - sequence number out of range
2016-06-16 11:05:32 +02:00
inputs = [ { ' txid ' : " 1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000 " , ' vout ' : 1 , ' sequence ' : 4294967296 } ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 1 }
2019-09-25 11:34:51 +02:00
assert_raises_rpc_error ( - 8 , ' Invalid parameter, sequence number is out of range ' , self . nodes [ 0 ] . createrawtransaction , inputs , outputs )
2017-07-20 16:32:47 +02:00
2016-06-16 11:05:32 +02:00
inputs = [ { ' txid ' : " 1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000 " , ' vout ' : 1 , ' sequence ' : 4294967294 } ]
outputs = { self . nodes [ 0 ] . getnewaddress ( ) : 1 }
rawtx = self . nodes [ 0 ] . createrawtransaction ( inputs , outputs )
decrawtx = self . nodes [ 0 ] . decoderawtransaction ( rawtx )
assert_equal ( decrawtx [ ' vin ' ] [ 0 ] [ ' sequence ' ] , 4294967294 )
2016-06-07 18:25:10 +02:00
2014-12-29 20:17:21 +01:00
if __name__ == ' __main__ ' :
RawTransactionsTest ( ) . main ( )