2012-05-31 16:01:16 -04:00
// Copyright (c) 2010 Satoshi Nakamoto
2019-02-02 19:48:54 -08:00
// Copyright (c) 2009-2019 The Bitcoin Core developers
2014-11-20 10:19:29 +08:00
// Distributed under the MIT software license, see the accompanying
2012-05-31 16:01:16 -04:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-11-10 13:57:53 +13:00
# include <chain.h>
# include <coins.h>
2018-06-28 19:04:40 -07:00
# include <compat/byteswap.h>
2019-02-25 14:54:22 -05:00
# include <consensus/validation.h>
2017-11-10 13:57:53 +13:00
# include <core_io.h>
2017-12-08 11:41:35 -08:00
# include <index/txindex.h>
2017-09-19 18:12:25 -07:00
# include <key_io.h>
2017-11-10 13:57:53 +13:00
# include <merkleblock.h>
2019-04-10 13:38:41 +00:00
# include <node/coin.h>
2019-04-08 16:33:05 -04:00
# include <node/psbt.h>
2019-01-08 22:16:50 -08:00
# include <node/transaction.h>
2019-08-02 02:03:01 +09:00
# include <policy/policy.h>
2017-11-10 13:57:53 +13:00
# include <policy/rbf.h>
# include <primitives/transaction.h>
2019-01-09 02:06:29 -08:00
# include <psbt.h>
2019-07-31 18:02:24 -04:00
# include <random.h>
2019-04-02 16:51:32 -04:00
# include <rpc/rawtransaction_util.h>
2017-11-10 13:57:53 +13:00
# include <rpc/server.h>
2017-05-30 15:55:17 -04:00
# include <rpc/util.h>
2017-11-10 13:57:53 +13:00
# include <script/script.h>
# include <script/script_error.h>
# include <script/sign.h>
2019-06-06 22:52:24 +02:00
# include <script/signingprovider.h>
2017-11-10 13:57:53 +13:00
# include <script/standard.h>
# include <uint256.h>
2018-06-27 17:21:07 +09:00
# include <util/moneystr.h>
2018-10-22 15:51:11 -07:00
# include <util/strencodings.h>
2018-11-06 10:40:50 -05:00
# include <validation.h>
# include <validationinterface.h>
2012-05-31 16:01:16 -04:00
2018-07-31 17:58:01 -07:00
# include <numeric>
2013-04-13 00:13:08 -05:00
# include <stdint.h>
2015-09-04 16:11:34 +02:00
# include <univalue.h>
2015-05-18 14:02:18 +02:00
2019-08-02 02:03:01 +09:00
/** High fee rate for sendrawtransaction and testmempoolaccept.
* By default , transaction with a fee rate higher than this will be rejected by
* the RPCs . This can be overridden with the maxfeerate argument .
2019-03-20 13:15:05 -04:00
*/
2019-08-02 02:03:01 +09:00
static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE { COIN / 10 } ;
2012-05-31 16:01:16 -04:00
2018-05-02 17:14:48 +02:00
static void TxToJSON ( const CTransaction & tx , const uint256 hashBlock , UniValue & entry )
2012-05-31 16:01:16 -04:00
{
2016-09-21 20:51:00 -04:00
// Call into TxToUniv() in bitcoin-common to decode the transaction hex.
//
// Blockchain contextual information (confirmations and blocktime) is not
// available to code in bitcoin-common, so we query them here and push the
// data into the returned UniValue.
2017-08-11 12:21:14 -07:00
TxToUniv ( tx , uint256 ( ) , entry , true , RPCSerializationFlags ( ) ) ;
2012-05-31 16:01:16 -04:00
2014-12-15 09:11:16 +01:00
if ( ! hashBlock . IsNull ( ) ) {
2017-12-08 11:49:08 -08:00
LOCK ( cs_main ) ;
2017-09-22 20:04:07 +02:00
entry . pushKV ( " blockhash " , hashBlock . GetHex ( ) ) ;
2018-01-12 00:23:09 +00:00
CBlockIndex * pindex = LookupBlockIndex ( hashBlock ) ;
if ( pindex ) {
2019-03-27 11:14:25 -04:00
if ( : : ChainActive ( ) . Contains ( pindex ) ) {
entry . pushKV ( " confirmations " , 1 + : : ChainActive ( ) . Height ( ) - pindex - > nHeight ) ;
2017-09-22 20:04:07 +02:00
entry . pushKV ( " time " , pindex - > GetBlockTime ( ) ) ;
entry . pushKV ( " blocktime " , pindex - > GetBlockTime ( ) ) ;
2012-05-31 16:01:16 -04:00
}
else
2017-09-22 20:04:07 +02:00
entry . pushKV ( " confirmations " , 0 ) ;
2012-05-31 16:01:16 -04:00
}
}
}
2018-05-02 17:14:48 +02:00
static UniValue getrawtransaction ( const JSONRPCRequest & request )
2012-05-31 16:01:16 -04:00
{
2019-06-19 13:59:11 +09:00
RPCHelpMan {
2019-02-02 19:48:54 -08:00
" getrawtransaction " ,
" \n Return the raw transaction data. \n "
2019-01-26 14:34:00 -08:00
" \n By default this function only works for mempool transactions. When called with a blockhash \n "
" argument, getrawtransaction will return the transaction if the specified block is available and \n "
" the transaction is found in that block. When called without a blockhash argument, getrawtransaction \n "
" will return the transaction if it is in the mempool, or if -txindex is enabled and the transaction \n "
" is in a block in the blockchain. \n "
2017-01-11 15:30:50 -08:00
2019-02-25 23:49:20 -05:00
" \n Hint: Use gettransaction for wallet transactions. \n "
2019-02-02 19:48:54 -08:00
" \n If verbose is 'true', returns an Object with information about 'txid'. \n "
" If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'. \n " ,
2018-11-23 11:21:38 -05:00
{
2018-12-10 16:56:51 -05:00
{ " txid " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The transaction id " } ,
{ " verbose " , RPCArg : : Type : : BOOL , /* default */ " false " , " If false, return a string, otherwise return a json object " } ,
{ " blockhash " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : OMITTED_NAMED_ARG , " The block in which to look for the transaction " } ,
2018-12-21 12:29:36 -05:00
} ,
{
RPCResult { " if verbose is not set or set to false " ,
2013-10-29 22:29:44 +11:00
" \" data \" (string) The serialized, hex-encoded data for 'txid' \n "
2018-12-21 12:29:36 -05:00
} ,
RPCResult { " if verbose is set to true " ,
2013-10-29 22:29:44 +11:00
" { \n "
2017-04-25 17:29:24 +09:00
" \" in_active_chain \" : b, (bool) Whether specified block is in the active chain or not (only present with explicit \" blockhash \" argument) \n "
2013-10-29 22:29:44 +11:00
" \" hex \" : \" data \" , (string) The serialized, hex-encoded data for 'txid' \n "
" \" txid \" : \" id \" , (string) The transaction id (same as provided) \n "
2016-01-23 01:46:11 +08:00
" \" hash \" : \" id \" , (string) The transaction hash (differs from txid for witness transactions) \n "
" \" size \" : n, (numeric) The serialized transaction size \n "
2016-01-03 18:54:50 +01:00
" \" vsize \" : n, (numeric) The virtual transaction size (differs from size for witness transactions) \n "
2018-03-26 11:20:56 -04:00
" \" weight \" : n, (numeric) The transaction's weight (between vsize*4-3 and vsize*4) \n "
2013-10-29 22:29:44 +11:00
" \" version \" : n, (numeric) The version \n "
" \" locktime \" : ttt, (numeric) The lock time \n "
" \" vin \" : [ (array of json objects) \n "
" { \n "
" \" txid \" : \" id \" , (string) The transaction id \n "
" \" vout \" : n, (numeric) \n "
" \" scriptSig \" : { (json object) The script \n "
" \" asm \" : \" asm \" , (string) asm \n "
" \" hex \" : \" hex \" (string) hex \n "
" }, \n "
" \" sequence \" : n (numeric) The script sequence number \n "
2016-01-23 01:46:11 +08:00
" \" txinwitness \" : [ \" hex \" , ...] (array of string) hex-encoded witness data (if any) \n "
2013-10-29 22:29:44 +11:00
" } \n "
" ,... \n "
" ], \n "
" \" vout \" : [ (array of json objects) \n "
" { \n "
2015-08-01 20:15:23 +01:00
" \" value \" : x.xxx, (numeric) The value in " + CURRENCY_UNIT + " \n "
2013-10-29 22:29:44 +11:00
" \" n \" : n, (numeric) index \n "
" \" scriptPubKey \" : { (json object) \n "
" \" asm \" : \" asm \" , (string) the asm \n "
" \" hex \" : \" hex \" , (string) the hex \n "
" \" reqSigs \" : n, (numeric) The required sigs \n "
" \" type \" : \" pubkeyhash \" , (string) The type, eg 'pubkeyhash' \n "
" \" addresses \" : [ (json array of string) \n "
2016-11-21 14:39:58 +01:00
" \" address \" (string) bitcoin address \n "
2013-10-29 22:29:44 +11:00
" ,... \n "
" ] \n "
" } \n "
" } \n "
" ,... \n "
" ], \n "
" \" blockhash \" : \" hash \" , (string) the block hash \n "
" \" confirmations \" : n, (numeric) The confirmations \n "
" \" blocktime \" : ttt (numeric) The block time in seconds since epoch (Jan 1 1970 GMT) \n "
2018-12-17 07:40:45 -06:00
" \" time \" : ttt, (numeric) Same as \" blocktime \" \n "
2013-10-29 22:29:44 +11:00
" } \n "
2018-12-21 12:29:36 -05:00
} ,
} ,
RPCExamples {
HelpExampleCli ( " getrawtransaction " , " \" mytxid \" " )
2016-10-26 13:09:54 +01:00
+ HelpExampleCli ( " getrawtransaction " , " \" mytxid \" true " )
+ HelpExampleRpc ( " getrawtransaction " , " \" mytxid \" , true " )
2017-04-25 17:29:24 +09:00
+ HelpExampleCli ( " getrawtransaction " , " \" mytxid \" false \" myblockhash \" " )
+ HelpExampleCli ( " getrawtransaction " , " \" mytxid \" true \" myblockhash \" " )
2018-12-21 12:29:36 -05:00
} ,
2019-06-19 13:59:11 +09:00
} . Check ( request ) ;
2012-05-31 16:01:16 -04:00
2017-04-25 17:29:24 +09:00
bool in_active_chain = true ;
2016-09-22 09:46:41 +02:00
uint256 hash = ParseHashV ( request . params [ 0 ] , " parameter 1 " ) ;
2017-04-25 17:29:24 +09:00
CBlockIndex * blockindex = nullptr ;
2012-05-31 16:01:16 -04:00
2018-01-27 20:10:56 +13:00
if ( hash = = Params ( ) . GenesisBlock ( ) . hashMerkleRoot ) {
// Special exception for the genesis block coinbase transaction
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved " ) ;
}
2016-10-26 13:09:54 +01:00
// Accept either a bool (true) or a num (>=1) to indicate verbose output.
2012-05-31 16:01:16 -04:00
bool fVerbose = false ;
2017-07-10 11:44:39 -04:00
if ( ! request . params [ 1 ] . isNull ( ) ) {
2017-05-06 12:49:18 +09:00
fVerbose = request . params [ 1 ] . isNum ( ) ? ( request . params [ 1 ] . get_int ( ) ! = 0 ) : request . params [ 1 ] . get_bool ( ) ;
2016-10-26 13:09:54 +01:00
}
2012-05-31 16:01:16 -04:00
2017-04-25 17:29:24 +09:00
if ( ! request . params [ 2 ] . isNull ( ) ) {
2017-12-08 11:49:08 -08:00
LOCK ( cs_main ) ;
2017-04-25 17:29:24 +09:00
uint256 blockhash = ParseHashV ( request . params [ 2 ] , " parameter 3 " ) ;
2018-01-12 00:23:09 +00:00
blockindex = LookupBlockIndex ( blockhash ) ;
if ( ! blockindex ) {
2017-12-06 10:52:29 -05:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Block hash not found " ) ;
2017-04-25 17:29:24 +09:00
}
2019-03-27 11:14:25 -04:00
in_active_chain = : : ChainActive ( ) . Contains ( blockindex ) ;
2017-04-25 17:29:24 +09:00
}
2017-12-08 11:49:08 -08:00
bool f_txindex_ready = false ;
if ( g_txindex & & ! blockindex ) {
f_txindex_ready = g_txindex - > BlockUntilSyncedToCurrentChain ( ) ;
}
2016-11-11 16:30:38 -08:00
CTransactionRef tx ;
2017-04-25 17:29:24 +09:00
uint256 hash_block ;
2019-01-26 14:34:00 -08:00
if ( ! GetTransaction ( hash , tx , Params ( ) . GetConsensus ( ) , hash_block , blockindex ) ) {
2017-04-25 17:29:24 +09:00
std : : string errmsg ;
if ( blockindex ) {
if ( ! ( blockindex - > nStatus & BLOCK_HAVE_DATA ) ) {
throw JSONRPCError ( RPC_MISC_ERROR , " Block not available " ) ;
}
errmsg = " No such transaction found in the provided block " ;
2017-12-08 11:41:35 -08:00
} else if ( ! g_txindex ) {
2019-06-14 23:00:37 +02:00
errmsg = " No such mempool transaction. Use -txindex or provide a block hash to enable blockchain transaction queries " ;
2017-12-08 11:49:08 -08:00
} else if ( ! f_txindex_ready ) {
errmsg = " No such mempool transaction. Blockchain transactions are still in the process of being indexed " ;
2017-04-25 17:29:24 +09:00
} else {
2017-12-08 11:41:35 -08:00
errmsg = " No such mempool or blockchain transaction " ;
2017-04-25 17:29:24 +09:00
}
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , errmsg + " . Use gettransaction for wallet transactions. " ) ;
}
2012-05-31 16:01:16 -04:00
2017-04-25 17:29:24 +09:00
if ( ! fVerbose ) {
2017-08-10 15:58:25 -07:00
return EncodeHexTx ( * tx , RPCSerializationFlags ( ) ) ;
2017-04-25 17:29:24 +09:00
}
2012-05-31 16:01:16 -04:00
2015-05-10 14:48:35 +02:00
UniValue result ( UniValue : : VOBJ ) ;
2017-09-22 20:04:07 +02:00
if ( blockindex ) result . pushKV ( " in_active_chain " , in_active_chain ) ;
2017-04-25 17:29:24 +09:00
TxToJSON ( * tx , hash_block , result ) ;
2012-05-31 16:01:16 -04:00
return result ;
}
2018-05-02 17:14:48 +02:00
static UniValue gettxoutproof ( const JSONRPCRequest & request )
2014-11-01 16:01:48 -07:00
{
2018-10-23 15:22:28 -04:00
RPCHelpMan { " gettxoutproof " ,
2018-10-20 08:19:44 -04:00
" \n Returns a hex-encoded proof that \" txid \" was included in a block. \n "
" \n NOTE: By default this function only works sometimes. This is when there is an \n "
" unspent output in the utxo for this transaction. To make it always work, \n "
" you need to maintain a transaction index, using the -txindex command line option or \n "
" specify the block in which the transaction is included manually (by blockhash). \n " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " txids " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " A json array of txids to filter " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " txid " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : OMITTED , " A transaction hash " } ,
2018-10-23 15:22:28 -04:00
} ,
2018-11-23 11:21:38 -05:00
} ,
2018-12-10 16:56:51 -05:00
{ " blockhash " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : OMITTED_NAMED_ARG , " If specified, looks for txid in the block with this hash " } ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2014-11-01 16:01:48 -07:00
" \" data \" (string) A string that is a serialized, hex-encoded data for the proof. \n "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples { " " } ,
2019-06-19 13:59:11 +09:00
} . Check ( request ) ;
2014-11-01 16:01:48 -07:00
2017-01-04 13:22:19 +09:00
std : : set < uint256 > setTxids ;
2014-11-01 16:01:48 -07:00
uint256 oneTxid ;
2016-09-22 09:46:41 +02:00
UniValue txids = request . params [ 0 ] . get_array ( ) ;
2015-05-10 13:35:44 +02:00
for ( unsigned int idx = 0 ; idx < txids . size ( ) ; idx + + ) {
2015-05-18 14:02:18 +02:00
const UniValue & txid = txids [ idx ] ;
2018-06-08 11:16:07 -07:00
uint256 hash ( ParseHashV ( txid , " txid " ) ) ;
2014-11-01 16:01:48 -07:00
if ( setTxids . count ( hash ) )
2017-01-04 13:22:19 +09:00
throw JSONRPCError ( RPC_INVALID_PARAMETER , std : : string ( " Invalid parameter, duplicated txid: " ) + txid . get_str ( ) ) ;
2014-11-01 16:01:48 -07:00
setTxids . insert ( hash ) ;
oneTxid = hash ;
}
2017-08-07 07:36:37 +02:00
CBlockIndex * pblockindex = nullptr ;
2014-11-01 16:01:48 -07:00
uint256 hashBlock ;
2017-12-08 11:49:08 -08:00
if ( ! request . params [ 1 ] . isNull ( ) ) {
LOCK ( cs_main ) ;
2018-06-08 11:16:07 -07:00
hashBlock = ParseHashV ( request . params [ 1 ] , " blockhash " ) ;
2018-01-12 00:23:09 +00:00
pblockindex = LookupBlockIndex ( hashBlock ) ;
if ( ! pblockindex ) {
2014-11-01 16:01:48 -07:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Block not found " ) ;
2018-01-12 00:23:09 +00:00
}
2014-11-01 16:01:48 -07:00
} else {
2017-12-08 11:49:08 -08:00
LOCK ( cs_main ) ;
2017-02-10 11:04:13 -05:00
// Loop through txids and try to find which block they're in. Exit loop once a block is found.
for ( const auto & tx : setTxids ) {
2019-07-24 11:45:04 -04:00
const Coin & coin = AccessByTxid ( : : ChainstateActive ( ) . CoinsTip ( ) , tx ) ;
2017-02-10 11:04:13 -05:00
if ( ! coin . IsSpent ( ) ) {
2019-03-27 11:14:25 -04:00
pblockindex = : : ChainActive ( ) [ coin . nHeight ] ;
2017-02-10 11:04:13 -05:00
break ;
}
2017-04-25 11:29:39 -07:00
}
2014-11-01 16:01:48 -07:00
}
2017-12-08 11:49:08 -08:00
// Allow txindex to catch up if we need to query it and before we acquire cs_main.
if ( g_txindex & & ! pblockindex ) {
g_txindex - > BlockUntilSyncedToCurrentChain ( ) ;
}
LOCK ( cs_main ) ;
2017-08-07 07:36:37 +02:00
if ( pblockindex = = nullptr )
2014-11-01 16:01:48 -07:00
{
2016-11-11 16:30:38 -08:00
CTransactionRef tx ;
2019-01-26 14:34:00 -08:00
if ( ! GetTransaction ( oneTxid , tx , Params ( ) . GetConsensus ( ) , hashBlock ) | | hashBlock . IsNull ( ) )
2014-11-01 16:01:48 -07:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Transaction not yet in block " ) ;
2018-01-12 00:23:09 +00:00
pblockindex = LookupBlockIndex ( hashBlock ) ;
if ( ! pblockindex ) {
2014-11-01 16:01:48 -07:00
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Transaction index corrupt " ) ;
2018-01-12 00:23:09 +00:00
}
2014-11-01 16:01:48 -07:00
}
CBlock block ;
2015-04-17 14:19:21 +02:00
if ( ! ReadBlockFromDisk ( block , pblockindex , Params ( ) . GetConsensus ( ) ) )
2014-11-01 16:01:48 -07:00
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Can't read block from disk " ) ;
unsigned int ntxFound = 0 ;
2016-11-10 17:26:00 -08:00
for ( const auto & tx : block . vtx )
if ( setTxids . count ( tx - > GetHash ( ) ) )
2014-11-01 16:01:48 -07:00
ntxFound + + ;
if ( ntxFound ! = setTxids . size ( ) )
2017-02-10 11:04:13 -05:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Not all transactions found in specified or retrieved block " ) ;
2014-11-01 16:01:48 -07:00
2015-11-06 01:32:04 +01:00
CDataStream ssMB ( SER_NETWORK , PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS ) ;
2014-11-01 16:01:48 -07:00
CMerkleBlock mb ( block , setTxids ) ;
ssMB < < mb ;
std : : string strHex = HexStr ( ssMB . begin ( ) , ssMB . end ( ) ) ;
return strHex ;
}
2018-05-02 17:14:48 +02:00
static UniValue verifytxoutproof ( const JSONRPCRequest & request )
2014-11-01 16:01:48 -07:00
{
2018-10-20 08:19:44 -04:00
RPCHelpMan { " verifytxoutproof " ,
" \n Verifies that a proof points to a transaction in a block, returning the transaction it commits to \n "
" and throwing an RPC error if the block is not in our best chain \n " ,
{
2018-12-10 16:56:51 -05:00
{ " proof " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The hex-encoded proof generated by gettxoutproof " } ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2018-06-12 17:10:21 -04:00
" [ \" txid \" ] (array, strings) The txid(s) which the proof commits to, or empty array if the proof can not be validated. \n "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples { " " } ,
2019-06-19 13:59:11 +09:00
} . Check ( request ) ;
2014-11-01 16:01:48 -07:00
2016-09-22 09:46:41 +02:00
CDataStream ssMB ( ParseHexV ( request . params [ 0 ] , " proof " ) , SER_NETWORK , PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS ) ;
2014-11-01 16:01:48 -07:00
CMerkleBlock merkleBlock ;
ssMB > > merkleBlock ;
2015-05-10 14:48:35 +02:00
UniValue res ( UniValue : : VARR ) ;
2014-11-01 16:01:48 -07:00
2017-01-04 13:22:19 +09:00
std : : vector < uint256 > vMatch ;
std : : vector < unsigned int > vIndex ;
2016-02-18 16:31:12 -08:00
if ( merkleBlock . txn . ExtractMatches ( vMatch , vIndex ) ! = merkleBlock . header . hashMerkleRoot )
2014-11-01 16:01:48 -07:00
return res ;
LOCK ( cs_main ) ;
2018-01-12 00:23:09 +00:00
const CBlockIndex * pindex = LookupBlockIndex ( merkleBlock . header . GetHash ( ) ) ;
2019-03-27 11:14:25 -04:00
if ( ! pindex | | ! : : ChainActive ( ) . Contains ( pindex ) | | pindex - > nTx = = 0 ) {
2014-11-01 16:01:48 -07:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Block not found in chain " ) ;
2018-01-12 00:23:09 +00:00
}
2014-11-01 16:01:48 -07:00
2018-06-12 17:10:21 -04:00
// Check if proof is valid, only add results if so
if ( pindex - > nTx = = merkleBlock . txn . GetNumTransactions ( ) ) {
for ( const uint256 & hash : vMatch ) {
res . push_back ( hash . GetHex ( ) ) ;
}
}
2014-11-01 16:01:48 -07:00
return res ;
}
2018-06-27 17:02:07 -07:00
static UniValue createrawtransaction ( const JSONRPCRequest & request )
{
2018-11-23 11:21:38 -05:00
RPCHelpMan { " createrawtransaction " ,
" \n Create a transaction spending the given inputs and creating new outputs. \n "
" Outputs can be addresses or data. \n "
" Returns hex-encoded raw transaction. \n "
" Note that the transaction's inputs are not signed, and \n "
" it is not stored in the wallet or transmitted to the network. \n " ,
{
2018-12-10 16:56:51 -05:00
{ " inputs " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " A json array of json objects " ,
2018-11-23 11:21:38 -05:00
{
2018-12-10 16:56:51 -05:00
{ " " , RPCArg : : Type : : OBJ , RPCArg : : Optional : : OMITTED , " " ,
2018-11-23 11:21:38 -05:00
{
2018-12-10 16:56:51 -05:00
{ " txid " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The transaction id " } ,
{ " vout " , RPCArg : : Type : : NUM , RPCArg : : Optional : : NO , " The output number " } ,
{ " sequence " , RPCArg : : Type : : NUM , /* default */ " depends on the value of the 'replaceable' and 'locktime' arguments " , " The sequence number " } ,
2018-11-23 11:21:38 -05:00
} ,
} ,
} ,
} ,
2018-12-10 16:56:51 -05:00
{ " outputs " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " a json array with outputs (key-value pairs), where none of the keys are duplicated. \n "
2018-12-06 16:13:53 -05:00
" That is, each address can only appear once and there can only be one 'data' object. \n "
2018-11-23 11:21:38 -05:00
" For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also \n "
" accepted as second parameter. " ,
{
2018-12-10 16:56:51 -05:00
{ " " , RPCArg : : Type : : OBJ , RPCArg : : Optional : : OMITTED , " " ,
2018-11-23 11:21:38 -05:00
{
2018-12-10 16:56:51 -05:00
{ " address " , RPCArg : : Type : : AMOUNT , RPCArg : : Optional : : NO , " A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT } ,
2018-11-23 11:21:38 -05:00
} ,
} ,
2018-12-10 16:56:51 -05:00
{ " " , RPCArg : : Type : : OBJ , RPCArg : : Optional : : OMITTED , " " ,
2018-11-23 11:21:38 -05:00
{
2018-12-10 16:56:51 -05:00
{ " data " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " A key-value pair. The key must be \" data \" , the value is hex-encoded data " } ,
2018-11-23 11:21:38 -05:00
} ,
} ,
} ,
} ,
2018-12-10 16:56:51 -05:00
{ " locktime " , RPCArg : : Type : : NUM , /* default */ " 0 " , " Raw locktime. Non-0 value also locktime-activates inputs " } ,
{ " replaceable " , RPCArg : : Type : : BOOL , /* default */ " false " , " Marks this transaction as BIP125-replaceable. \n "
2018-11-23 11:21:38 -05:00
" Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible. " } ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2018-06-27 17:02:07 -07:00
" \" transaction \" (string) hex string of the transaction \n "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
HelpExampleCli ( " createrawtransaction " , " \" [{ \\ \" txid \\ \" : \\ \" myid \\ \" , \\ \" vout \\ \" :0}] \" \" [{ \\ \" address \\ \" :0.01}] \" " )
2018-06-27 17:02:07 -07:00
+ HelpExampleCli ( " createrawtransaction " , " \" [{ \\ \" txid \\ \" : \\ \" myid \\ \" , \\ \" vout \\ \" :0}] \" \" [{ \\ \" data \\ \" : \\ \" 00010203 \\ \" }] \" " )
+ HelpExampleRpc ( " createrawtransaction " , " \" [{ \\ \" txid \\ \" : \\ \" myid \\ \" , \\ \" vout \\ \" :0}] \" , \" [{ \\ \" address \\ \" :0.01}] \" " )
+ HelpExampleRpc ( " createrawtransaction " , " \" [{ \\ \" txid \\ \" : \\ \" myid \\ \" , \\ \" vout \\ \" :0}] \" , \" [{ \\ \" data \\ \" : \\ \" 00010203 \\ \" }] \" " )
2018-12-21 12:29:36 -05:00
} ,
2019-06-19 13:59:11 +09:00
} . Check ( request ) ;
2018-06-27 17:02:07 -07:00
RPCTypeCheck ( request . params , {
UniValue : : VARR ,
UniValueType ( ) , // ARR or OBJ, checked later
UniValue : : VNUM ,
UniValue : : VBOOL
} , true
) ;
2019-04-27 19:44:38 +02:00
bool rbf = false ;
if ( ! request . params [ 3 ] . isNull ( ) ) {
rbf = request . params [ 3 ] . isTrue ( ) ;
}
CMutableTransaction rawTx = ConstructTransaction ( request . params [ 0 ] , request . params [ 1 ] , request . params [ 2 ] , rbf ) ;
2018-06-27 17:02:07 -07:00
2018-12-09 22:03:07 -08:00
return EncodeHexTx ( CTransaction ( rawTx ) ) ;
2012-05-31 16:01:16 -04:00
}
2018-05-02 17:14:48 +02:00
static UniValue decoderawtransaction ( const JSONRPCRequest & request )
2012-05-31 16:01:16 -04:00
{
2019-06-19 13:59:11 +09:00
RPCHelpMan { " decoderawtransaction " ,
2018-10-20 08:19:44 -04:00
" \n Return a JSON object representing the serialized, hex-encoded transaction. \n " ,
{
2018-12-10 16:56:51 -05:00
{ " hexstring " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The transaction hex string " } ,
2019-04-26 09:04:08 -04:00
{ " iswitness " , RPCArg : : Type : : BOOL , /* default */ " depends on heuristic tests " , " Whether the transaction hex is a serialized witness transaction. \n "
" If iswitness is not present, heuristic tests will be used in decoding. \n "
" If true, only witness deserialization will be tried. \n "
" If false, only non-witness deserialization will be tried. \n "
" This boolean should reflect whether the transaction has inputs \n "
" (e.g. fully valid, or on-chain transactions), if known by the caller. "
} ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2013-10-29 22:29:44 +11:00
" { \n "
2014-04-29 14:34:41 -04:00
" \" txid \" : \" id \" , (string) The transaction id \n "
2016-01-23 01:46:11 +08:00
" \" hash \" : \" id \" , (string) The transaction hash (differs from txid for witness transactions) \n "
2015-11-21 05:35:11 +03:00
" \" size \" : n, (numeric) The transaction size \n "
2016-01-03 18:54:50 +01:00
" \" vsize \" : n, (numeric) The virtual transaction size (differs from size for witness transactions) \n "
2018-03-26 11:20:56 -04:00
" \" weight \" : n, (numeric) The transaction's weight (between vsize*4 - 3 and vsize*4) \n "
2013-10-29 22:29:44 +11:00
" \" version \" : n, (numeric) The version \n "
" \" locktime \" : ttt, (numeric) The lock time \n "
" \" vin \" : [ (array of json objects) \n "
" { \n "
" \" txid \" : \" id \" , (string) The transaction id \n "
" \" vout \" : n, (numeric) The output number \n "
" \" scriptSig \" : { (json object) The script \n "
" \" asm \" : \" asm \" , (string) asm \n "
" \" hex \" : \" hex \" (string) hex \n "
" }, \n "
2016-01-23 01:46:11 +08:00
" \" txinwitness \" : [ \" hex \" , ...] (array of string) hex-encoded witness data (if any) \n "
2013-10-29 22:29:44 +11:00
" \" sequence \" : n (numeric) The script sequence number \n "
" } \n "
" ,... \n "
" ], \n "
" \" vout \" : [ (array of json objects) \n "
" { \n "
2015-08-01 20:15:23 +01:00
" \" value \" : x.xxx, (numeric) The value in " + CURRENCY_UNIT + " \n "
2013-10-29 22:29:44 +11:00
" \" n \" : n, (numeric) index \n "
" \" scriptPubKey \" : { (json object) \n "
" \" asm \" : \" asm \" , (string) the asm \n "
" \" hex \" : \" hex \" , (string) the hex \n "
" \" reqSigs \" : n, (numeric) The required sigs \n "
" \" type \" : \" pubkeyhash \" , (string) The type, eg 'pubkeyhash' \n "
" \" addresses \" : [ (json array of string) \n "
" \" 12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc \" (string) bitcoin address \n "
" ,... \n "
" ] \n "
" } \n "
" } \n "
" ,... \n "
" ], \n "
" } \n "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
HelpExampleCli ( " decoderawtransaction " , " \" hexstring \" " )
2013-10-29 22:29:44 +11:00
+ HelpExampleRpc ( " decoderawtransaction " , " \" hexstring \" " )
2018-12-21 12:29:36 -05:00
} ,
2019-06-19 13:59:11 +09:00
} . Check ( request ) ;
2012-05-31 16:01:16 -04:00
2017-08-28 18:00:21 +12:00
RPCTypeCheck ( request . params , { UniValue : : VSTR , UniValue : : VBOOL } ) ;
2014-06-23 23:10:24 -04:00
2016-11-30 14:50:20 -08:00
CMutableTransaction mtx ;
2014-06-23 23:10:24 -04:00
2017-08-28 18:00:21 +12:00
bool try_witness = request . params [ 1 ] . isNull ( ) ? true : request . params [ 1 ] . get_bool ( ) ;
bool try_no_witness = request . params [ 1 ] . isNull ( ) ? true : ! request . params [ 1 ] . get_bool ( ) ;
if ( ! DecodeHexTx ( mtx , request . params [ 0 ] . get_str ( ) , try_no_witness , try_witness ) ) {
2012-10-04 09:34:44 +02:00
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , " TX decode failed " ) ;
2017-08-28 18:00:21 +12:00
}
2012-05-31 16:01:16 -04:00
2015-05-10 13:35:44 +02:00
UniValue result ( UniValue : : VOBJ ) ;
2017-08-11 12:21:14 -07:00
TxToUniv ( CTransaction ( std : : move ( mtx ) ) , uint256 ( ) , result , false ) ;
2012-05-31 16:01:16 -04:00
return result ;
}
2019-03-20 15:54:37 -04:00
static std : : string GetAllOutputTypes ( )
{
std : : string ret ;
for ( int i = TX_NONSTANDARD ; i < = TX_WITNESS_UNKNOWN ; + + i ) {
if ( i ! = TX_NONSTANDARD ) ret + = " , " ;
ret + = GetTxnOutputType ( static_cast < txnouttype > ( i ) ) ;
}
return ret ;
}
2018-05-02 17:14:48 +02:00
static UniValue decodescript ( const JSONRPCRequest & request )
2013-07-15 01:22:10 -04:00
{
2019-06-19 13:59:11 +09:00
RPCHelpMan { " decodescript " ,
2018-10-20 08:19:44 -04:00
" \n Decode a hex-encoded script. \n " ,
{
2018-12-10 16:56:51 -05:00
{ " hexstring " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " the hex-encoded script " } ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2013-10-29 22:29:44 +11:00
" { \n "
2019-03-17 22:27:45 -04:00
" \" asm \" : \" asm \" , (string) Script public key \n "
2019-03-20 15:54:37 -04:00
" \" type \" : \" type \" , (string) The output type (e.g. " + GetAllOutputTypes ( ) + " ) \n "
2019-03-17 22:27:45 -04:00
" \" reqSigs \" : n, (numeric) The required signatures \n "
" \" addresses \" : [ (json array of string) \n "
" \" address \" (string) bitcoin address \n "
2013-10-29 22:29:44 +11:00
" ,... \n "
" ], \n "
2019-03-17 22:27:45 -04:00
" \" p2sh \" : \" str \" (string) address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH). \n "
2019-03-20 15:54:37 -04:00
" \" segwit \" : { (json object) Result of a witness script public key wrapping this redeem script (not returned if the script is a P2SH or witness). \n "
2019-03-17 22:27:45 -04:00
" \" asm \" : \" str \" , (string) String representation of the script public key \n "
" \" hex \" : \" hexstr \" , (string) Hex string of the script public key \n "
" \" type \" : \" str \" , (string) The type of the script public key (e.g. witness_v0_keyhash or witness_v0_scripthash) \n "
" \" reqSigs \" : n, (numeric) The required signatures (always 1) \n "
" \" addresses \" : [ (json array of string) (always length 1) \n "
" \" address \" (string) segwit address \n "
" ,... \n "
" ], \n "
" \" p2sh-segwit \" : \" str \" (string) address of the P2SH script wrapping this witness redeem script. \n "
2013-10-29 22:29:44 +11:00
" } \n "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
HelpExampleCli ( " decodescript " , " \" hexstring \" " )
2013-10-29 22:29:44 +11:00
+ HelpExampleRpc ( " decodescript " , " \" hexstring \" " )
2018-12-21 12:29:36 -05:00
} ,
2019-06-19 13:59:11 +09:00
} . Check ( request ) ;
2013-07-15 01:22:10 -04:00
2017-06-06 21:15:28 +02:00
RPCTypeCheck ( request . params , { UniValue : : VSTR } ) ;
2013-07-15 01:22:10 -04:00
2015-05-10 14:48:35 +02:00
UniValue r ( UniValue : : VOBJ ) ;
2013-07-15 01:22:10 -04:00
CScript script ;
2016-09-22 09:46:41 +02:00
if ( request . params [ 0 ] . get_str ( ) . size ( ) > 0 ) {
2017-01-04 13:22:19 +09:00
std : : vector < unsigned char > scriptData ( ParseHexV ( request . params [ 0 ] , " argument " ) ) ;
2013-07-15 01:22:10 -04:00
script = CScript ( scriptData . begin ( ) , scriptData . end ( ) ) ;
} else {
// Empty scripts are valid
}
2019-03-17 22:27:45 -04:00
ScriptPubKeyToUniv ( script , r , /* fIncludeHex */ false ) ;
2013-07-15 01:22:10 -04:00
2016-09-26 17:01:10 -04:00
UniValue type ;
type = find_value ( r , " type " ) ;
if ( type . isStr ( ) & & type . get_str ( ) ! = " scripthash " ) {
// P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,
// don't return the address for a P2SH of the P2SH.
2019-02-19 17:00:45 -05:00
r . pushKV ( " p2sh " , EncodeDestination ( ScriptHash ( script ) ) ) ;
2018-02-01 02:40:47 +02:00
// P2SH and witness programs cannot be wrapped in P2WSH, if this script
// is a witness program, don't return addresses for a segwit programs.
2018-04-08 00:03:04 +03:00
if ( type . get_str ( ) = = " pubkey " | | type . get_str ( ) = = " pubkeyhash " | | type . get_str ( ) = = " multisig " | | type . get_str ( ) = = " nonstandard " ) {
2018-02-01 02:40:47 +02:00
std : : vector < std : : vector < unsigned char > > solutions_data ;
2018-06-10 22:19:07 -07:00
txnouttype which_type = Solver ( script , solutions_data ) ;
2018-02-01 02:40:47 +02:00
// Uncompressed pubkeys cannot be used with segwit checksigs.
// If the script contains an uncompressed pubkey, skip encoding of a segwit program.
if ( ( which_type = = TX_PUBKEY ) | | ( which_type = = TX_MULTISIG ) ) {
for ( const auto & solution : solutions_data ) {
if ( ( solution . size ( ) ! = 1 ) & & ! CPubKey ( solution ) . IsCompressed ( ) ) {
return r ;
}
}
}
UniValue sr ( UniValue : : VOBJ ) ;
CScript segwitScr ;
if ( which_type = = TX_PUBKEY ) {
segwitScr = GetScriptForDestination ( WitnessV0KeyHash ( Hash160 ( solutions_data [ 0 ] . begin ( ) , solutions_data [ 0 ] . end ( ) ) ) ) ;
} else if ( which_type = = TX_PUBKEYHASH ) {
segwitScr = GetScriptForDestination ( WitnessV0KeyHash ( solutions_data [ 0 ] ) ) ;
} else {
// Scripts that are not fit for P2WPKH are encoded as P2WSH.
// Newer segwit program versions should be considered when then become available.
2018-06-17 19:44:50 -07:00
segwitScr = GetScriptForDestination ( WitnessV0ScriptHash ( script ) ) ;
2018-02-01 02:40:47 +02:00
}
2019-03-17 22:27:45 -04:00
ScriptPubKeyToUniv ( segwitScr , sr , /* fIncludeHex */ true ) ;
2019-02-19 17:00:45 -05:00
sr . pushKV ( " p2sh-segwit " , EncodeDestination ( ScriptHash ( segwitScr ) ) ) ;
2018-02-01 02:40:47 +02:00
r . pushKV ( " segwit " , sr ) ;
}
2016-09-26 17:01:10 -04:00
}
2013-07-15 01:22:10 -04:00
return r ;
}
2018-05-02 17:14:48 +02:00
static UniValue combinerawtransaction ( const JSONRPCRequest & request )
2017-06-09 22:38:06 -07:00
{
2018-10-23 15:22:28 -04:00
RPCHelpMan { " combinerawtransaction " ,
2018-10-20 08:19:44 -04:00
" \n Combine multiple partially signed transactions into one transaction. \n "
" The combined transaction may be another partially signed transaction or a \n "
" fully signed transaction. " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " txs " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " A json array of hex strings of partially signed transactions " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " hexstring " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : OMITTED , " A transaction hash " } ,
2018-11-23 11:21:38 -05:00
} ,
2018-10-23 15:22:28 -04:00
} ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2017-08-17 19:35:30 -07:00
" \" hex \" (string) The hex-encoded raw transaction with signature(s) \n "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
HelpExampleCli ( " combinerawtransaction " , " [ \" myhex1 \" , \" myhex2 \" , \" myhex3 \" ] " )
} ,
2019-06-19 13:59:11 +09:00
} . Check ( request ) ;
2017-06-09 22:38:06 -07:00
UniValue txs = request . params [ 0 ] . get_array ( ) ;
std : : vector < CMutableTransaction > txVariants ( txs . size ( ) ) ;
for ( unsigned int idx = 0 ; idx < txs . size ( ) ; idx + + ) {
if ( ! DecodeHexTx ( txVariants [ idx ] , txs [ idx ] . get_str ( ) , true ) ) {
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , strprintf ( " TX decode failed for tx %d " , idx ) ) ;
}
}
if ( txVariants . empty ( ) ) {
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , " Missing transactions " ) ;
}
// mergedTx will end up with all the signatures; it
// starts as a clone of the rawtx:
CMutableTransaction mergedTx ( txVariants [ 0 ] ) ;
// Fetch previous transactions (inputs):
CCoinsView viewDummy ;
CCoinsViewCache view ( & viewDummy ) ;
{
LOCK ( cs_main ) ;
LOCK ( mempool . cs ) ;
2019-07-24 11:45:04 -04:00
CCoinsViewCache & viewChain = : : ChainstateActive ( ) . CoinsTip ( ) ;
2017-06-09 22:38:06 -07:00
CCoinsViewMemPool viewMempool ( & viewChain , mempool ) ;
view . SetBackend ( viewMempool ) ; // temporarily switch cache backend to db+mempool view
for ( const CTxIn & txin : mergedTx . vin ) {
view . AccessCoin ( txin . prevout ) ; // Load entries from viewChain into view; can fail.
}
view . SetBackend ( viewDummy ) ; // switch back to avoid locking mempool for too long
}
// Use CTransaction for the constant parts of the
// transaction to avoid rehashing.
const CTransaction txConst ( mergedTx ) ;
// Sign what we can:
for ( unsigned int i = 0 ; i < mergedTx . vin . size ( ) ; i + + ) {
CTxIn & txin = mergedTx . vin [ i ] ;
const Coin & coin = view . AccessCoin ( txin . prevout ) ;
if ( coin . IsSpent ( ) ) {
throw JSONRPCError ( RPC_VERIFY_ERROR , " Input not found or already spent " ) ;
}
SignatureData sigdata ;
// ... and merge in other signatures:
for ( const CMutableTransaction & txv : txVariants ) {
if ( txv . vin . size ( ) > i ) {
2018-06-07 21:12:25 -07:00
sigdata . MergeSignatureData ( DataFromTransaction ( txv , i , coin . out ) ) ;
2017-06-09 22:38:06 -07:00
}
}
2018-06-07 21:12:25 -07:00
ProduceSignature ( DUMMY_SIGNING_PROVIDER , MutableTransactionSignatureCreator ( & mergedTx , i , coin . out . nValue , 1 ) , coin . out . scriptPubKey , sigdata ) ;
2017-06-09 22:38:06 -07:00
2018-05-17 17:54:18 -07:00
UpdateInput ( txin , sigdata ) ;
2017-06-09 22:38:06 -07:00
}
2018-12-09 22:03:07 -08:00
return EncodeHexTx ( CTransaction ( mergedTx ) ) ;
2017-06-09 22:38:06 -07:00
}
2018-05-02 17:14:48 +02:00
static UniValue signrawtransactionwithkey ( const JSONRPCRequest & request )
2017-06-12 12:23:02 -07:00
{
2018-10-23 15:22:28 -04:00
RPCHelpMan { " signrawtransactionwithkey " ,
2018-10-20 08:19:44 -04:00
" \n Sign inputs for raw transaction (serialized, hex-encoded). \n "
" The second argument is an array of base58-encoded private \n "
" keys that will be the only keys used to sign the transaction. \n "
" The third optional argument (may be null) is an array of previous transaction outputs that \n "
" this transaction depends on but may not yet be in the block chain. \n " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " hexstring " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " The transaction hex string " } ,
{ " privkeys " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " A json array of base58-encoded private keys for signing " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " privatekey " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : OMITTED , " private key in base58-encoding " } ,
2018-10-23 15:22:28 -04:00
} ,
2018-11-23 11:21:38 -05:00
} ,
2018-12-10 16:56:51 -05:00
{ " prevtxs " , RPCArg : : Type : : ARR , RPCArg : : Optional : : OMITTED_NAMED_ARG , " A json array of previous dependent transaction outputs " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " " , RPCArg : : Type : : OBJ , RPCArg : : Optional : : OMITTED , " " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " txid " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The transaction id " } ,
{ " vout " , RPCArg : : Type : : NUM , RPCArg : : Optional : : NO , " The output number " } ,
{ " scriptPubKey " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " script key " } ,
2018-10-15 16:57:18 +13:00
{ " redeemScript " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : OMITTED , " (required for P2SH) redeem script " } ,
{ " witnessScript " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : OMITTED , " (required for P2WSH or P2SH-P2WSH) witness script " } ,
2019-03-26 17:39:39 +01:00
{ " amount " , RPCArg : : Type : : AMOUNT , RPCArg : : Optional : : OMITTED , " (required for Segwit inputs) the amount spent " } ,
2018-11-23 11:21:38 -05:00
} ,
2018-10-23 15:22:28 -04:00
} ,
} ,
2018-11-23 11:21:38 -05:00
} ,
2018-12-10 16:56:51 -05:00
{ " sighashtype " , RPCArg : : Type : : STR , /* default */ " ALL " , " The signature hash type. Must be one of: \n "
2017-06-12 12:23:02 -07:00
" \" ALL \" \n "
" \" NONE \" \n "
" \" SINGLE \" \n "
" \" ALL|ANYONECANPAY \" \n "
" \" NONE|ANYONECANPAY \" \n "
" \" SINGLE|ANYONECANPAY \" \n "
2018-11-23 11:21:38 -05:00
} ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2017-06-12 12:23:02 -07:00
" { \n "
" \" hex \" : \" value \" , (string) The hex-encoded raw transaction with signature(s) \n "
" \" complete \" : true|false, (boolean) If the transaction has a complete set of signatures \n "
" \" errors \" : [ (json array of objects) Script verification errors (if there are any) \n "
" { \n "
" \" txid \" : \" hash \" , (string) The hash of the referenced, previous transaction \n "
" \" vout \" : n, (numeric) The index of the output to spent and used as input \n "
" \" scriptSig \" : \" hex \" , (string) The hex-encoded signature script \n "
" \" sequence \" : n, (numeric) Script sequence number \n "
" \" error \" : \" text \" (string) Verification or signing error related to the input \n "
" } \n "
" ,... \n "
" ] \n "
" } \n "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
2019-06-13 19:33:28 -07:00
HelpExampleCli ( " signrawtransactionwithkey " , " \" myhex \" \" [ \\ \" key1 \\ \" , \\ \" key2 \\ \" ] \" " )
+ HelpExampleRpc ( " signrawtransactionwithkey " , " \" myhex \" , \" [ \\ \" key1 \\ \" , \\ \" key2 \\ \" ] \" " )
2018-12-21 12:29:36 -05:00
} ,
2019-06-19 13:59:11 +09:00
} . Check ( request ) ;
2017-06-12 12:23:02 -07:00
RPCTypeCheck ( request . params , { UniValue : : VSTR , UniValue : : VARR , UniValue : : VARR , UniValue : : VSTR } , true ) ;
CMutableTransaction mtx ;
if ( ! DecodeHexTx ( mtx , request . params [ 0 ] . get_str ( ) , true ) ) {
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , " TX decode failed " ) ;
}
2019-06-06 16:33:23 +02:00
FillableSigningProvider keystore ;
2017-06-12 12:23:02 -07:00
const UniValue & keys = request . params [ 1 ] . get_array ( ) ;
for ( unsigned int idx = 0 ; idx < keys . size ( ) ; + + idx ) {
UniValue k = keys [ idx ] ;
2017-09-19 16:49:52 -07:00
CKey key = DecodeSecret ( k . get_str ( ) ) ;
2017-06-12 12:23:02 -07:00
if ( ! key . IsValid ( ) ) {
2017-09-19 16:49:52 -07:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid private key " ) ;
2017-06-12 12:23:02 -07:00
}
keystore . AddKey ( key ) ;
}
2019-04-10 13:38:41 +00:00
// Fetch previous transactions (inputs):
std : : map < COutPoint , Coin > coins ;
for ( const CTxIn & txin : mtx . vin ) {
coins [ txin . prevout ] ; // Create empty map entry keyed by prevout.
}
FindCoins ( coins ) ;
2019-07-05 17:39:31 -04:00
// Parse the prevtxs array
ParsePrevouts ( request . params [ 2 ] , & keystore , coins ) ;
return SignTransaction ( mtx , & keystore , coins , request . params [ 3 ] ) ;
2017-06-12 12:23:02 -07:00
}
2018-05-02 17:14:48 +02:00
static UniValue sendrawtransaction ( const JSONRPCRequest & request )
2012-05-31 16:01:16 -04:00
{
2019-06-19 13:59:11 +09:00
RPCHelpMan { " sendrawtransaction " ,
2019-07-26 11:30:51 +02:00
" \n Submit a raw transaction (serialized, hex-encoded) to local node and network. \n "
" \n Note that the transaction will be sent unconditionally to all peers, so using this \n "
" for manual rebroadcast may degrade privacy by leaking the transaction's origin, as \n "
" nodes will normally not rebroadcast non-wallet transactions already in their mempool. \n "
2018-10-20 08:19:44 -04:00
" \n Also see createrawtransaction and signrawtransactionwithkey calls. \n " ,
{
2018-12-10 16:56:51 -05:00
{ " hexstring " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The hex string of the raw transaction " } ,
2019-08-02 02:03:01 +09:00
{ " maxfeerate " , RPCArg : : Type : : AMOUNT , /* default */ FormatMoney ( DEFAULT_MAX_RAW_TX_FEE_RATE . GetFeePerK ( ) ) ,
2019-04-05 18:01:28 -04:00
" Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
" /kB. \n Set to 0 to accept any fee rate. \n " } ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2013-10-29 22:29:44 +11:00
" \" hex \" (string) The transaction hash in hex \n "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
2013-10-29 22:29:44 +11:00
" \n Create a transaction \n "
+ HelpExampleCli ( " createrawtransaction " , " \" [{ \\ \" txid \\ \" : \\ \" mytxid \\ \" , \\ \" vout \\ \" :0}] \" \" { \\ \" myaddress \\ \" :0.01} \" " ) +
" Sign the transaction, and get back the hex \n "
2018-02-20 09:15:28 -05:00
+ HelpExampleCli ( " signrawtransactionwithwallet " , " \" myhex \" " ) +
2013-10-29 22:29:44 +11:00
" \n Send the transaction (signed hex) \n "
+ HelpExampleCli ( " sendrawtransaction " , " \" signedhex \" " ) +
2018-10-02 14:49:18 -05:00
" \n As a JSON-RPC call \n "
2013-10-29 22:29:44 +11:00
+ HelpExampleRpc ( " sendrawtransaction " , " \" signedhex \" " )
2018-12-21 12:29:36 -05:00
} ,
2019-06-19 13:59:11 +09:00
} . Check ( request ) ;
2013-10-29 22:29:44 +11:00
2018-06-27 17:21:07 +09:00
RPCTypeCheck ( request . params , {
UniValue : : VSTR ,
UniValueType ( ) , // NUM or BOOL, checked later
} ) ;
2012-05-31 16:01:16 -04:00
// parse hex string from parameter
2016-11-30 14:50:20 -08:00
CMutableTransaction mtx ;
if ( ! DecodeHexTx ( mtx , request . params [ 0 ] . get_str ( ) ) )
2014-06-23 23:10:24 -04:00
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , " TX decode failed " ) ;
2016-11-10 22:29:19 -08:00
CTransactionRef tx ( MakeTransactionRef ( std : : move ( mtx ) ) ) ;
2013-08-28 15:41:46 -07:00
2019-08-02 02:03:01 +09:00
CFeeRate max_raw_tx_fee_rate = DEFAULT_MAX_RAW_TX_FEE_RATE ;
2018-06-27 17:21:07 +09:00
// TODO: temporary migration code for old clients. Remove in v0.20
if ( request . params [ 1 ] . isBool ( ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Second argument must be numeric (maxfeerate) and no longer supports a boolean . To allow a transaction with high fees , set maxfeerate to 0. " ) ;
2019-04-08 15:40:57 +01:00
} else if ( ! request . params [ 1 ] . isNull ( ) ) {
2019-08-02 02:03:01 +09:00
max_raw_tx_fee_rate = CFeeRate ( AmountFromValue ( request . params [ 1 ] ) ) ;
2018-06-27 17:21:07 +09:00
}
2019-08-02 02:03:01 +09:00
int64_t virtual_size = GetVirtualTransactionSize ( * tx ) ;
CAmount max_raw_tx_fee = max_raw_tx_fee_rate . GetFee ( virtual_size ) ;
2019-02-09 20:51:33 -08:00
std : : string err_string ;
2019-04-11 14:37:30 +00:00
AssertLockNotHeld ( cs_main ) ;
const TransactionError err = BroadcastTransaction ( tx , err_string , max_raw_tx_fee , /*relay*/ true , /*wait_callback*/ true ) ;
2019-02-14 10:01:06 -05:00
if ( TransactionError : : OK ! = err ) {
2019-02-09 20:51:33 -08:00
throw JSONRPCTransactionError ( err , err_string ) ;
2017-04-25 11:29:30 -07:00
}
2012-05-31 16:01:16 -04:00
2019-04-11 14:37:30 +00:00
return tx - > GetHash ( ) . GetHex ( ) ;
2012-05-31 16:01:16 -04:00
}
2016-03-29 19:43:02 +02:00
2018-05-02 17:14:48 +02:00
static UniValue testmempoolaccept ( const JSONRPCRequest & request )
2017-11-17 12:54:39 -05:00
{
2019-06-19 13:59:11 +09:00
RPCHelpMan { " testmempoolaccept " ,
2018-11-23 11:21:38 -05:00
" \n Returns result of mempool acceptance tests indicating if raw transaction (serialized, hex-encoded) would be accepted by mempool. \n "
" \n This checks if the transaction violates the consensus or policy rules. \n "
" \n See sendrawtransaction call. \n " ,
{
2018-12-10 16:56:51 -05:00
{ " rawtxs " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " An array of hex strings of raw transactions. \n "
2018-11-23 11:21:38 -05:00
" Length must be one for now. " ,
{
2018-12-10 16:56:51 -05:00
{ " rawtx " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : OMITTED , " " } ,
2018-11-23 11:21:38 -05:00
} ,
} ,
2019-08-02 02:03:01 +09:00
{ " maxfeerate " , RPCArg : : Type : : AMOUNT , /* default */ FormatMoney ( DEFAULT_MAX_RAW_TX_FEE_RATE . GetFeePerK ( ) ) , " Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + " /kB \n " } ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2017-11-17 12:54:39 -05:00
" [ (array) The result of the mempool acceptance test for each raw transaction in the input array. \n "
" Length is exactly one for now. \n "
" { \n "
" \" txid \" (string) The transaction hash in hex \n "
" \" allowed \" (boolean) If the mempool allows this tx to be inserted \n "
" \" reject-reason \" (string) Rejection string (only present when 'allowed' is false) \n "
" } \n "
" ] \n "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
2017-11-17 12:54:39 -05:00
" \n Create a transaction \n "
+ HelpExampleCli ( " createrawtransaction " , " \" [{ \\ \" txid \\ \" : \\ \" mytxid \\ \" , \\ \" vout \\ \" :0}] \" \" { \\ \" myaddress \\ \" :0.01} \" " ) +
" Sign the transaction, and get back the hex \n "
2018-02-20 09:15:28 -05:00
+ HelpExampleCli ( " signrawtransactionwithwallet " , " \" myhex \" " ) +
2017-11-17 12:54:39 -05:00
" \n Test acceptance of the transaction (signed hex) \n "
2018-12-15 11:12:31 +09:00
+ HelpExampleCli ( " testmempoolaccept " , " [ \" signedhex \" ] " ) +
2018-10-02 14:49:18 -05:00
" \n As a JSON-RPC call \n "
2017-11-17 12:54:39 -05:00
+ HelpExampleRpc ( " testmempoolaccept " , " [ \" signedhex \" ] " )
2018-12-21 12:29:36 -05:00
} ,
2019-06-19 13:59:11 +09:00
} . Check ( request ) ;
2017-11-17 12:54:39 -05:00
2019-02-14 17:07:29 +09:00
RPCTypeCheck ( request . params , {
UniValue : : VARR ,
UniValueType ( ) , // NUM or BOOL, checked later
} ) ;
2017-11-17 12:54:39 -05:00
if ( request . params [ 0 ] . get_array ( ) . size ( ) ! = 1 ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Array must contain exactly one raw transaction for now " ) ;
}
CMutableTransaction mtx ;
if ( ! DecodeHexTx ( mtx , request . params [ 0 ] . get_array ( ) [ 0 ] . get_str ( ) ) ) {
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , " TX decode failed " ) ;
}
CTransactionRef tx ( MakeTransactionRef ( std : : move ( mtx ) ) ) ;
const uint256 & tx_hash = tx - > GetHash ( ) ;
2019-08-02 02:03:01 +09:00
CFeeRate max_raw_tx_fee_rate = DEFAULT_MAX_RAW_TX_FEE_RATE ;
2019-02-14 17:07:29 +09:00
// TODO: temporary migration code for old clients. Remove in v0.20
if ( request . params [ 1 ] . isBool ( ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Second argument must be numeric (maxfeerate) and no longer supports a boolean . To allow a transaction with high fees , set maxfeerate to 0. " ) ;
2019-04-08 15:40:57 +01:00
} else if ( ! request . params [ 1 ] . isNull ( ) ) {
2019-08-02 02:03:01 +09:00
max_raw_tx_fee_rate = CFeeRate ( AmountFromValue ( request . params [ 1 ] ) ) ;
2017-11-17 12:54:39 -05:00
}
2019-08-02 02:03:01 +09:00
int64_t virtual_size = GetVirtualTransactionSize ( * tx ) ;
CAmount max_raw_tx_fee = max_raw_tx_fee_rate . GetFee ( virtual_size ) ;
2017-11-17 12:54:39 -05:00
UniValue result ( UniValue : : VARR ) ;
UniValue result_0 ( UniValue : : VOBJ ) ;
result_0 . pushKV ( " txid " , tx_hash . GetHex ( ) ) ;
CValidationState state ;
bool missing_inputs ;
bool test_accept_res ;
{
LOCK ( cs_main ) ;
test_accept_res = AcceptToMemoryPool ( mempool , state , std : : move ( tx ) , & missing_inputs ,
2018-04-02 11:16:56 -04:00
nullptr /* plTxnReplaced */ , false /* bypass_limits */ , max_raw_tx_fee , /* test_accept */ true ) ;
2017-11-17 12:54:39 -05:00
}
result_0 . pushKV ( " allowed " , test_accept_res ) ;
if ( ! test_accept_res ) {
if ( state . IsInvalid ( ) ) {
result_0 . pushKV ( " reject-reason " , strprintf ( " %i: %s " , state . GetRejectCode ( ) , state . GetRejectReason ( ) ) ) ;
} else if ( missing_inputs ) {
result_0 . pushKV ( " reject-reason " , " missing-inputs " ) ;
} else {
result_0 . pushKV ( " reject-reason " , state . GetRejectReason ( ) ) ;
}
}
result . push_back ( std : : move ( result_0 ) ) ;
return result ;
}
2018-06-28 19:04:40 -07:00
static std : : string WriteHDKeypath ( std : : vector < uint32_t > & keypath )
{
std : : string keypath_str = " m " ;
for ( uint32_t num : keypath ) {
keypath_str + = " / " ;
bool hardened = false ;
if ( num & 0x80000000 ) {
hardened = true ;
num & = ~ 0x80000000 ;
}
keypath_str + = std : : to_string ( num ) ;
if ( hardened ) {
keypath_str + = " ' " ;
}
}
return keypath_str ;
}
UniValue decodepsbt ( const JSONRPCRequest & request )
{
2018-10-20 08:19:44 -04:00
RPCHelpMan { " decodepsbt " ,
" \n Return a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction. \n " ,
{
2018-12-10 16:56:51 -05:00
{ " psbt " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " The PSBT base64 string " } ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2018-06-28 19:04:40 -07:00
" { \n "
" \" tx \" : { (json object) The decoded network-serialized unsigned transaction. \n "
" ... The layout is the same as the output of decoderawtransaction. \n "
" }, \n "
" \" unknown \" : { (json object) The unknown global fields \n "
" \" key \" : \" value \" (key-value pair) An unknown key-value pair \n "
" ... \n "
" }, \n "
" \" inputs \" : [ (array of json objects) \n "
" { \n "
" \" non_witness_utxo \" : { (json object, optional) Decoded network transaction for non-witness UTXOs \n "
" ... \n "
" }, \n "
" \" witness_utxo \" : { (json object, optional) Transaction output for witness UTXOs \n "
" \" amount \" : x.xxx, (numeric) The value in " + CURRENCY_UNIT + " \n "
" \" scriptPubKey \" : { (json object) \n "
" \" asm \" : \" asm \" , (string) The asm \n "
" \" hex \" : \" hex \" , (string) The hex \n "
" \" type \" : \" pubkeyhash \" , (string) The type, eg 'pubkeyhash' \n "
" \" address \" : \" address \" (string) Bitcoin address if there is one \n "
" } \n "
" }, \n "
" \" partial_signatures \" : { (json object, optional) \n "
" \" pubkey \" : \" signature \" , (string) The public key and signature that corresponds to it. \n "
" ,... \n "
" } \n "
" \" sighash \" : \" type \" , (string, optional) The sighash type to be used \n "
" \" redeem_script \" : { (json object, optional) \n "
" \" asm \" : \" asm \" , (string) The asm \n "
" \" hex \" : \" hex \" , (string) The hex \n "
" \" type \" : \" pubkeyhash \" , (string) The type, eg 'pubkeyhash' \n "
" } \n "
" \" witness_script \" : { (json object, optional) \n "
" \" asm \" : \" asm \" , (string) The asm \n "
" \" hex \" : \" hex \" , (string) The hex \n "
" \" type \" : \" pubkeyhash \" , (string) The type, eg 'pubkeyhash' \n "
" } \n "
" \" bip32_derivs \" : { (json object, optional) \n "
" \" pubkey \" : { (json object, optional) The public key with the derivation path as the value. \n "
" \" master_fingerprint \" : \" fingerprint \" (string) The fingerprint of the master key \n "
" \" path \" : \" path \" , (string) The path \n "
" } \n "
" ,... \n "
" } \n "
" \" final_scriptsig \" : { (json object, optional) \n "
" \" asm \" : \" asm \" , (string) The asm \n "
" \" hex \" : \" hex \" , (string) The hex \n "
" } \n "
" \" final_scriptwitness \" : [ \" hex \" , ...] (array of string) hex-encoded witness data (if any) \n "
" \" unknown \" : { (json object) The unknown global fields \n "
" \" key \" : \" value \" (key-value pair) An unknown key-value pair \n "
" ... \n "
" }, \n "
" } \n "
" ,... \n "
" ] \n "
" \" outputs \" : [ (array of json objects) \n "
" { \n "
" \" redeem_script \" : { (json object, optional) \n "
" \" asm \" : \" asm \" , (string) The asm \n "
" \" hex \" : \" hex \" , (string) The hex \n "
" \" type \" : \" pubkeyhash \" , (string) The type, eg 'pubkeyhash' \n "
" } \n "
" \" witness_script \" : { (json object, optional) \n "
" \" asm \" : \" asm \" , (string) The asm \n "
" \" hex \" : \" hex \" , (string) The hex \n "
" \" type \" : \" pubkeyhash \" , (string) The type, eg 'pubkeyhash' \n "
" } \n "
" \" bip32_derivs \" : [ (array of json objects, optional) \n "
" { \n "
" \" pubkey \" : \" pubkey \" , (string) The public key this path corresponds to \n "
" \" master_fingerprint \" : \" fingerprint \" (string) The fingerprint of the master key \n "
" \" path \" : \" path \" , (string) The path \n "
" } \n "
" } \n "
" ,... \n "
" ], \n "
" \" unknown \" : { (json object) The unknown global fields \n "
" \" key \" : \" value \" (key-value pair) An unknown key-value pair \n "
" ... \n "
" }, \n "
" } \n "
" ,... \n "
" ] \n "
" \" fee \" : fee (numeric, optional) The transaction fee paid if all UTXOs slots in the PSBT have been filled. \n "
" } \n "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
HelpExampleCli ( " decodepsbt " , " \" psbt \" " )
} ,
2019-06-19 13:59:11 +09:00
} . Check ( request ) ;
2018-06-28 19:04:40 -07:00
RPCTypeCheck ( request . params , { UniValue : : VSTR } ) ;
// Unserialize the transactions
PartiallySignedTransaction psbtx ;
std : : string error ;
2019-01-29 21:32:38 -08:00
if ( ! DecodeBase64PSBT ( psbtx , request . params [ 0 ] . get_str ( ) , error ) ) {
2018-06-28 19:04:40 -07:00
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , strprintf ( " TX decode failed %s " , error ) ) ;
}
UniValue result ( UniValue : : VOBJ ) ;
// Add the decoded tx
UniValue tx_univ ( UniValue : : VOBJ ) ;
TxToUniv ( CTransaction ( * psbtx . tx ) , uint256 ( ) , tx_univ , false ) ;
result . pushKV ( " tx " , tx_univ ) ;
// Unknown data
UniValue unknowns ( UniValue : : VOBJ ) ;
for ( auto entry : psbtx . unknown ) {
unknowns . pushKV ( HexStr ( entry . first ) , HexStr ( entry . second ) ) ;
}
result . pushKV ( " unknown " , unknowns ) ;
// inputs
CAmount total_in = 0 ;
bool have_all_utxos = true ;
UniValue inputs ( UniValue : : VARR ) ;
for ( unsigned int i = 0 ; i < psbtx . inputs . size ( ) ; + + i ) {
const PSBTInput & input = psbtx . inputs [ i ] ;
UniValue in ( UniValue : : VOBJ ) ;
// UTXOs
if ( ! input . witness_utxo . IsNull ( ) ) {
const CTxOut & txout = input . witness_utxo ;
UniValue out ( UniValue : : VOBJ ) ;
out . pushKV ( " amount " , ValueFromAmount ( txout . nValue ) ) ;
total_in + = txout . nValue ;
UniValue o ( UniValue : : VOBJ ) ;
ScriptToUniv ( txout . scriptPubKey , o , true ) ;
out . pushKV ( " scriptPubKey " , o ) ;
in . pushKV ( " witness_utxo " , out ) ;
} else if ( input . non_witness_utxo ) {
UniValue non_wit ( UniValue : : VOBJ ) ;
TxToUniv ( * input . non_witness_utxo , uint256 ( ) , non_wit , false ) ;
in . pushKV ( " non_witness_utxo " , non_wit ) ;
total_in + = input . non_witness_utxo - > vout [ psbtx . tx - > vin [ i ] . prevout . n ] . nValue ;
} else {
have_all_utxos = false ;
}
// Partial sigs
if ( ! input . partial_sigs . empty ( ) ) {
UniValue partial_sigs ( UniValue : : VOBJ ) ;
for ( const auto & sig : input . partial_sigs ) {
partial_sigs . pushKV ( HexStr ( sig . second . first ) , HexStr ( sig . second . second ) ) ;
}
in . pushKV ( " partial_signatures " , partial_sigs ) ;
}
// Sighash
if ( input . sighash_type > 0 ) {
in . pushKV ( " sighash " , SighashToStr ( ( unsigned char ) input . sighash_type ) ) ;
}
// Redeem script and witness script
if ( ! input . redeem_script . empty ( ) ) {
UniValue r ( UniValue : : VOBJ ) ;
ScriptToUniv ( input . redeem_script , r , false ) ;
in . pushKV ( " redeem_script " , r ) ;
}
if ( ! input . witness_script . empty ( ) ) {
UniValue r ( UniValue : : VOBJ ) ;
ScriptToUniv ( input . witness_script , r , false ) ;
in . pushKV ( " witness_script " , r ) ;
}
// keypaths
if ( ! input . hd_keypaths . empty ( ) ) {
UniValue keypaths ( UniValue : : VARR ) ;
for ( auto entry : input . hd_keypaths ) {
UniValue keypath ( UniValue : : VOBJ ) ;
keypath . pushKV ( " pubkey " , HexStr ( entry . first ) ) ;
2018-07-19 23:15:53 -07:00
keypath . pushKV ( " master_fingerprint " , strprintf ( " %08x " , ReadBE32 ( entry . second . fingerprint ) ) ) ;
keypath . pushKV ( " path " , WriteHDKeypath ( entry . second . path ) ) ;
2018-06-28 19:04:40 -07:00
keypaths . push_back ( keypath ) ;
}
in . pushKV ( " bip32_derivs " , keypaths ) ;
}
// Final scriptSig and scriptwitness
if ( ! input . final_script_sig . empty ( ) ) {
UniValue scriptsig ( UniValue : : VOBJ ) ;
scriptsig . pushKV ( " asm " , ScriptToAsmStr ( input . final_script_sig , true ) ) ;
scriptsig . pushKV ( " hex " , HexStr ( input . final_script_sig ) ) ;
in . pushKV ( " final_scriptSig " , scriptsig ) ;
}
if ( ! input . final_script_witness . IsNull ( ) ) {
UniValue txinwitness ( UniValue : : VARR ) ;
for ( const auto & item : input . final_script_witness . stack ) {
txinwitness . push_back ( HexStr ( item . begin ( ) , item . end ( ) ) ) ;
}
in . pushKV ( " final_scriptwitness " , txinwitness ) ;
}
// Unknown data
if ( input . unknown . size ( ) > 0 ) {
UniValue unknowns ( UniValue : : VOBJ ) ;
for ( auto entry : input . unknown ) {
unknowns . pushKV ( HexStr ( entry . first ) , HexStr ( entry . second ) ) ;
}
in . pushKV ( " unknown " , unknowns ) ;
}
inputs . push_back ( in ) ;
}
result . pushKV ( " inputs " , inputs ) ;
// outputs
CAmount output_value = 0 ;
UniValue outputs ( UniValue : : VARR ) ;
for ( unsigned int i = 0 ; i < psbtx . outputs . size ( ) ; + + i ) {
const PSBTOutput & output = psbtx . outputs [ i ] ;
UniValue out ( UniValue : : VOBJ ) ;
// Redeem script and witness script
if ( ! output . redeem_script . empty ( ) ) {
UniValue r ( UniValue : : VOBJ ) ;
ScriptToUniv ( output . redeem_script , r , false ) ;
out . pushKV ( " redeem_script " , r ) ;
}
if ( ! output . witness_script . empty ( ) ) {
UniValue r ( UniValue : : VOBJ ) ;
ScriptToUniv ( output . witness_script , r , false ) ;
out . pushKV ( " witness_script " , r ) ;
}
// keypaths
if ( ! output . hd_keypaths . empty ( ) ) {
UniValue keypaths ( UniValue : : VARR ) ;
for ( auto entry : output . hd_keypaths ) {
UniValue keypath ( UniValue : : VOBJ ) ;
keypath . pushKV ( " pubkey " , HexStr ( entry . first ) ) ;
2018-07-19 23:15:53 -07:00
keypath . pushKV ( " master_fingerprint " , strprintf ( " %08x " , ReadBE32 ( entry . second . fingerprint ) ) ) ;
keypath . pushKV ( " path " , WriteHDKeypath ( entry . second . path ) ) ;
2018-06-28 19:04:40 -07:00
keypaths . push_back ( keypath ) ;
}
out . pushKV ( " bip32_derivs " , keypaths ) ;
}
// Unknown data
if ( output . unknown . size ( ) > 0 ) {
UniValue unknowns ( UniValue : : VOBJ ) ;
for ( auto entry : output . unknown ) {
unknowns . pushKV ( HexStr ( entry . first ) , HexStr ( entry . second ) ) ;
}
out . pushKV ( " unknown " , unknowns ) ;
}
outputs . push_back ( out ) ;
// Fee calculation
output_value + = psbtx . tx - > vout [ i ] . nValue ;
}
result . pushKV ( " outputs " , outputs ) ;
if ( have_all_utxos ) {
result . pushKV ( " fee " , ValueFromAmount ( total_in - output_value ) ) ;
}
return result ;
}
UniValue combinepsbt ( const JSONRPCRequest & request )
{
2018-10-23 15:22:28 -04:00
RPCHelpMan { " combinepsbt " ,
2018-10-20 08:19:44 -04:00
" \n Combine multiple partially signed Bitcoin transactions into one transaction. \n "
" Implements the Combiner role. \n " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " txs " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " A json array of base64 strings of partially signed transactions " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " psbt " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED , " A base64 string of a PSBT " } ,
2018-11-23 11:21:38 -05:00
} ,
2018-10-23 15:22:28 -04:00
} ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2018-06-28 19:04:40 -07:00
" \" psbt \" (string) The base64-encoded partially signed transaction \n "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
HelpExampleCli ( " combinepsbt " , " [ \" mybase64_1 \" , \" mybase64_2 \" , \" mybase64_3 \" ] " )
} ,
2019-06-19 13:59:11 +09:00
} . Check ( request ) ;
2018-06-28 19:04:40 -07:00
RPCTypeCheck ( request . params , { UniValue : : VARR } , true ) ;
// Unserialize the transactions
std : : vector < PartiallySignedTransaction > psbtxs ;
UniValue txs = request . params [ 0 ] . get_array ( ) ;
2019-02-04 21:26:43 -06:00
if ( txs . empty ( ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Parameter 'txs' cannot be empty " ) ;
}
2018-06-28 19:04:40 -07:00
for ( unsigned int i = 0 ; i < txs . size ( ) ; + + i ) {
PartiallySignedTransaction psbtx ;
std : : string error ;
2019-01-29 21:32:38 -08:00
if ( ! DecodeBase64PSBT ( psbtx , txs [ i ] . get_str ( ) , error ) ) {
2018-06-28 19:04:40 -07:00
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , strprintf ( " TX decode failed %s " , error ) ) ;
}
psbtxs . push_back ( psbtx ) ;
}
2019-01-09 03:08:32 -08:00
PartiallySignedTransaction merged_psbt ;
2019-02-14 10:01:06 -05:00
const TransactionError error = CombinePSBTs ( merged_psbt , psbtxs ) ;
if ( error ! = TransactionError : : OK ) {
2019-01-09 03:08:32 -08:00
throw JSONRPCTransactionError ( error ) ;
2018-06-28 19:04:40 -07:00
}
CDataStream ssTx ( SER_NETWORK , PROTOCOL_VERSION ) ;
ssTx < < merged_psbt ;
return EncodeBase64 ( ( unsigned char * ) ssTx . data ( ) , ssTx . size ( ) ) ;
}
UniValue finalizepsbt ( const JSONRPCRequest & request )
{
2018-10-20 08:19:44 -04:00
RPCHelpMan { " finalizepsbt " ,
" Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a \n "
" network serialized transaction which can be broadcast with sendrawtransaction. Otherwise a PSBT will be \n "
" created which has the final_scriptSig and final_scriptWitness fields filled for inputs that are complete. \n "
" Implements the Finalizer and Extractor roles. \n " ,
{
2018-12-10 16:56:51 -05:00
{ " psbt " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " A base64 string of a PSBT " } ,
{ " extract " , RPCArg : : Type : : BOOL , /* default */ " true " , " If true and the transaction is complete, \n "
2018-11-23 11:21:38 -05:00
" extract and return the complete transaction in normal network serialization instead of the PSBT. " } ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2018-06-28 19:04:40 -07:00
" { \n "
" \" psbt \" : \" value \" , (string) The base64-encoded partially signed transaction if not extracted \n "
" \" hex \" : \" value \" , (string) The hex-encoded network transaction if extracted \n "
" \" complete \" : true|false, (boolean) If the transaction has a complete set of signatures \n "
" ] \n "
" } \n "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
HelpExampleCli ( " finalizepsbt " , " \" psbt \" " )
} ,
2019-06-19 13:59:11 +09:00
} . Check ( request ) ;
2018-06-28 19:04:40 -07:00
RPCTypeCheck ( request . params , { UniValue : : VSTR , UniValue : : VBOOL } , true ) ;
// Unserialize the transactions
PartiallySignedTransaction psbtx ;
std : : string error ;
2019-01-29 21:32:38 -08:00
if ( ! DecodeBase64PSBT ( psbtx , request . params [ 0 ] . get_str ( ) , error ) ) {
2018-06-28 19:04:40 -07:00
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , strprintf ( " TX decode failed %s " , error ) ) ;
}
2019-01-09 03:08:32 -08:00
bool extract = request . params [ 1 ] . isNull ( ) | | ( ! request . params [ 1 ] . isNull ( ) & & request . params [ 1 ] . get_bool ( ) ) ;
CMutableTransaction mtx ;
bool complete = FinalizeAndExtractPSBT ( psbtx , mtx ) ;
2018-06-28 19:04:40 -07:00
UniValue result ( UniValue : : VOBJ ) ;
CDataStream ssTx ( SER_NETWORK , PROTOCOL_VERSION ) ;
2019-01-09 03:08:32 -08:00
std : : string result_str ;
2018-06-28 19:04:40 -07:00
if ( complete & & extract ) {
ssTx < < mtx ;
2019-01-09 03:08:32 -08:00
result_str = HexStr ( ssTx . str ( ) ) ;
result . pushKV ( " hex " , result_str ) ;
2018-06-28 19:04:40 -07:00
} else {
ssTx < < psbtx ;
2019-01-09 03:08:32 -08:00
result_str = EncodeBase64 ( ssTx . str ( ) ) ;
result . pushKV ( " psbt " , result_str ) ;
2018-06-28 19:04:40 -07:00
}
2018-08-09 18:08:45 +02:00
result . pushKV ( " complete " , complete ) ;
2018-06-28 19:04:40 -07:00
return result ;
}
UniValue createpsbt ( const JSONRPCRequest & request )
{
2018-10-23 15:22:28 -04:00
RPCHelpMan { " createpsbt " ,
2018-10-20 08:19:44 -04:00
" \n Creates a transaction in the Partially Signed Transaction format. \n "
" Implements the Creator role. \n " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " inputs " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " A json array of json objects " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " " , RPCArg : : Type : : OBJ , RPCArg : : Optional : : OMITTED , " " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " txid " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The transaction id " } ,
{ " vout " , RPCArg : : Type : : NUM , RPCArg : : Optional : : NO , " The output number " } ,
{ " sequence " , RPCArg : : Type : : NUM , /* default */ " depends on the value of the 'replaceable' and 'locktime' arguments " , " The sequence number " } ,
2018-10-23 15:22:28 -04:00
} ,
2018-11-23 11:21:38 -05:00
} ,
} ,
2018-10-23 15:22:28 -04:00
} ,
2018-12-10 16:56:51 -05:00
{ " outputs " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " a json array with outputs (key-value pairs), where none of the keys are duplicated. \n "
2018-12-06 16:13:53 -05:00
" That is, each address can only appear once and there can only be one 'data' object. \n "
2018-11-23 11:21:38 -05:00
" For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also \n "
" accepted as second parameter. " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " " , RPCArg : : Type : : OBJ , RPCArg : : Optional : : OMITTED , " " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " address " , RPCArg : : Type : : AMOUNT , RPCArg : : Optional : : NO , " A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT } ,
2018-10-23 15:22:28 -04:00
} ,
2018-11-23 11:21:38 -05:00
} ,
2018-12-10 16:56:51 -05:00
{ " " , RPCArg : : Type : : OBJ , RPCArg : : Optional : : OMITTED , " " ,
2018-10-23 15:22:28 -04:00
{
2018-12-10 16:56:51 -05:00
{ " data " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " A key-value pair. The key must be \" data \" , the value is hex-encoded data " } ,
2018-11-23 11:21:38 -05:00
} ,
2018-10-23 15:22:28 -04:00
} ,
} ,
2018-11-23 11:21:38 -05:00
} ,
2018-12-10 16:56:51 -05:00
{ " locktime " , RPCArg : : Type : : NUM , /* default */ " 0 " , " Raw locktime. Non-0 value also locktime-activates inputs " } ,
{ " replaceable " , RPCArg : : Type : : BOOL , /* default */ " false " , " Marks this transaction as BIP125 replaceable. \n "
2018-11-23 11:21:38 -05:00
" Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible. " } ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2018-06-28 19:04:40 -07:00
" \" psbt \" (string) The resulting raw transaction (base64-encoded string) \n "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
HelpExampleCli ( " createpsbt " , " \" [{ \\ \" txid \\ \" : \\ \" myid \\ \" , \\ \" vout \\ \" :0}] \" \" [{ \\ \" data \\ \" : \\ \" 00010203 \\ \" }] \" " )
} ,
2019-06-19 13:59:11 +09:00
} . Check ( request ) ;
2018-06-28 19:04:40 -07:00
RPCTypeCheck ( request . params , {
UniValue : : VARR ,
UniValueType ( ) , // ARR or OBJ, checked later
UniValue : : VNUM ,
UniValue : : VBOOL ,
} , true
) ;
2019-04-27 19:44:38 +02:00
bool rbf = false ;
if ( ! request . params [ 3 ] . isNull ( ) ) {
rbf = request . params [ 3 ] . isTrue ( ) ;
}
CMutableTransaction rawTx = ConstructTransaction ( request . params [ 0 ] , request . params [ 1 ] , request . params [ 2 ] , rbf ) ;
2018-06-28 19:04:40 -07:00
// Make a blank psbt
PartiallySignedTransaction psbtx ;
psbtx . tx = rawTx ;
for ( unsigned int i = 0 ; i < rawTx . vin . size ( ) ; + + i ) {
psbtx . inputs . push_back ( PSBTInput ( ) ) ;
}
for ( unsigned int i = 0 ; i < rawTx . vout . size ( ) ; + + i ) {
psbtx . outputs . push_back ( PSBTOutput ( ) ) ;
}
// Serialize the PSBT
CDataStream ssTx ( SER_NETWORK , PROTOCOL_VERSION ) ;
ssTx < < psbtx ;
return EncodeBase64 ( ( unsigned char * ) ssTx . data ( ) , ssTx . size ( ) ) ;
}
UniValue converttopsbt ( const JSONRPCRequest & request )
{
2019-06-19 13:59:11 +09:00
RPCHelpMan { " converttopsbt " ,
2018-10-20 08:19:44 -04:00
" \n Converts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction \n "
" createpsbt and walletcreatefundedpsbt should be used for new applications. \n " ,
{
2018-12-10 16:56:51 -05:00
{ " hexstring " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The hex string of a raw transaction " } ,
2019-04-26 09:04:08 -04:00
{ " permitsigdata " , RPCArg : : Type : : BOOL , /* default */ " false " , " If true, any signatures in the input will be discarded and conversion \n "
2018-11-23 11:21:38 -05:00
" will continue. If false, RPC will fail if any signatures are present. " } ,
2018-12-10 16:56:51 -05:00
{ " iswitness " , RPCArg : : Type : : BOOL , /* default */ " depends on heuristic tests " , " Whether the transaction hex is a serialized witness transaction. \n "
2019-04-26 09:04:08 -04:00
" If iswitness is not present, heuristic tests will be used in decoding. \n "
" If true, only witness deserialization will be tried. \n "
" If false, only non-witness deserialization will be tried. \n "
" This boolean should reflect whether the transaction has inputs \n "
" (e.g. fully valid, or on-chain transactions), if known by the caller. "
} ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2018-06-28 19:04:40 -07:00
" \" psbt \" (string) The resulting raw transaction (base64-encoded string) \n "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
2018-06-28 19:04:40 -07:00
" \n Create a transaction \n "
+ HelpExampleCli ( " createrawtransaction " , " \" [{ \\ \" txid \\ \" : \\ \" myid \\ \" , \\ \" vout \\ \" :0}] \" \" [{ \\ \" data \\ \" : \\ \" 00010203 \\ \" }] \" " ) +
" \n Convert the transaction to a PSBT \n "
+ HelpExampleCli ( " converttopsbt " , " \" rawtransaction \" " )
2018-12-21 12:29:36 -05:00
} ,
2019-06-19 13:59:11 +09:00
} . Check ( request ) ;
2018-06-28 19:04:40 -07:00
RPCTypeCheck ( request . params , { UniValue : : VSTR , UniValue : : VBOOL , UniValue : : VBOOL } , true ) ;
// parse hex string from parameter
CMutableTransaction tx ;
bool permitsigdata = request . params [ 1 ] . isNull ( ) ? false : request . params [ 1 ] . get_bool ( ) ;
bool witness_specified = ! request . params [ 2 ] . isNull ( ) ;
bool iswitness = witness_specified ? request . params [ 2 ] . get_bool ( ) : false ;
2019-04-26 09:04:08 -04:00
const bool try_witness = witness_specified ? iswitness : true ;
const bool try_no_witness = witness_specified ? ! iswitness : true ;
2018-06-28 19:04:40 -07:00
if ( ! DecodeHexTx ( tx , request . params [ 0 ] . get_str ( ) , try_no_witness , try_witness ) ) {
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , " TX decode failed " ) ;
}
// Remove all scriptSigs and scriptWitnesses from inputs
for ( CTxIn & input : tx . vin ) {
2018-09-29 22:09:15 -04:00
if ( ( ! input . scriptSig . empty ( ) | | ! input . scriptWitness . IsNull ( ) ) & & ! permitsigdata ) {
2018-06-28 19:04:40 -07:00
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , " Inputs must not have scriptSigs and scriptWitnesses " ) ;
}
input . scriptSig . clear ( ) ;
input . scriptWitness . SetNull ( ) ;
}
// Make a blank psbt
PartiallySignedTransaction psbtx ;
psbtx . tx = tx ;
for ( unsigned int i = 0 ; i < tx . vin . size ( ) ; + + i ) {
psbtx . inputs . push_back ( PSBTInput ( ) ) ;
}
for ( unsigned int i = 0 ; i < tx . vout . size ( ) ; + + i ) {
psbtx . outputs . push_back ( PSBTOutput ( ) ) ;
}
// Serialize the PSBT
CDataStream ssTx ( SER_NETWORK , PROTOCOL_VERSION ) ;
ssTx < < psbtx ;
return EncodeBase64 ( ( unsigned char * ) ssTx . data ( ) , ssTx . size ( ) ) ;
}
2018-07-20 17:08:25 -07:00
UniValue utxoupdatepsbt ( const JSONRPCRequest & request )
{
RPCHelpMan { " utxoupdatepsbt " ,
2019-02-16 14:59:16 -08:00
" \n Updates all segwit inputs and outputs in a PSBT with data from output descriptors, the UTXO set or the mempool. \n " ,
2018-07-20 17:08:25 -07:00
{
2019-02-16 14:59:16 -08:00
{ " psbt " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " A base64 string of a PSBT " } ,
{ " descriptors " , RPCArg : : Type : : ARR , RPCArg : : Optional : : OMITTED_NAMED_ARG , " An array of either strings or objects " , {
{ " " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED , " An output descriptor " } ,
{ " " , RPCArg : : Type : : OBJ , RPCArg : : Optional : : OMITTED , " An object with an output descriptor and extra information " , {
{ " desc " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " An output descriptor " } ,
{ " range " , RPCArg : : Type : : RANGE , " 1000 " , " Up to what index HD chains should be explored (either end or [begin,end]) " } ,
} } ,
} } ,
2018-07-20 17:08:25 -07:00
} ,
RPCResult {
" \" psbt \" (string) The base64-encoded partially signed transaction with inputs updated \n "
} ,
RPCExamples {
HelpExampleCli ( " utxoupdatepsbt " , " \" psbt \" " )
2019-06-19 13:59:11 +09:00
} } . Check ( request ) ;
2018-07-20 17:08:25 -07:00
2019-02-16 14:59:16 -08:00
RPCTypeCheck ( request . params , { UniValue : : VSTR , UniValue : : VARR } , true ) ;
2018-07-20 17:08:25 -07:00
// Unserialize the transactions
PartiallySignedTransaction psbtx ;
std : : string error ;
if ( ! DecodeBase64PSBT ( psbtx , request . params [ 0 ] . get_str ( ) , error ) ) {
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , strprintf ( " TX decode failed %s " , error ) ) ;
}
2019-02-16 14:59:16 -08:00
// Parse descriptors, if any.
FlatSigningProvider provider ;
if ( ! request . params [ 1 ] . isNull ( ) ) {
auto descs = request . params [ 1 ] . get_array ( ) ;
for ( size_t i = 0 ; i < descs . size ( ) ; + + i ) {
EvalDescriptorStringOrObject ( descs [ i ] , provider ) ;
}
}
// We don't actually need private keys further on; hide them as a precaution.
HidingSigningProvider public_provider ( & provider , /* nosign */ true , /* nobip32derivs */ false ) ;
2018-07-20 17:08:25 -07:00
// Fetch previous transactions (inputs):
CCoinsView viewDummy ;
CCoinsViewCache view ( & viewDummy ) ;
{
LOCK2 ( cs_main , mempool . cs ) ;
2019-07-24 11:45:04 -04:00
CCoinsViewCache & viewChain = : : ChainstateActive ( ) . CoinsTip ( ) ;
2018-07-20 17:08:25 -07:00
CCoinsViewMemPool viewMempool ( & viewChain , mempool ) ;
view . SetBackend ( viewMempool ) ; // temporarily switch cache backend to db+mempool view
for ( const CTxIn & txin : psbtx . tx - > vin ) {
view . AccessCoin ( txin . prevout ) ; // Load entries from viewChain into view; can fail.
}
view . SetBackend ( viewDummy ) ; // switch back to avoid locking mempool for too long
}
// Fill the inputs
for ( unsigned int i = 0 ; i < psbtx . tx - > vin . size ( ) ; + + i ) {
PSBTInput & input = psbtx . inputs . at ( i ) ;
if ( input . non_witness_utxo | | ! input . witness_utxo . IsNull ( ) ) {
continue ;
}
const Coin & coin = view . AccessCoin ( psbtx . tx - > vin [ i ] . prevout ) ;
2019-02-16 14:59:16 -08:00
if ( IsSegWitOutput ( provider , coin . out . scriptPubKey ) ) {
2018-07-20 17:08:25 -07:00
input . witness_utxo = coin . out ;
}
2019-02-16 14:59:16 -08:00
// Update script/keypath information using descriptor data.
// Note that SignPSBTInput does a lot more than just constructing ECDSA signatures
// we don't actually care about those here, in fact.
SignPSBTInput ( public_provider , psbtx , i , /* sighash_type */ 1 ) ;
}
// Update script/keypath information using descriptor data.
for ( unsigned int i = 0 ; i < psbtx . tx - > vout . size ( ) ; + + i ) {
UpdatePSBTOutput ( public_provider , psbtx , i ) ;
2018-07-20 17:08:25 -07:00
}
CDataStream ssTx ( SER_NETWORK , PROTOCOL_VERSION ) ;
ssTx < < psbtx ;
return EncodeBase64 ( ( unsigned char * ) ssTx . data ( ) , ssTx . size ( ) ) ;
}
2018-07-20 18:24:16 -07:00
UniValue joinpsbts ( const JSONRPCRequest & request )
{
RPCHelpMan { " joinpsbts " ,
" \n Joins multiple distinct PSBTs with different inputs and outputs into one PSBT with inputs and outputs from all of the PSBTs \n "
" No input in any of the PSBTs can be in more than one of the PSBTs. \n " ,
{
{ " txs " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " A json array of base64 strings of partially signed transactions " ,
{
{ " psbt " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " A base64 string of a PSBT " }
} }
} ,
RPCResult {
" \" psbt \" (string) The base64-encoded partially signed transaction \n "
} ,
RPCExamples {
HelpExampleCli ( " joinpsbts " , " \" psbt \" " )
2019-06-19 13:59:11 +09:00
} } . Check ( request ) ;
2018-07-20 18:24:16 -07:00
RPCTypeCheck ( request . params , { UniValue : : VARR } , true ) ;
// Unserialize the transactions
std : : vector < PartiallySignedTransaction > psbtxs ;
UniValue txs = request . params [ 0 ] . get_array ( ) ;
if ( txs . size ( ) < = 1 ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " At least two PSBTs are required to join PSBTs. " ) ;
}
int32_t best_version = 1 ;
uint32_t best_locktime = 0xffffffff ;
for ( unsigned int i = 0 ; i < txs . size ( ) ; + + i ) {
PartiallySignedTransaction psbtx ;
std : : string error ;
if ( ! DecodeBase64PSBT ( psbtx , txs [ i ] . get_str ( ) , error ) ) {
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , strprintf ( " TX decode failed %s " , error ) ) ;
}
psbtxs . push_back ( psbtx ) ;
// Choose the highest version number
if ( psbtx . tx - > nVersion > best_version ) {
best_version = psbtx . tx - > nVersion ;
}
// Choose the lowest lock time
if ( psbtx . tx - > nLockTime < best_locktime ) {
best_locktime = psbtx . tx - > nLockTime ;
}
}
// Create a blank psbt where everything will be added
PartiallySignedTransaction merged_psbt ;
merged_psbt . tx = CMutableTransaction ( ) ;
merged_psbt . tx - > nVersion = best_version ;
merged_psbt . tx - > nLockTime = best_locktime ;
// Merge
for ( auto & psbt : psbtxs ) {
for ( unsigned int i = 0 ; i < psbt . tx - > vin . size ( ) ; + + i ) {
if ( ! merged_psbt . AddInput ( psbt . tx - > vin [ i ] , psbt . inputs [ i ] ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , strprintf ( " Input %s:%d exists in multiple PSBTs " , psbt . tx - > vin [ i ] . prevout . hash . ToString ( ) . c_str ( ) , psbt . tx - > vin [ i ] . prevout . n ) ) ;
}
}
for ( unsigned int i = 0 ; i < psbt . tx - > vout . size ( ) ; + + i ) {
merged_psbt . AddOutput ( psbt . tx - > vout [ i ] , psbt . outputs [ i ] ) ;
}
merged_psbt . unknown . insert ( psbt . unknown . begin ( ) , psbt . unknown . end ( ) ) ;
}
2019-07-31 18:02:24 -04:00
// Generate list of shuffled indices for shuffling inputs and outputs of the merged PSBT
std : : vector < int > input_indices ( merged_psbt . inputs . size ( ) ) ;
std : : iota ( input_indices . begin ( ) , input_indices . end ( ) , 0 ) ;
std : : vector < int > output_indices ( merged_psbt . outputs . size ( ) ) ;
std : : iota ( output_indices . begin ( ) , output_indices . end ( ) , 0 ) ;
// Shuffle input and output indicies lists
Shuffle ( input_indices . begin ( ) , input_indices . end ( ) , FastRandomContext ( ) ) ;
Shuffle ( output_indices . begin ( ) , output_indices . end ( ) , FastRandomContext ( ) ) ;
PartiallySignedTransaction shuffled_psbt ;
shuffled_psbt . tx = CMutableTransaction ( ) ;
shuffled_psbt . tx - > nVersion = merged_psbt . tx - > nVersion ;
shuffled_psbt . tx - > nLockTime = merged_psbt . tx - > nLockTime ;
for ( int i : input_indices ) {
shuffled_psbt . AddInput ( merged_psbt . tx - > vin [ i ] , merged_psbt . inputs [ i ] ) ;
}
for ( int i : output_indices ) {
shuffled_psbt . AddOutput ( merged_psbt . tx - > vout [ i ] , merged_psbt . outputs [ i ] ) ;
}
shuffled_psbt . unknown . insert ( merged_psbt . unknown . begin ( ) , merged_psbt . unknown . end ( ) ) ;
2018-07-20 18:24:16 -07:00
CDataStream ssTx ( SER_NETWORK , PROTOCOL_VERSION ) ;
2019-07-31 18:02:24 -04:00
ssTx < < shuffled_psbt ;
2018-07-20 18:24:16 -07:00
return EncodeBase64 ( ( unsigned char * ) ssTx . data ( ) , ssTx . size ( ) ) ;
}
2018-07-31 17:58:01 -07:00
UniValue analyzepsbt ( const JSONRPCRequest & request )
{
RPCHelpMan { " analyzepsbt " ,
" \n Analyzes and provides information about the current status of a PSBT and its inputs \n " ,
{
{ " psbt " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " A base64 string of a PSBT " }
} ,
RPCResult {
" { \n "
" \" inputs \" : [ (array of json objects) \n "
" { \n "
" \" has_utxo \" : true|false (boolean) Whether a UTXO is provided \n "
" \" is_final \" : true|false (boolean) Whether the input is finalized \n "
" \" missing \" : { (json object, optional) Things that are missing that are required to complete this input \n "
2019-03-08 12:20:51 +08:00
" \" pubkeys \" : [ (array, optional) \n "
2018-07-31 17:58:01 -07:00
" \" keyid \" (string) Public key ID, hash160 of the public key, of a public key whose BIP 32 derivation path is missing \n "
" ] \n "
2019-03-08 12:20:51 +08:00
" \" signatures \" : [ (array, optional) \n "
2018-07-31 17:58:01 -07:00
" \" keyid \" (string) Public key ID, hash160 of the public key, of a public key whose signature is missing \n "
" ] \n "
2019-03-08 12:20:51 +08:00
" \" redeemscript \" : \" hash \" (string, optional) Hash160 of the redeemScript that is missing \n "
" \" witnessscript \" : \" hash \" (string, optional) SHA256 of the witnessScript that is missing \n "
2018-07-31 17:58:01 -07:00
" } \n "
2019-03-08 12:20:51 +08:00
" \" next \" : \" role \" (string, optional) Role of the next person that this input needs to go to \n "
2018-07-31 17:58:01 -07:00
" } \n "
" ,... \n "
" ] \n "
2019-03-08 12:20:51 +08:00
" \" estimated_vsize \" : vsize (numeric, optional) Estimated vsize of the final signed transaction \n "
" \" estimated_feerate \" : feerate (numeric, optional) Estimated feerate of the final signed transaction in " + CURRENCY_UNIT + " /kB. Shown only if all UTXO slots in the PSBT have been filled. \n "
2018-07-31 17:58:01 -07:00
" \" fee \" : fee (numeric, optional) The transaction fee paid. Shown only if all UTXO slots in the PSBT have been filled. \n "
" \" next \" : \" role \" (string) Role of the next person that this psbt needs to go to \n "
" } \n "
} ,
RPCExamples {
HelpExampleCli ( " analyzepsbt " , " \" psbt \" " )
2019-06-19 13:59:11 +09:00
} } . Check ( request ) ;
2018-07-31 17:58:01 -07:00
RPCTypeCheck ( request . params , { UniValue : : VSTR } ) ;
// Unserialize the transaction
PartiallySignedTransaction psbtx ;
std : : string error ;
if ( ! DecodeBase64PSBT ( psbtx , request . params [ 0 ] . get_str ( ) , error ) ) {
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , strprintf ( " TX decode failed %s " , error ) ) ;
}
2019-03-01 00:25:10 -08:00
PSBTAnalysis psbta = AnalyzePSBT ( psbtx ) ;
2018-07-31 17:58:01 -07:00
UniValue result ( UniValue : : VOBJ ) ;
UniValue inputs_result ( UniValue : : VARR ) ;
2019-03-01 00:25:10 -08:00
for ( const auto & input : psbta . inputs ) {
2018-07-31 17:58:01 -07:00
UniValue input_univ ( UniValue : : VOBJ ) ;
UniValue missing ( UniValue : : VOBJ ) ;
2019-03-01 00:25:10 -08:00
input_univ . pushKV ( " has_utxo " , input . has_utxo ) ;
input_univ . pushKV ( " is_final " , input . is_final ) ;
input_univ . pushKV ( " next " , PSBTRoleName ( input . next ) ) ;
2018-07-31 17:58:01 -07:00
2019-03-01 00:25:10 -08:00
if ( ! input . missing_pubkeys . empty ( ) ) {
UniValue missing_pubkeys_univ ( UniValue : : VARR ) ;
for ( const CKeyID & pubkey : input . missing_pubkeys ) {
missing_pubkeys_univ . push_back ( HexStr ( pubkey ) ) ;
2018-07-31 17:58:01 -07:00
}
2019-03-01 00:25:10 -08:00
missing . pushKV ( " pubkeys " , missing_pubkeys_univ ) ;
}
if ( ! input . missing_redeem_script . IsNull ( ) ) {
missing . pushKV ( " redeemscript " , HexStr ( input . missing_redeem_script ) ) ;
}
if ( ! input . missing_witness_script . IsNull ( ) ) {
missing . pushKV ( " witnessscript " , HexStr ( input . missing_witness_script ) ) ;
}
if ( ! input . missing_sigs . empty ( ) ) {
UniValue missing_sigs_univ ( UniValue : : VARR ) ;
for ( const CKeyID & pubkey : input . missing_sigs ) {
missing_sigs_univ . push_back ( HexStr ( pubkey ) ) ;
}
missing . pushKV ( " signatures " , missing_sigs_univ ) ;
}
if ( ! missing . getKeys ( ) . empty ( ) ) {
input_univ . pushKV ( " missing " , missing ) ;
2018-07-31 17:58:01 -07:00
}
inputs_result . push_back ( input_univ ) ;
}
result . pushKV ( " inputs " , inputs_result ) ;
2019-03-01 00:25:10 -08:00
if ( psbta . estimated_vsize ! = nullopt ) {
result . pushKV ( " estimated_vsize " , ( int ) * psbta . estimated_vsize ) ;
2018-07-31 17:58:01 -07:00
}
2019-03-01 00:25:10 -08:00
if ( psbta . estimated_feerate ! = nullopt ) {
result . pushKV ( " estimated_feerate " , ValueFromAmount ( psbta . estimated_feerate - > GetFeePerK ( ) ) ) ;
2018-07-31 17:58:01 -07:00
}
2019-03-01 00:25:10 -08:00
if ( psbta . fee ! = nullopt ) {
result . pushKV ( " fee " , ValueFromAmount ( * psbta . fee ) ) ;
}
result . pushKV ( " next " , PSBTRoleName ( psbta . next ) ) ;
2018-07-31 17:58:01 -07:00
return result ;
}
2018-08-20 14:19:43 +02:00
// clang-format off
2016-03-29 19:43:02 +02:00
static const CRPCCommand commands [ ] =
2017-06-12 12:23:02 -07:00
{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
{ " rawtransactions " , " getrawtransaction " , & getrawtransaction , { " txid " , " verbose " , " blockhash " } } ,
{ " rawtransactions " , " createrawtransaction " , & createrawtransaction , { " inputs " , " outputs " , " locktime " , " replaceable " } } ,
{ " rawtransactions " , " decoderawtransaction " , & decoderawtransaction , { " hexstring " , " iswitness " } } ,
{ " rawtransactions " , " decodescript " , & decodescript , { " hexstring " } } ,
2018-06-27 17:21:07 +09:00
{ " rawtransactions " , " sendrawtransaction " , & sendrawtransaction , { " hexstring " , " allowhighfees|maxfeerate " } } ,
2017-06-12 12:23:02 -07:00
{ " rawtransactions " , " combinerawtransaction " , & combinerawtransaction , { " txs " } } ,
{ " rawtransactions " , " signrawtransactionwithkey " , & signrawtransactionwithkey , { " hexstring " , " privkeys " , " prevtxs " , " sighashtype " } } ,
2019-02-14 17:07:29 +09:00
{ " rawtransactions " , " testmempoolaccept " , & testmempoolaccept , { " rawtxs " , " allowhighfees|maxfeerate " } } ,
2018-06-28 19:04:40 -07:00
{ " rawtransactions " , " decodepsbt " , & decodepsbt , { " psbt " } } ,
{ " rawtransactions " , " combinepsbt " , & combinepsbt , { " txs " } } ,
{ " rawtransactions " , " finalizepsbt " , & finalizepsbt , { " psbt " , " extract " } } ,
{ " rawtransactions " , " createpsbt " , & createpsbt , { " inputs " , " outputs " , " locktime " , " replaceable " } } ,
{ " rawtransactions " , " converttopsbt " , & converttopsbt , { " hexstring " , " permitsigdata " , " iswitness " } } ,
2019-07-02 18:34:18 +01:00
{ " rawtransactions " , " utxoupdatepsbt " , & utxoupdatepsbt , { " psbt " , " descriptors " } } ,
2018-07-20 18:24:16 -07:00
{ " rawtransactions " , " joinpsbts " , & joinpsbts , { " txs " } } ,
2018-07-31 17:58:01 -07:00
{ " rawtransactions " , " analyzepsbt " , & analyzepsbt , { " psbt " } } ,
2017-06-12 12:23:02 -07:00
{ " blockchain " , " gettxoutproof " , & gettxoutproof , { " txids " , " blockhash " } } ,
{ " blockchain " , " verifytxoutproof " , & verifytxoutproof , { " proof " } } ,
2016-03-29 19:43:02 +02:00
} ;
2018-08-20 14:19:43 +02:00
// clang-format on
2016-03-29 19:43:02 +02:00
2016-06-07 18:42:42 +02:00
void RegisterRawTransactionRPCCommands ( CRPCTable & t )
2016-03-29 19:43:02 +02:00
{
for ( unsigned int vcidx = 0 ; vcidx < ARRAYLEN ( commands ) ; vcidx + + )
2016-06-07 18:42:42 +02:00
t . appendCommand ( commands [ vcidx ] . name , & commands [ vcidx ] ) ;
2016-03-29 19:43:02 +02:00
}