2012-05-31 16:01:16 -04:00
// Copyright (c) 2010 Satoshi Nakamoto
2022-12-24 23:49:50 +00:00
// Copyright (c) 2009-2022 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.
2019-07-25 13:20:38 -04:00
# include <base58.h>
2017-11-10 13:57:53 +13:00
# include <chain.h>
# include <coins.h>
2021-09-11 10:29:00 +08:00
# include <consensus/amount.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>
2021-04-02 20:42:05 +02:00
# include <node/blockstorage.h>
2019-04-10 13:38:41 +00:00
# include <node/coin.h>
2019-09-17 18:28:03 -04:00
# include <node/context.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>
2021-02-11 10:50:45 -08:00
# include <policy/packages.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-09-17 19:05:26 -04:00
# include <rpc/blockchain.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>
2021-04-21 16:39:40 +02:00
# include <rpc/server_util.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/sign.h>
2019-06-06 22:52:24 +02:00
# include <script/signingprovider.h>
2023-08-09 07:36:08 -04:00
# include <script/solver.h>
2017-11-10 13:57:53 +13:00
# include <uint256.h>
2021-11-21 11:17:59 +02:00
# include <undo.h>
2020-07-19 17:25:07 +02:00
# include <util/bip32.h>
2022-04-09 02:14:02 +02:00
# include <util/check.h>
2018-10-22 15:51:11 -07:00
# include <util/strencodings.h>
2020-02-12 23:01:45 -05:00
# include <util/string.h>
2022-03-31 12:02:22 +02:00
# include <util/vector.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
2021-11-12 10:06:00 -05:00
using node : : AnalyzePSBT ;
using node : : FindCoins ;
using node : : GetTransaction ;
using node : : NodeContext ;
using node : : PSBTAnalysis ;
2023-01-26 11:21:27 +00:00
static void TxToJSON ( const CTransaction & tx , const uint256 hashBlock , UniValue & entry ,
Chainstate & active_chainstate , const CTxUndo * txundo = nullptr ,
TxVerbosity verbosity = TxVerbosity : : SHOW_DETAILS )
2012-05-31 16:01:16 -04:00
{
2023-01-26 11:21:27 +00:00
CHECK_NONFATAL ( verbosity > = TxVerbosity : : SHOW_DETAILS ) ;
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.
2023-11-16 10:35:08 +01:00
TxToUniv ( tx , /*block_hash=*/ uint256 ( ) , entry , /*include_hex=*/ true , txundo , verbosity ) ;
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 ( ) ) ;
2022-03-02 15:42:57 +10:00
const CBlockIndex * pindex = active_chainstate . m_blockman . LookupBlockIndex ( hashBlock ) ;
2018-01-12 00:23:09 +00:00
if ( pindex ) {
2020-10-14 16:05:27 -04:00
if ( active_chainstate . m_chain . Contains ( pindex ) ) {
entry . pushKV ( " confirmations " , 1 + active_chainstate . m_chain . 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
}
}
}
2022-12-21 00:46:16 +02:00
static std : : vector < RPCResult > ScriptPubKeyDoc ( ) {
return
{
{ RPCResult : : Type : : STR , " asm " , " Disassembly of the public key script " } ,
{ RPCResult : : Type : : STR , " desc " , " Inferred descriptor for the output " } ,
{ RPCResult : : Type : : STR_HEX , " hex " , " The raw public key script bytes, hex-encoded " } ,
{ RPCResult : : Type : : STR , " address " , /*optional=*/ true , " The Bitcoin address (only if a well-defined address exists) " } ,
{ RPCResult : : Type : : STR , " type " , " The type (one of: " + GetAllOutputTypes ( ) + " ) " } ,
} ;
}
2022-03-31 12:02:22 +02:00
static std : : vector < RPCResult > DecodeTxDoc ( const std : : string & txid_field_doc )
{
return {
{ RPCResult : : Type : : STR_HEX , " txid " , txid_field_doc } ,
{ RPCResult : : Type : : STR_HEX , " hash " , " The transaction hash (differs from txid for witness transactions) " } ,
{ RPCResult : : Type : : NUM , " size " , " The serialized transaction size " } ,
{ RPCResult : : Type : : NUM , " vsize " , " The virtual transaction size (differs from size for witness transactions) " } ,
{ RPCResult : : Type : : NUM , " weight " , " The transaction's weight (between vsize*4-3 and vsize*4) " } ,
{ RPCResult : : Type : : NUM , " version " , " The version " } ,
{ RPCResult : : Type : : NUM_TIME , " locktime " , " The lock time " } ,
{ RPCResult : : Type : : ARR , " vin " , " " ,
{
{ RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR_HEX , " coinbase " , /*optional=*/ true , " The coinbase value (only if coinbase transaction) " } ,
{ RPCResult : : Type : : STR_HEX , " txid " , /*optional=*/ true , " The transaction id (if not coinbase transaction) " } ,
{ RPCResult : : Type : : NUM , " vout " , /*optional=*/ true , " The output number (if not coinbase transaction) " } ,
{ RPCResult : : Type : : OBJ , " scriptSig " , /*optional=*/ true , " The script (if not coinbase transaction) " ,
{
2022-07-25 03:36:02 +00:00
{ RPCResult : : Type : : STR , " asm " , " Disassembly of the signature script " } ,
{ RPCResult : : Type : : STR_HEX , " hex " , " The raw signature script bytes, hex-encoded " } ,
2022-03-31 12:02:22 +02:00
} } ,
{ RPCResult : : Type : : ARR , " txinwitness " , /*optional=*/ true , " " ,
{
{ RPCResult : : Type : : STR_HEX , " hex " , " hex-encoded witness data (if any) " } ,
} } ,
{ RPCResult : : Type : : NUM , " sequence " , " The script sequence number " } ,
} } ,
} } ,
{ RPCResult : : Type : : ARR , " vout " , " " ,
{
{ RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR_AMOUNT , " value " , " The value in " + CURRENCY_UNIT } ,
{ RPCResult : : Type : : NUM , " n " , " index " } ,
2022-12-21 00:46:16 +02:00
{ RPCResult : : Type : : OBJ , " scriptPubKey " , " " , ScriptPubKeyDoc ( ) } ,
2022-03-31 12:02:22 +02:00
} } ,
} } ,
} ;
}
2021-11-30 17:12:57 +08:00
static std : : vector < RPCArg > CreateTxDoc ( )
{
return {
{ " inputs " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " The inputs " ,
{
{ " " , RPCArg : : Type : : OBJ , RPCArg : : Optional : : OMITTED , " " ,
{
{ " 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 , RPCArg : : DefaultHint { " depends on the value of the 'replaceable' and 'locktime' arguments " } , " The sequence number " } ,
} ,
} ,
} ,
} ,
2023-08-22 21:46:08 -04:00
{ " outputs " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " The outputs specified as key-value pairs. \n "
" Each key may only appear once, i.e. there can only be one 'data' output, and no address may be duplicated. \n "
" At least one output of either type must be specified. \n "
2021-11-30 17:12:57 +08:00
" For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also \n "
" accepted as second parameter. " ,
{
{ " " , RPCArg : : Type : : OBJ_USER_KEYS , RPCArg : : Optional : : OMITTED , " " ,
{
{ " 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 } ,
} ,
} ,
{ " " , RPCArg : : Type : : OBJ , RPCArg : : Optional : : OMITTED , " " ,
{
{ " data " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " A key-value pair. The key must be \" data \" , the value is hex-encoded data " } ,
} ,
} ,
} ,
2022-12-12 14:30:14 +01:00
RPCArgOptions { . skip_type_check = true } } ,
2021-11-30 17:12:57 +08:00
{ " locktime " , RPCArg : : Type : : NUM , RPCArg : : Default { 0 } , " Raw locktime. Non-0 value also locktime-activates inputs " } ,
2022-07-13 16:29:27 -04:00
{ " replaceable " , RPCArg : : Type : : BOOL , RPCArg : : Default { true } , " Marks this transaction as BIP125-replaceable. \n "
2021-11-30 17:12:57 +08: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. " } ,
} ;
}
2022-08-03 19:32:59 -04:00
// Update PSBT with information from the mempool, the UTXO set, the txindex, and the provided descriptors.
// Optionally, sign the inputs that we can using information from the descriptors.
PartiallySignedTransaction ProcessPSBT ( const std : : string & psbt_string , const std : : any & context , const HidingSigningProvider & provider , int sighash_type , bool finalize )
2022-07-27 14:24:19 +05:30
{
// Unserialize the transactions
PartiallySignedTransaction psbtx ;
std : : string error ;
if ( ! DecodeBase64PSBT ( psbtx , psbt_string , error ) ) {
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , strprintf ( " TX decode failed %s " , error ) ) ;
}
2022-08-23 15:24:00 -04:00
if ( g_txindex ) g_txindex - > BlockUntilSyncedToCurrentChain ( ) ;
const NodeContext & node = EnsureAnyNodeContext ( context ) ;
2022-07-27 14:24:19 +05:30
2022-08-23 15:24:00 -04:00
// If we can't find the corresponding full transaction for all of our inputs,
// this will be used to find just the utxos for the segwit inputs for which
// the full transaction isn't found
std : : map < COutPoint , Coin > coins ;
2022-07-27 14:24:19 +05:30
2022-08-23 15:24:00 -04:00
// Fetch previous transactions:
// First, look in the txindex and the mempool
2022-07-27 14:24:19 +05:30
for ( unsigned int i = 0 ; i < psbtx . tx - > vin . size ( ) ; + + i ) {
2022-08-23 15:24:00 -04:00
PSBTInput & psbt_input = psbtx . inputs . at ( i ) ;
const CTxIn & tx_in = psbtx . tx - > vin . at ( i ) ;
2022-07-27 14:24:19 +05:30
2022-08-23 15:24:00 -04:00
// The `non_witness_utxo` is the whole previous transaction
if ( psbt_input . non_witness_utxo ) continue ;
CTransactionRef tx ;
// Look in the txindex
if ( g_txindex ) {
uint256 block_hash ;
g_txindex - > FindTx ( tx_in . prevout . hash , block_hash , tx ) ;
}
// If we still don't have it look in the mempool
if ( ! tx ) {
tx = node . mempool - > get ( tx_in . prevout . hash ) ;
}
if ( tx ) {
psbt_input . non_witness_utxo = tx ;
} else {
coins [ tx_in . prevout ] ; // Create empty map entry keyed by prevout
}
}
// If we still haven't found all of the inputs, look for the missing ones in the utxo set
if ( ! coins . empty ( ) ) {
FindCoins ( node , coins ) ;
for ( unsigned int i = 0 ; i < psbtx . tx - > vin . size ( ) ; + + i ) {
PSBTInput & input = psbtx . inputs . at ( i ) ;
// If there are still missing utxos, add them if they were found in the utxo set
if ( ! input . non_witness_utxo ) {
const CTxIn & tx_in = psbtx . tx - > vin . at ( i ) ;
const Coin & coin = coins . at ( tx_in . prevout ) ;
if ( ! coin . out . IsNull ( ) & & IsSegWitOutput ( provider , coin . out . scriptPubKey ) ) {
input . witness_utxo = coin . out ;
}
}
2022-07-27 14:24:19 +05:30
}
2022-08-23 15:24:00 -04:00
}
2022-07-27 14:24:19 +05:30
2022-08-23 15:24:00 -04:00
const PrecomputedTransactionData & txdata = PrecomputePSBTData ( psbtx ) ;
2022-07-27 14:24:19 +05:30
2022-08-23 15:24:00 -04:00
for ( unsigned int i = 0 ; i < psbtx . tx - > vin . size ( ) ; + + i ) {
if ( PSBTInputSigned ( psbtx . inputs . at ( i ) ) ) {
continue ;
2022-07-27 14:24:19 +05:30
}
// Update script/keypath information using descriptor data.
2022-08-03 19:32:59 -04:00
// Note that SignPSBTInput does a lot more than just constructing ECDSA signatures.
// We only actually care about those if our signing provider doesn't hide private
// information, as is the case with `descriptorprocesspsbt`
SignPSBTInput ( provider , psbtx , /*index=*/ i , & txdata , sighash_type , /*out_sigdata=*/ nullptr , finalize ) ;
2022-07-27 14:24:19 +05:30
}
// Update script/keypath information using descriptor data.
for ( unsigned int i = 0 ; i < psbtx . tx - > vout . size ( ) ; + + i ) {
UpdatePSBTOutput ( provider , psbtx , i ) ;
}
2022-08-23 15:24:00 -04:00
RemoveUnnecessaryTransactions ( psbtx , /*sighash_type=*/ 1 ) ;
2022-07-27 14:24:19 +05:30
return psbtx ;
}
2020-08-31 18:29:48 +02:00
static RPCHelpMan getrawtransaction ( )
2012-05-31 16:01:16 -04:00
{
2020-08-31 18:29:48 +02:00
return RPCHelpMan {
2019-02-02 19:48:54 -08:00
" getrawtransaction " ,
2021-11-21 11:17:59 +02:00
" By default, this call only returns a transaction if it is in the mempool. If -txindex is enabled \n "
2021-07-01 10:17:28 -04:00
" and no blockhash argument is passed, it will return the transaction if it is in the mempool or any block. \n "
2021-07-22 20:32:04 +02:00
" If a blockhash argument is passed, it will return the transaction if \n "
2021-11-21 11:17:59 +02:00
" the specified block is available and the transaction is in that block. \n \n "
" Hint: Use gettransaction for wallet transactions. \n \n "
2019-02-02 19:48:54 -08:00
2021-11-21 11:17:59 +02:00
" If verbosity is 0 or omitted, returns the serialized transaction as a hex-encoded string. \n "
2022-12-21 00:46:16 +02:00
" If verbosity is 1, returns a JSON Object with information about the transaction. \n "
" If verbosity is 2, returns a JSON Object with information about the transaction, including fee and prevout information. " ,
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 " } ,
2022-12-12 14:30:14 +01:00
{ " verbosity|verbose " , RPCArg : : Type : : NUM , RPCArg : : Default { 0 } , " 0 for hex-encoded data, 1 for a JSON object, and 2 for JSON object with fee and prevout " ,
RPCArgOptions { . skip_type_check = true } } ,
2023-01-19 10:33:27 +00:00
{ " blockhash " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : OMITTED , " The block in which to look for the transaction " } ,
2018-12-21 12:29:36 -05:00
} ,
{
2021-11-21 11:17:59 +02:00
RPCResult { " if verbosity is not set or set to 0 " ,
RPCResult : : Type : : STR , " data " , " The serialized transaction as a hex-encoded string for 'txid' "
2018-12-21 12:29:36 -05:00
} ,
2021-11-21 11:17:59 +02:00
RPCResult { " if verbosity is set to 1 " ,
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : OBJ , " " , " " ,
2022-03-31 12:02:22 +02:00
Cat < std : : vector < RPCResult > > (
2020-01-10 00:00:57 +07:00
{
2021-12-08 11:55:46 +01:00
{ RPCResult : : Type : : BOOL , " in_active_chain " , /*optional=*/ true , " Whether specified block is in the active chain or not (only present with explicit \" blockhash \" argument) " } ,
{ RPCResult : : Type : : STR_HEX , " blockhash " , /*optional=*/ true , " the block hash " } ,
{ RPCResult : : Type : : NUM , " confirmations " , /*optional=*/ true , " The confirmations " } ,
{ RPCResult : : Type : : NUM_TIME , " blocktime " , /*optional=*/ true , " The block time expressed in " + UNIX_EPOCH_TIME } ,
{ RPCResult : : Type : : NUM , " time " , /*optional=*/ true , " Same as \" blocktime \" " } ,
2022-03-31 12:02:22 +02:00
{ RPCResult : : Type : : STR_HEX , " hex " , " The serialized, hex-encoded data for 'txid' " } ,
} ,
DecodeTxDoc ( /*txid_field_doc=*/ " The transaction id (same as provided) " ) ) ,
2018-12-21 12:29:36 -05:00
} ,
2021-11-21 11:17:59 +02:00
RPCResult { " for verbosity = 2 " ,
RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : ELISION , " " , " Same output as verbosity = 1 " } ,
2022-12-21 00:46:16 +02:00
{ RPCResult : : Type : : NUM , " fee " , /*optional=*/ true , " transaction fee in " + CURRENCY_UNIT + " , omitted if block undo data is not available " } ,
2021-11-21 11:17:59 +02:00
{ RPCResult : : Type : : ARR , " vin " , " " ,
{
2023-01-25 21:11:21 +02:00
{ RPCResult : : Type : : OBJ , " " , " utxo being spent " ,
2021-11-21 11:17:59 +02:00
{
{ RPCResult : : Type : : ELISION , " " , " Same output as verbosity = 1 " } ,
2023-01-25 21:11:21 +02:00
{ RPCResult : : Type : : OBJ , " prevout " , /*optional=*/ true , " The previous output, omitted if block undo data is not available " ,
2021-11-21 11:17:59 +02:00
{
{ RPCResult : : Type : : BOOL , " generated " , " Coinbase or not " } ,
{ RPCResult : : Type : : NUM , " height " , " The height of the prevout " } ,
{ RPCResult : : Type : : STR_AMOUNT , " value " , " The value in " + CURRENCY_UNIT } ,
2022-12-21 00:46:16 +02:00
{ RPCResult : : Type : : OBJ , " scriptPubKey " , " " , ScriptPubKeyDoc ( ) } ,
2021-11-21 11:17:59 +02:00
} } ,
} } ,
} } ,
} } ,
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
HelpExampleCli ( " getrawtransaction " , " \" mytxid \" " )
2021-11-21 11:17:59 +02:00
+ HelpExampleCli ( " getrawtransaction " , " \" mytxid \" 1 " )
+ HelpExampleRpc ( " getrawtransaction " , " \" mytxid \" , 1 " )
+ HelpExampleCli ( " getrawtransaction " , " \" mytxid \" 0 \" myblockhash \" " )
+ HelpExampleCli ( " getrawtransaction " , " \" mytxid \" 1 \" myblockhash \" " )
+ HelpExampleCli ( " getrawtransaction " , " \" mytxid \" 2 \" myblockhash \" " )
2018-12-21 12:29:36 -05:00
} ,
2020-08-31 18:29:48 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2021-04-13 17:04:43 -04:00
const NodeContext & node = EnsureAnyNodeContext ( request . context ) ;
2021-04-12 18:41:05 -04:00
ChainstateManager & chainman = EnsureChainman ( node ) ;
2020-07-26 09:59:11 +02:00
2016-09-22 09:46:41 +02:00
uint256 hash = ParseHashV ( request . params [ 0 ] , " parameter 1 " ) ;
2022-03-02 15:42:57 +10:00
const CBlockIndex * blockindex = nullptr ;
2012-05-31 16:01:16 -04:00
2022-05-18 18:36:31 +02:00
if ( hash = = chainman . GetParams ( ) . GenesisBlock ( ) . hashMerkleRoot ) {
2018-01-27 20:10:56 +13:00
// 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 " ) ;
}
2021-11-21 11:17:59 +02:00
// Accept either a bool (true) or a num (>=0) to indicate verbosity.
int verbosity { 0 } ;
2017-07-10 11:44:39 -04:00
if ( ! request . params [ 1 ] . isNull ( ) ) {
2021-11-21 11:17:59 +02:00
if ( request . params [ 1 ] . isBool ( ) ) {
verbosity = request . params [ 1 ] . get_bool ( ) ;
} else {
verbosity = request . params [ 1 ] . getInt < int > ( ) ;
}
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 " ) ;
2020-10-14 16:05:27 -04:00
blockindex = chainman . m_blockman . LookupBlockIndex ( blockhash ) ;
2018-01-12 00:23:09 +00:00
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
}
}
2017-12-08 11:49:08 -08:00
bool f_txindex_ready = false ;
if ( g_txindex & & ! blockindex ) {
f_txindex_ready = g_txindex - > BlockUntilSyncedToCurrentChain ( ) ;
}
2017-04-25 17:29:24 +09:00
uint256 hash_block ;
2023-02-18 15:49:41 +01:00
const CTransactionRef tx = GetTransaction ( blockindex , node . mempool . get ( ) , hash , hash_block , chainman . m_blockman ) ;
2020-07-26 09:59:11 +02:00
if ( ! tx ) {
2017-04-25 17:29:24 +09:00
std : : string errmsg ;
if ( blockindex ) {
2022-01-19 13:42:32 +01:00
const bool block_has_data = WITH_LOCK ( : : cs_main , return blockindex - > nStatus & BLOCK_HAVE_DATA ) ;
if ( ! block_has_data ) {
2017-04-25 17:29:24 +09:00
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
2021-11-21 11:17:59 +02:00
if ( verbosity < = 0 ) {
2023-11-16 10:35:08 +01:00
return EncodeHexTx ( * tx ) ;
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 ) ;
2021-11-21 11:17:59 +02:00
if ( blockindex ) {
LOCK ( cs_main ) ;
result . pushKV ( " in_active_chain " , chainman . ActiveChain ( ) . Contains ( blockindex ) ) ;
}
// If request is verbosity >= 1 but no blockhash was given, then look up the blockindex
if ( request . params [ 2 ] . isNull ( ) ) {
LOCK ( cs_main ) ;
2023-12-07 10:21:14 +01:00
blockindex = chainman . m_blockman . LookupBlockIndex ( hash_block ) ; // May be nullptr for mempool transactions
2021-11-21 11:17:59 +02:00
}
2023-12-07 10:21:14 +01:00
if ( verbosity = = 1 ) {
2021-11-21 11:17:59 +02:00
TxToJSON ( * tx , hash_block , result , chainman . ActiveChainstate ( ) ) ;
return result ;
}
CBlockUndo blockUndo ;
CBlock block ;
2023-12-07 10:21:14 +01:00
if ( tx - > IsCoinBase ( ) | | ! blockindex | | WITH_LOCK ( : : cs_main , return chainman . m_blockman . IsBlockPruned ( * blockindex ) ) | |
2023-02-18 15:49:41 +01:00
! ( chainman . m_blockman . UndoReadFromDisk ( blockUndo , * blockindex ) & & chainman . m_blockman . ReadBlockFromDisk ( block , * blockindex ) ) ) {
2021-11-21 11:17:59 +02:00
TxToJSON ( * tx , hash_block , result , chainman . ActiveChainstate ( ) ) ;
return result ;
}
CTxUndo * undoTX { nullptr } ;
auto it = std : : find_if ( block . vtx . begin ( ) , block . vtx . end ( ) , [ tx ] ( CTransactionRef t ) { return * t = = * tx ; } ) ;
if ( it ! = block . vtx . end ( ) ) {
// -1 as blockundo does not have coinbase tx
undoTX = & blockUndo . vtxundo . at ( it - block . vtx . begin ( ) - 1 ) ;
}
TxToJSON ( * tx , hash_block , result , chainman . ActiveChainstate ( ) , undoTX , TxVerbosity : : SHOW_DETAILS_AND_PREVOUT ) ;
2012-05-31 16:01:16 -04:00
return result ;
2020-08-31 18:29:48 +02:00
} ,
} ;
2012-05-31 16:01:16 -04:00
}
2020-08-31 18:29:48 +02:00
static RPCHelpMan createrawtransaction ( )
2018-06-27 17:02:07 -07:00
{
2020-08-31 18:29:48 +02:00
return RPCHelpMan { " createrawtransaction " ,
2018-11-23 11:21:38 -05:00
" \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 " ,
2021-11-30 17:12:57 +08:00
CreateTxDoc ( ) ,
2018-12-21 12:29:36 -05:00
RPCResult {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : STR_HEX , " transaction " , " hex string of the transaction "
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
} ,
2020-08-31 18:29:48 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2022-07-13 16:29:27 -04:00
std : : optional < bool > rbf ;
2019-04-27 19:44:38 +02:00
if ( ! request . params [ 3 ] . isNull ( ) ) {
2022-12-05 14:55:32 +01:00
rbf = request . params [ 3 ] . get_bool ( ) ;
2019-04-27 19:44:38 +02:00
}
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 ) ) ;
2020-08-31 18:29:48 +02:00
} ,
} ;
2012-05-31 16:01:16 -04:00
}
2020-08-31 18:29:48 +02:00
static RPCHelpMan decoderawtransaction ( )
2012-05-31 16:01:16 -04:00
{
2020-08-31 18:29:48 +02:00
return RPCHelpMan { " decoderawtransaction " ,
2022-03-31 12:02:22 +02:00
" Return a JSON object representing the serialized, hex-encoded transaction. " ,
2018-10-20 08:19:44 -04:00
{
2018-12-10 16:56:51 -05:00
{ " hexstring " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " The transaction hex string " } ,
2021-04-14 15:01:00 +01:00
{ " iswitness " , RPCArg : : Type : : BOOL , RPCArg : : DefaultHint { " 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 {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : OBJ , " " , " " ,
2022-03-31 12:02:22 +02:00
DecodeTxDoc ( /*txid_field_doc=*/ " The transaction id " ) ,
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
} ,
2020-08-31 18:29:48 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
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 ) ;
2021-09-28 19:04:07 -05:00
TxToUniv ( CTransaction ( std : : move ( mtx ) ) , /*block_hash=*/ uint256 ( ) , /*entry=*/ result , /*include_hex=*/ false ) ;
2012-05-31 16:01:16 -04:00
return result ;
2020-08-31 18:29:48 +02:00
} ,
} ;
2012-05-31 16:01:16 -04:00
}
2020-08-31 18:29:48 +02:00
static RPCHelpMan decodescript ( )
2013-07-15 01:22:10 -04:00
{
2021-11-12 12:10:47 +01:00
return RPCHelpMan {
" decodescript " ,
" \n Decode a hex-encoded script. \n " ,
{
{ " hexstring " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : NO , " the hex-encoded script " } ,
} ,
RPCResult {
RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR , " asm " , " Script public key " } ,
2019-09-03 12:04:30 -04:00
{ RPCResult : : Type : : STR , " desc " , " Inferred descriptor for the script " } ,
2021-11-12 12:10:47 +01:00
{ RPCResult : : Type : : STR , " type " , " The output type (e.g. " + GetAllOutputTypes ( ) + " ) " } ,
2021-12-08 11:55:46 +01:00
{ RPCResult : : Type : : STR , " address " , /*optional=*/ true , " The Bitcoin address (only if a well-defined address exists) " } ,
2021-11-12 14:11:02 +01:00
{ RPCResult : : Type : : STR , " p2sh " , /*optional=*/ true ,
" address of P2SH script wrapping this redeem script (not returned for types that should not be wrapped) " } ,
{ RPCResult : : Type : : OBJ , " segwit " , /*optional=*/ true ,
" Result of a witness script public key wrapping this redeem script (not returned for types that should not be wrapped) " ,
2021-11-12 12:10:47 +01:00
{
{ RPCResult : : Type : : STR , " asm " , " String representation of the script public key " } ,
{ RPCResult : : Type : : STR_HEX , " hex " , " Hex string of the script public key " } ,
{ RPCResult : : Type : : STR , " type " , " The type of the script public key (e.g. witness_v0_keyhash or witness_v0_scripthash) " } ,
2021-12-08 11:55:46 +01:00
{ RPCResult : : Type : : STR , " address " , /*optional=*/ true , " The Bitcoin address (only if a well-defined address exists) " } ,
2019-09-03 12:04:30 -04:00
{ RPCResult : : Type : : STR , " desc " , " Inferred descriptor for the script " } ,
2021-11-12 12:10:47 +01:00
{ RPCResult : : Type : : STR , " p2sh-segwit " , " address of the P2SH script wrapping this witness redeem script " } ,
} } ,
} ,
} ,
RPCExamples {
HelpExampleCli ( " decodescript " , " \" hexstring \" " )
+ HelpExampleRpc ( " decodescript " , " \" hexstring \" " )
} ,
2020-08-31 18:29:48 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
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
}
2021-09-28 18:11:49 -05:00
ScriptToUniv ( script , /*out=*/ r , /*include_hex=*/ false , /*include_address=*/ true ) ;
2013-07-15 01:22:10 -04:00
2021-11-14 12:02:40 +01:00
std : : vector < std : : vector < unsigned char > > solutions_data ;
const TxoutType which_type { Solver ( script , solutions_data ) } ;
2016-09-26 17:01:10 -04:00
2021-11-12 14:11:02 +01:00
const bool can_wrap { [ & ] {
switch ( which_type ) {
case TxoutType : : MULTISIG :
case TxoutType : : NONSTANDARD :
case TxoutType : : PUBKEY :
case TxoutType : : PUBKEYHASH :
case TxoutType : : WITNESS_V0_KEYHASH :
case TxoutType : : WITNESS_V0_SCRIPTHASH :
// Can be wrapped if the checks below pass
break ;
case TxoutType : : NULL_DATA :
case TxoutType : : SCRIPTHASH :
case TxoutType : : WITNESS_UNKNOWN :
case TxoutType : : WITNESS_V1_TAPROOT :
// Should not be wrapped
return false ;
} // no default case, so the compiler can warn about missing cases
if ( ! script . HasValidOps ( ) | | script . IsUnspendable ( ) ) {
return false ;
}
for ( CScript : : const_iterator it { script . begin ( ) } ; it ! = script . end ( ) ; ) {
opcodetype op ;
CHECK_NONFATAL ( script . GetOp ( it , op ) ) ;
if ( op = = OP_CHECKSIGADD | | IsOpSuccess ( op ) ) {
return false ;
}
}
return true ;
} ( ) } ;
if ( can_wrap ) {
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.
2021-11-12 14:11:02 +01:00
const bool can_wrap_P2WSH { [ & ] {
switch ( which_type ) {
case TxoutType : : MULTISIG :
case TxoutType : : PUBKEY :
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.
for ( const auto & solution : solutions_data ) {
if ( ( solution . size ( ) ! = 1 ) & & ! CPubKey ( solution ) . IsCompressed ( ) ) {
2021-11-12 14:11:02 +01:00
return false ;
2018-02-01 02:40:47 +02:00
}
}
2021-11-12 14:11:02 +01:00
return true ;
case TxoutType : : NONSTANDARD :
case TxoutType : : PUBKEYHASH :
// Can be P2WSH wrapped
return true ;
case TxoutType : : NULL_DATA :
case TxoutType : : SCRIPTHASH :
case TxoutType : : WITNESS_UNKNOWN :
case TxoutType : : WITNESS_V0_KEYHASH :
case TxoutType : : WITNESS_V0_SCRIPTHASH :
case TxoutType : : WITNESS_V1_TAPROOT :
// Should not be wrapped
return false ;
} // no default case, so the compiler can warn about missing cases
2022-04-09 02:14:02 +02:00
NONFATAL_UNREACHABLE ( ) ;
2021-11-12 14:11:02 +01:00
} ( ) } ;
if ( can_wrap_P2WSH ) {
2018-02-01 02:40:47 +02:00
UniValue sr ( UniValue : : VOBJ ) ;
CScript segwitScr ;
2023-02-16 11:37:31 -05:00
FlatSigningProvider provider ;
2020-05-30 09:16:05 -04:00
if ( which_type = = TxoutType : : PUBKEY ) {
2020-06-26 13:36:41 -07:00
segwitScr = GetScriptForDestination ( WitnessV0KeyHash ( Hash160 ( solutions_data [ 0 ] ) ) ) ;
2020-05-30 09:16:05 -04:00
} else if ( which_type = = TxoutType : : PUBKEYHASH ) {
2020-01-14 22:37:16 -08:00
segwitScr = GetScriptForDestination ( WitnessV0KeyHash ( uint160 { solutions_data [ 0 ] } ) ) ;
2018-02-01 02:40:47 +02:00
} else {
// Scripts that are not fit for P2WPKH are encoded as P2WSH.
2023-02-16 11:37:31 -05:00
provider . scripts [ CScriptID ( script ) ] = script ;
2018-06-17 19:44:50 -07:00
segwitScr = GetScriptForDestination ( WitnessV0ScriptHash ( script ) ) ;
2018-02-01 02:40:47 +02:00
}
2023-02-03 17:44:22 +01:00
ScriptToUniv ( segwitScr , /*out=*/ sr , /*include_hex=*/ true , /*include_address=*/ true , /*provider=*/ & provider ) ;
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 ;
2020-08-31 18:29:48 +02:00
} ,
} ;
2013-07-15 01:22:10 -04:00
}
2020-08-31 18:29:48 +02:00
static RPCHelpMan combinerawtransaction ( )
2017-06-09 22:38:06 -07:00
{
2020-08-31 18:29:48 +02:00
return 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
{
2020-03-05 10:36:27 +00:00
{ " txs " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " The hex strings of partially signed transactions " ,
2018-10-23 15:22:28 -04:00
{
2020-09-04 17:21:18 -04:00
{ " hexstring " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : OMITTED , " A hex-encoded raw transaction " } ,
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 {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : STR , " " , " The hex-encoded raw transaction with signature(s) "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
2019-10-14 13:09:42 -04:00
HelpExampleCli ( " combinerawtransaction " , R " ('[ " myhex1 " , " myhex2 " , " myhex3 " ]') " )
2018-12-21 12:29:36 -05:00
} ,
2020-08-31 18:29:48 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
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 + + ) {
2020-08-30 10:28:42 +02:00
if ( ! DecodeHexTx ( txVariants [ idx ] , txs [ idx ] . get_str ( ) ) ) {
2020-10-13 15:21:03 +02:00
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , strprintf ( " TX decode failed for tx %d. Make sure the tx has at least one input. " , idx ) ) ;
2017-06-09 22:38:06 -07:00
}
}
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 ) ;
{
2021-04-12 18:41:05 -04:00
NodeContext & node = EnsureAnyNodeContext ( request . context ) ;
const CTxMemPool & mempool = EnsureMemPool ( node ) ;
ChainstateManager & chainman = EnsureChainman ( node ) ;
LOCK2 ( cs_main , mempool . cs ) ;
CCoinsViewCache & viewChain = chainman . ActiveChainstate ( ) . 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
}
}
2020-07-01 19:31:53 +02: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 ) ) ;
2020-08-31 18:29:48 +02:00
} ,
} ;
2017-06-09 22:38:06 -07:00
}
2020-08-31 18:29:48 +02:00
static RPCHelpMan signrawtransactionwithkey ( )
2017-06-12 12:23:02 -07:00
{
2020-08-31 18:29:48 +02:00
return 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 " } ,
2020-03-05 10:36:27 +00:00
{ " privkeys " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " The 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
} ,
2023-01-19 10:33:27 +00:00
{ " prevtxs " , RPCArg : : Type : : ARR , RPCArg : : Optional : : OMITTED , " The 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
} ,
2021-11-19 13:13:27 -05:00
{ " sighashtype " , RPCArg : : Type : : STR , RPCArg : : Default { " DEFAULT for Taproot, ALL otherwise " } , " The signature hash type. Must be one of: \n "
2021-03-04 14:27:20 -08:00
" \" DEFAULT \" \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 {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR_HEX , " hex " , " The hex-encoded raw transaction with signature(s) " } ,
{ RPCResult : : Type : : BOOL , " complete " , " If the transaction has a complete set of signatures " } ,
2021-12-08 11:55:46 +01:00
{ RPCResult : : Type : : ARR , " errors " , /*optional=*/ true , " Script verification errors (if there are any) " ,
2020-01-10 00:00:57 +07:00
{
{ RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR_HEX , " txid " , " The hash of the referenced, previous transaction " } ,
{ RPCResult : : Type : : NUM , " vout " , " The index of the output to spent and used as input " } ,
2021-08-25 19:55:15 +02:00
{ RPCResult : : Type : : ARR , " witness " , " " ,
{
{ RPCResult : : Type : : STR_HEX , " witness " , " " } ,
} } ,
2020-01-10 00:00:57 +07:00
{ RPCResult : : Type : : STR_HEX , " scriptSig " , " The hex-encoded signature script " } ,
{ RPCResult : : Type : : NUM , " sequence " , " Script sequence number " } ,
{ RPCResult : : Type : : STR , " error " , " Verification or signing error related to the input " } ,
} } ,
} } ,
}
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
} ,
2020-08-31 18:29:48 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2017-06-12 12:23:02 -07:00
CMutableTransaction mtx ;
2020-08-30 10:28:42 +02:00
if ( ! DecodeHexTx ( mtx , request . params [ 0 ] . get_str ( ) ) ) {
2020-10-13 15:21:03 +02:00
throw JSONRPCError ( RPC_DESERIALIZATION_ERROR , " TX decode failed. Make sure the tx has at least one input. " ) ;
2017-06-12 12:23:02 -07:00
}
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.
}
2021-04-13 17:04:43 -04:00
NodeContext & node = EnsureAnyNodeContext ( request . context ) ;
2020-04-17 11:28:45 -04:00
FindCoins ( node , coins ) ;
2019-04-10 13:38:41 +00:00
2019-07-05 17:39:31 -04:00
// Parse the prevtxs array
ParsePrevouts ( request . params [ 2 ] , & keystore , coins ) ;
2019-11-18 14:56:52 -05:00
UniValue result ( UniValue : : VOBJ ) ;
SignTransaction ( mtx , & keystore , coins , request . params [ 3 ] , result ) ;
return result ;
2020-08-31 18:29:48 +02:00
} ,
} ;
2017-06-12 12:23:02 -07:00
}
2022-07-01 01:20:42 +02:00
const RPCResult decodepsbt_inputs {
RPCResult : : Type : : ARR , " inputs " , " " ,
{
{ RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : OBJ , " non_witness_utxo " , /*optional=*/ true , " Decoded network transaction for non-witness UTXOs " ,
{
{ RPCResult : : Type : : ELISION , " " , " " } ,
} } ,
{ RPCResult : : Type : : OBJ , " witness_utxo " , /*optional=*/ true , " Transaction output for witness UTXOs " ,
{
{ RPCResult : : Type : : NUM , " amount " , " The value in " + CURRENCY_UNIT } ,
{ RPCResult : : Type : : OBJ , " scriptPubKey " , " " ,
{
2022-07-25 03:36:02 +00:00
{ RPCResult : : Type : : STR , " asm " , " Disassembly of the public key script " } ,
2022-07-01 01:20:42 +02:00
{ RPCResult : : Type : : STR , " desc " , " Inferred descriptor for the output " } ,
2022-07-25 03:36:02 +00:00
{ RPCResult : : Type : : STR_HEX , " hex " , " The raw public key script bytes, hex-encoded " } ,
2022-07-01 01:20:42 +02:00
{ RPCResult : : Type : : STR , " type " , " The type, eg 'pubkeyhash' " } ,
{ RPCResult : : Type : : STR , " address " , /*optional=*/ true , " The Bitcoin address (only if a well-defined address exists) " } ,
} } ,
} } ,
{ RPCResult : : Type : : OBJ_DYN , " partial_signatures " , /*optional=*/ true , " " ,
{
{ RPCResult : : Type : : STR , " pubkey " , " The public key and signature that corresponds to it. " } ,
} } ,
{ RPCResult : : Type : : STR , " sighash " , /*optional=*/ true , " The sighash type to be used " } ,
{ RPCResult : : Type : : OBJ , " redeem_script " , /*optional=*/ true , " " ,
{
2022-07-25 03:36:02 +00:00
{ RPCResult : : Type : : STR , " asm " , " Disassembly of the redeem script " } ,
{ RPCResult : : Type : : STR_HEX , " hex " , " The raw redeem script bytes, hex-encoded " } ,
2022-07-01 01:20:42 +02:00
{ RPCResult : : Type : : STR , " type " , " The type, eg 'pubkeyhash' " } ,
} } ,
{ RPCResult : : Type : : OBJ , " witness_script " , /*optional=*/ true , " " ,
{
2022-07-25 03:36:02 +00:00
{ RPCResult : : Type : : STR , " asm " , " Disassembly of the witness script " } ,
{ RPCResult : : Type : : STR_HEX , " hex " , " The raw witness script bytes, hex-encoded " } ,
2022-07-01 01:20:42 +02:00
{ RPCResult : : Type : : STR , " type " , " The type, eg 'pubkeyhash' " } ,
} } ,
{ RPCResult : : Type : : ARR , " bip32_derivs " , /*optional=*/ true , " " ,
{
{ RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR , " pubkey " , " The public key with the derivation path as the value. " } ,
{ RPCResult : : Type : : STR , " master_fingerprint " , " The fingerprint of the master key " } ,
{ RPCResult : : Type : : STR , " path " , " The path " } ,
} } ,
} } ,
{ RPCResult : : Type : : OBJ , " final_scriptSig " , /*optional=*/ true , " " ,
{
2022-07-25 03:36:02 +00:00
{ RPCResult : : Type : : STR , " asm " , " Disassembly of the final signature script " } ,
{ RPCResult : : Type : : STR_HEX , " hex " , " The raw final signature script bytes, hex-encoded " } ,
2022-07-01 01:20:42 +02:00
} } ,
{ RPCResult : : Type : : ARR , " final_scriptwitness " , /*optional=*/ true , " " ,
{
{ RPCResult : : Type : : STR_HEX , " " , " hex-encoded witness data (if any) " } ,
} } ,
{ RPCResult : : Type : : OBJ_DYN , " ripemd160_preimages " , /*optional=*/ true , " " ,
{
{ RPCResult : : Type : : STR , " hash " , " The hash and preimage that corresponds to it. " } ,
} } ,
{ RPCResult : : Type : : OBJ_DYN , " sha256_preimages " , /*optional=*/ true , " " ,
{
{ RPCResult : : Type : : STR , " hash " , " The hash and preimage that corresponds to it. " } ,
} } ,
{ RPCResult : : Type : : OBJ_DYN , " hash160_preimages " , /*optional=*/ true , " " ,
{
{ RPCResult : : Type : : STR , " hash " , " The hash and preimage that corresponds to it. " } ,
} } ,
{ RPCResult : : Type : : OBJ_DYN , " hash256_preimages " , /*optional=*/ true , " " ,
{
{ RPCResult : : Type : : STR , " hash " , " The hash and preimage that corresponds to it. " } ,
} } ,
{ RPCResult : : Type : : STR_HEX , " taproot_key_path_sig " , /*optional=*/ true , " hex-encoded signature for the Taproot key path spend " } ,
{ RPCResult : : Type : : ARR , " taproot_script_path_sigs " , /*optional=*/ true , " " ,
{
{ RPCResult : : Type : : OBJ , " signature " , /*optional=*/ true , " The signature for the pubkey and leaf hash combination " ,
{
{ RPCResult : : Type : : STR , " pubkey " , " The x-only pubkey for this signature " } ,
{ RPCResult : : Type : : STR , " leaf_hash " , " The leaf hash for this signature " } ,
{ RPCResult : : Type : : STR , " sig " , " The signature itself " } ,
} } ,
} } ,
{ RPCResult : : Type : : ARR , " taproot_scripts " , /*optional=*/ true , " " ,
{
{ RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR_HEX , " script " , " A leaf script " } ,
{ RPCResult : : Type : : NUM , " leaf_ver " , " The version number for the leaf script " } ,
{ RPCResult : : Type : : ARR , " control_blocks " , " The control blocks for this script " ,
{
{ RPCResult : : Type : : STR_HEX , " control_block " , " A hex-encoded control block for this script " } ,
} } ,
} } ,
} } ,
{ RPCResult : : Type : : ARR , " taproot_bip32_derivs " , /*optional=*/ true , " " ,
{
{ RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR , " pubkey " , " The x-only public key this path corresponds to " } ,
{ RPCResult : : Type : : STR , " master_fingerprint " , " The fingerprint of the master key " } ,
{ RPCResult : : Type : : STR , " path " , " The path " } ,
{ RPCResult : : Type : : ARR , " leaf_hashes " , " The hashes of the leaves this pubkey appears in " ,
{
{ RPCResult : : Type : : STR_HEX , " hash " , " The hash of a leaf this pubkey appears in " } ,
} } ,
} } ,
} } ,
{ RPCResult : : Type : : STR_HEX , " taproot_internal_key " , /*optional=*/ true , " The hex-encoded Taproot x-only internal key " } ,
{ RPCResult : : Type : : STR_HEX , " taproot_merkle_root " , /*optional=*/ true , " The hex-encoded Taproot merkle root " } ,
{ RPCResult : : Type : : OBJ_DYN , " unknown " , /*optional=*/ true , " The unknown input fields " ,
{
{ RPCResult : : Type : : STR_HEX , " key " , " (key-value pair) An unknown key-value pair " } ,
} } ,
{ RPCResult : : Type : : ARR , " proprietary " , /*optional=*/ true , " The input proprietary map " ,
{
{ RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR_HEX , " identifier " , " The hex string for the proprietary identifier " } ,
{ RPCResult : : Type : : NUM , " subtype " , " The number for the subtype " } ,
{ RPCResult : : Type : : STR_HEX , " key " , " The hex for the key " } ,
{ RPCResult : : Type : : STR_HEX , " value " , " The hex for the value " } ,
} } ,
} } ,
} } ,
}
} ;
2022-07-01 01:21:04 +02:00
const RPCResult decodepsbt_outputs {
RPCResult : : Type : : ARR , " outputs " , " " ,
{
{ RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : OBJ , " redeem_script " , /*optional=*/ true , " " ,
{
2022-07-25 03:36:02 +00:00
{ RPCResult : : Type : : STR , " asm " , " Disassembly of the redeem script " } ,
{ RPCResult : : Type : : STR_HEX , " hex " , " The raw redeem script bytes, hex-encoded " } ,
2022-07-01 01:21:04 +02:00
{ RPCResult : : Type : : STR , " type " , " The type, eg 'pubkeyhash' " } ,
} } ,
{ RPCResult : : Type : : OBJ , " witness_script " , /*optional=*/ true , " " ,
{
2022-07-25 03:36:02 +00:00
{ RPCResult : : Type : : STR , " asm " , " Disassembly of the witness script " } ,
{ RPCResult : : Type : : STR_HEX , " hex " , " The raw witness script bytes, hex-encoded " } ,
2022-07-01 01:21:04 +02:00
{ RPCResult : : Type : : STR , " type " , " The type, eg 'pubkeyhash' " } ,
} } ,
{ RPCResult : : Type : : ARR , " bip32_derivs " , /*optional=*/ true , " " ,
{
{ RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR , " pubkey " , " The public key this path corresponds to " } ,
{ RPCResult : : Type : : STR , " master_fingerprint " , " The fingerprint of the master key " } ,
{ RPCResult : : Type : : STR , " path " , " The path " } ,
} } ,
} } ,
{ RPCResult : : Type : : STR_HEX , " taproot_internal_key " , /*optional=*/ true , " The hex-encoded Taproot x-only internal key " } ,
{ RPCResult : : Type : : ARR , " taproot_tree " , /*optional=*/ true , " The tuples that make up the Taproot tree, in depth first search order " ,
{
{ RPCResult : : Type : : OBJ , " tuple " , /*optional=*/ true , " A single leaf script in the taproot tree " ,
{
{ RPCResult : : Type : : NUM , " depth " , " The depth of this element in the tree " } ,
{ RPCResult : : Type : : NUM , " leaf_ver " , " The version of this leaf " } ,
{ RPCResult : : Type : : STR , " script " , " The hex-encoded script itself " } ,
} } ,
} } ,
{ RPCResult : : Type : : ARR , " taproot_bip32_derivs " , /*optional=*/ true , " " ,
{
{ RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR , " pubkey " , " The x-only public key this path corresponds to " } ,
{ RPCResult : : Type : : STR , " master_fingerprint " , " The fingerprint of the master key " } ,
{ RPCResult : : Type : : STR , " path " , " The path " } ,
{ RPCResult : : Type : : ARR , " leaf_hashes " , " The hashes of the leaves this pubkey appears in " ,
{
{ RPCResult : : Type : : STR_HEX , " hash " , " The hash of a leaf this pubkey appears in " } ,
} } ,
} } ,
} } ,
{ RPCResult : : Type : : OBJ_DYN , " unknown " , /*optional=*/ true , " The unknown output fields " ,
{
{ RPCResult : : Type : : STR_HEX , " key " , " (key-value pair) An unknown key-value pair " } ,
} } ,
{ RPCResult : : Type : : ARR , " proprietary " , /*optional=*/ true , " The output proprietary map " ,
{
{ RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR_HEX , " identifier " , " The hex string for the proprietary identifier " } ,
{ RPCResult : : Type : : NUM , " subtype " , " The number for the subtype " } ,
{ RPCResult : : Type : : STR_HEX , " key " , " The hex for the key " } ,
{ RPCResult : : Type : : STR_HEX , " value " , " The hex for the value " } ,
} } ,
} } ,
} } ,
}
} ;
2020-08-31 18:29:48 +02:00
static RPCHelpMan decodepsbt ( )
2018-06-28 19:04:40 -07:00
{
2022-01-04 16:59:20 +01:00
return RPCHelpMan {
" decodepsbt " ,
" Return a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction. " ,
2018-10-20 08:19:44 -04:00
{
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 {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : OBJ , " tx " , " The decoded network-serialized unsigned transaction. " ,
{
{ RPCResult : : Type : : ELISION , " " , " The layout is the same as the output of decoderawtransaction. " } ,
} } ,
2019-07-25 13:20:38 -04:00
{ RPCResult : : Type : : ARR , " global_xpubs " , " " ,
{
{ RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR , " xpub " , " The extended public key this path corresponds to " } ,
{ RPCResult : : Type : : STR_HEX , " master_fingerprint " , " The fingerprint of the master key " } ,
{ RPCResult : : Type : : STR , " path " , " The path " } ,
} } ,
} } ,
2021-01-25 16:49:44 -05:00
{ RPCResult : : Type : : NUM , " psbt_version " , " The PSBT version number. Not to be confused with the unsigned transaction version " } ,
2019-10-02 16:58:20 -04:00
{ RPCResult : : Type : : ARR , " proprietary " , " The global proprietary map " ,
{
{ RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR_HEX , " identifier " , " The hex string for the proprietary identifier " } ,
{ RPCResult : : Type : : NUM , " subtype " , " The number for the subtype " } ,
{ RPCResult : : Type : : STR_HEX , " key " , " The hex for the key " } ,
{ RPCResult : : Type : : STR_HEX , " value " , " The hex for the value " } ,
} } ,
} } ,
2020-01-10 00:00:57 +07:00
{ RPCResult : : Type : : OBJ_DYN , " unknown " , " The unknown global fields " ,
{
{ RPCResult : : Type : : STR_HEX , " key " , " (key-value pair) An unknown key-value pair " } ,
} } ,
2022-07-01 01:20:42 +02:00
decodepsbt_inputs ,
2022-07-01 01:21:04 +02:00
decodepsbt_outputs ,
2021-12-08 11:55:46 +01:00
{ RPCResult : : Type : : STR_AMOUNT , " fee " , /*optional=*/ true , " The transaction fee paid if all UTXOs slots in the PSBT have been filled. " } ,
2020-01-10 00:00:57 +07:00
}
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
HelpExampleCli ( " decodepsbt " , " \" psbt \" " )
} ,
2020-08-31 18:29:48 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2018-06-28 19:04:40 -07:00
// 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 ) ;
2021-09-28 19:04:07 -05:00
TxToUniv ( CTransaction ( * psbtx . tx ) , /*block_hash=*/ uint256 ( ) , /*entry=*/ tx_univ , /*include_hex=*/ false ) ;
2018-06-28 19:04:40 -07:00
result . pushKV ( " tx " , tx_univ ) ;
2019-07-25 13:20:38 -04:00
// Add the global xpubs
UniValue global_xpubs ( UniValue : : VARR ) ;
for ( std : : pair < KeyOriginInfo , std : : set < CExtPubKey > > xpub_pair : psbtx . m_xpubs ) {
for ( auto & xpub : xpub_pair . second ) {
std : : vector < unsigned char > ser_xpub ;
ser_xpub . assign ( BIP32_EXTKEY_WITH_VERSION_SIZE , 0 ) ;
xpub . EncodeWithVersion ( ser_xpub . data ( ) ) ;
UniValue keypath ( UniValue : : VOBJ ) ;
keypath . pushKV ( " xpub " , EncodeBase58Check ( ser_xpub ) ) ;
keypath . pushKV ( " master_fingerprint " , HexStr ( Span < unsigned char > ( xpub_pair . first . fingerprint , xpub_pair . first . fingerprint + 4 ) ) ) ;
keypath . pushKV ( " path " , WriteHDKeypath ( xpub_pair . first . path ) ) ;
global_xpubs . push_back ( keypath ) ;
}
}
result . pushKV ( " global_xpubs " , global_xpubs ) ;
2021-01-25 16:49:44 -05:00
// PSBT version
result . pushKV ( " psbt_version " , static_cast < uint64_t > ( psbtx . GetVersion ( ) ) ) ;
2019-10-02 16:58:20 -04:00
// Proprietary
UniValue proprietary ( UniValue : : VARR ) ;
for ( const auto & entry : psbtx . m_proprietary ) {
UniValue this_prop ( UniValue : : VOBJ ) ;
this_prop . pushKV ( " identifier " , HexStr ( entry . identifier ) ) ;
this_prop . pushKV ( " subtype " , entry . subtype ) ;
this_prop . pushKV ( " key " , HexStr ( entry . key ) ) ;
this_prop . pushKV ( " value " , HexStr ( entry . value ) ) ;
proprietary . push_back ( this_prop ) ;
}
result . pushKV ( " proprietary " , proprietary ) ;
2018-06-28 19:04:40 -07:00
// 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
2020-06-04 23:43:25 -04:00
bool have_a_utxo = false ;
2020-07-14 12:16:18 -04:00
CTxOut txout ;
2018-06-28 19:04:40 -07:00
if ( ! input . witness_utxo . IsNull ( ) ) {
2020-07-14 12:16:18 -04:00
txout = input . witness_utxo ;
2018-06-28 19:04:40 -07:00
UniValue o ( UniValue : : VOBJ ) ;
2021-09-28 18:11:49 -05:00
ScriptToUniv ( txout . scriptPubKey , /*out=*/ o , /*include_hex=*/ true , /*include_address=*/ true ) ;
2020-07-14 12:16:18 -04:00
UniValue out ( UniValue : : VOBJ ) ;
out . pushKV ( " amount " , ValueFromAmount ( txout . nValue ) ) ;
2018-06-28 19:04:40 -07:00
out . pushKV ( " scriptPubKey " , o ) ;
2020-07-14 12:16:18 -04:00
2018-06-28 19:04:40 -07:00
in . pushKV ( " witness_utxo " , out ) ;
2020-07-14 12:16:18 -04:00
2020-06-04 23:43:25 -04:00
have_a_utxo = true ;
}
if ( input . non_witness_utxo ) {
2020-07-14 12:16:18 -04:00
txout = input . non_witness_utxo - > vout [ psbtx . tx - > vin [ i ] . prevout . n ] ;
2018-06-28 19:04:40 -07:00
UniValue non_wit ( UniValue : : VOBJ ) ;
2021-09-28 19:04:07 -05:00
TxToUniv ( * input . non_witness_utxo , /*block_hash=*/ uint256 ( ) , /*entry=*/ non_wit , /*include_hex=*/ false ) ;
2018-06-28 19:04:40 -07:00
in . pushKV ( " non_witness_utxo " , non_wit ) ;
2020-07-14 12:16:18 -04:00
have_a_utxo = true ;
}
if ( have_a_utxo ) {
if ( MoneyRange ( txout . nValue ) & & MoneyRange ( total_in + txout . nValue ) ) {
total_in + = txout . nValue ;
2019-10-15 17:15:22 -04:00
} else {
// Hack to just not show fee later
have_all_utxos = false ;
}
2020-07-14 12:16:18 -04:00
} else {
2018-06-28 19:04:40 -07:00
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
2021-11-15 13:54:01 -05:00
if ( input . sighash_type ! = std : : nullopt ) {
in . pushKV ( " sighash " , SighashToStr ( ( unsigned char ) * input . sighash_type ) ) ;
2018-06-28 19:04:40 -07:00
}
// Redeem script and witness script
if ( ! input . redeem_script . empty ( ) ) {
UniValue r ( UniValue : : VOBJ ) ;
2021-09-28 19:04:07 -05:00
ScriptToUniv ( input . redeem_script , /*out=*/ r ) ;
2018-06-28 19:04:40 -07:00
in . pushKV ( " redeem_script " , r ) ;
}
if ( ! input . witness_script . empty ( ) ) {
UniValue r ( UniValue : : VOBJ ) ;
2021-09-28 19:04:07 -05:00
ScriptToUniv ( input . witness_script , /*out=*/ r ) ;
2018-06-28 19:04:40 -07:00
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 ) {
2020-06-24 15:48:26 +02:00
txinwitness . push_back ( HexStr ( item ) ) ;
2018-06-28 19:04:40 -07:00
}
in . pushKV ( " final_scriptwitness " , txinwitness ) ;
}
2021-12-05 14:18:26 +01:00
// Ripemd160 hash preimages
if ( ! input . ripemd160_preimages . empty ( ) ) {
UniValue ripemd160_preimages ( UniValue : : VOBJ ) ;
for ( const auto & [ hash , preimage ] : input . ripemd160_preimages ) {
ripemd160_preimages . pushKV ( HexStr ( hash ) , HexStr ( preimage ) ) ;
}
in . pushKV ( " ripemd160_preimages " , ripemd160_preimages ) ;
}
// Sha256 hash preimages
if ( ! input . sha256_preimages . empty ( ) ) {
UniValue sha256_preimages ( UniValue : : VOBJ ) ;
for ( const auto & [ hash , preimage ] : input . sha256_preimages ) {
sha256_preimages . pushKV ( HexStr ( hash ) , HexStr ( preimage ) ) ;
}
in . pushKV ( " sha256_preimages " , sha256_preimages ) ;
}
// Hash160 hash preimages
if ( ! input . hash160_preimages . empty ( ) ) {
UniValue hash160_preimages ( UniValue : : VOBJ ) ;
for ( const auto & [ hash , preimage ] : input . hash160_preimages ) {
hash160_preimages . pushKV ( HexStr ( hash ) , HexStr ( preimage ) ) ;
}
in . pushKV ( " hash160_preimages " , hash160_preimages ) ;
}
// Hash256 hash preimages
if ( ! input . hash256_preimages . empty ( ) ) {
UniValue hash256_preimages ( UniValue : : VOBJ ) ;
for ( const auto & [ hash , preimage ] : input . hash256_preimages ) {
hash256_preimages . pushKV ( HexStr ( hash ) , HexStr ( preimage ) ) ;
}
in . pushKV ( " hash256_preimages " , hash256_preimages ) ;
}
2021-07-19 16:54:16 -04:00
// Taproot key path signature
if ( ! input . m_tap_key_sig . empty ( ) ) {
in . pushKV ( " taproot_key_path_sig " , HexStr ( input . m_tap_key_sig ) ) ;
}
// Taproot script path signatures
if ( ! input . m_tap_script_sigs . empty ( ) ) {
UniValue script_sigs ( UniValue : : VARR ) ;
for ( const auto & [ pubkey_leaf , sig ] : input . m_tap_script_sigs ) {
const auto & [ xonly , leaf_hash ] = pubkey_leaf ;
UniValue sigobj ( UniValue : : VOBJ ) ;
sigobj . pushKV ( " pubkey " , HexStr ( xonly ) ) ;
sigobj . pushKV ( " leaf_hash " , HexStr ( leaf_hash ) ) ;
sigobj . pushKV ( " sig " , HexStr ( sig ) ) ;
script_sigs . push_back ( sigobj ) ;
}
in . pushKV ( " taproot_script_path_sigs " , script_sigs ) ;
}
// Taproot leaf scripts
if ( ! input . m_tap_scripts . empty ( ) ) {
UniValue tap_scripts ( UniValue : : VARR ) ;
for ( const auto & [ leaf , control_blocks ] : input . m_tap_scripts ) {
const auto & [ script , leaf_ver ] = leaf ;
UniValue script_info ( UniValue : : VOBJ ) ;
script_info . pushKV ( " script " , HexStr ( script ) ) ;
script_info . pushKV ( " leaf_ver " , leaf_ver ) ;
UniValue control_blocks_univ ( UniValue : : VARR ) ;
for ( const auto & control_block : control_blocks ) {
control_blocks_univ . push_back ( HexStr ( control_block ) ) ;
}
script_info . pushKV ( " control_blocks " , control_blocks_univ ) ;
tap_scripts . push_back ( script_info ) ;
}
in . pushKV ( " taproot_scripts " , tap_scripts ) ;
}
// Taproot bip32 keypaths
if ( ! input . m_tap_bip32_paths . empty ( ) ) {
UniValue keypaths ( UniValue : : VARR ) ;
for ( const auto & [ xonly , leaf_origin ] : input . m_tap_bip32_paths ) {
const auto & [ leaf_hashes , origin ] = leaf_origin ;
UniValue path_obj ( UniValue : : VOBJ ) ;
path_obj . pushKV ( " pubkey " , HexStr ( xonly ) ) ;
path_obj . pushKV ( " master_fingerprint " , strprintf ( " %08x " , ReadBE32 ( origin . fingerprint ) ) ) ;
path_obj . pushKV ( " path " , WriteHDKeypath ( origin . path ) ) ;
UniValue leaf_hashes_arr ( UniValue : : VARR ) ;
for ( const auto & leaf_hash : leaf_hashes ) {
leaf_hashes_arr . push_back ( HexStr ( leaf_hash ) ) ;
}
path_obj . pushKV ( " leaf_hashes " , leaf_hashes_arr ) ;
keypaths . push_back ( path_obj ) ;
}
in . pushKV ( " taproot_bip32_derivs " , keypaths ) ;
}
// Taproot internal key
if ( ! input . m_tap_internal_key . IsNull ( ) ) {
in . pushKV ( " taproot_internal_key " , HexStr ( input . m_tap_internal_key ) ) ;
}
// Write taproot merkle root
if ( ! input . m_tap_merkle_root . IsNull ( ) ) {
in . pushKV ( " taproot_merkle_root " , HexStr ( input . m_tap_merkle_root ) ) ;
}
2019-10-02 16:58:20 -04:00
// Proprietary
if ( ! input . m_proprietary . empty ( ) ) {
UniValue proprietary ( UniValue : : VARR ) ;
for ( const auto & entry : input . m_proprietary ) {
UniValue this_prop ( UniValue : : VOBJ ) ;
this_prop . pushKV ( " identifier " , HexStr ( entry . identifier ) ) ;
this_prop . pushKV ( " subtype " , entry . subtype ) ;
this_prop . pushKV ( " key " , HexStr ( entry . key ) ) ;
this_prop . pushKV ( " value " , HexStr ( entry . value ) ) ;
proprietary . push_back ( this_prop ) ;
}
in . pushKV ( " proprietary " , proprietary ) ;
}
2018-06-28 19:04:40 -07:00
// 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 ) ;
2021-09-28 19:04:07 -05:00
ScriptToUniv ( output . redeem_script , /*out=*/ r ) ;
2018-06-28 19:04:40 -07:00
out . pushKV ( " redeem_script " , r ) ;
}
if ( ! output . witness_script . empty ( ) ) {
UniValue r ( UniValue : : VOBJ ) ;
2021-09-28 19:04:07 -05:00
ScriptToUniv ( output . witness_script , /*out=*/ r ) ;
2018-06-28 19:04:40 -07:00
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 ) ;
}
2021-07-19 16:54:16 -04:00
// Taproot internal key
if ( ! output . m_tap_internal_key . IsNull ( ) ) {
out . pushKV ( " taproot_internal_key " , HexStr ( output . m_tap_internal_key ) ) ;
}
// Taproot tree
2022-08-16 21:17:43 -04:00
if ( ! output . m_tap_tree . empty ( ) ) {
2021-07-19 16:54:16 -04:00
UniValue tree ( UniValue : : VARR ) ;
2022-08-16 21:17:43 -04:00
for ( const auto & [ depth , leaf_ver , script ] : output . m_tap_tree ) {
2021-07-19 16:54:16 -04:00
UniValue elem ( UniValue : : VOBJ ) ;
elem . pushKV ( " depth " , ( int ) depth ) ;
elem . pushKV ( " leaf_ver " , ( int ) leaf_ver ) ;
elem . pushKV ( " script " , HexStr ( script ) ) ;
tree . push_back ( elem ) ;
}
out . pushKV ( " taproot_tree " , tree ) ;
}
// Taproot bip32 keypaths
if ( ! output . m_tap_bip32_paths . empty ( ) ) {
UniValue keypaths ( UniValue : : VARR ) ;
for ( const auto & [ xonly , leaf_origin ] : output . m_tap_bip32_paths ) {
const auto & [ leaf_hashes , origin ] = leaf_origin ;
UniValue path_obj ( UniValue : : VOBJ ) ;
path_obj . pushKV ( " pubkey " , HexStr ( xonly ) ) ;
path_obj . pushKV ( " master_fingerprint " , strprintf ( " %08x " , ReadBE32 ( origin . fingerprint ) ) ) ;
path_obj . pushKV ( " path " , WriteHDKeypath ( origin . path ) ) ;
UniValue leaf_hashes_arr ( UniValue : : VARR ) ;
for ( const auto & leaf_hash : leaf_hashes ) {
leaf_hashes_arr . push_back ( HexStr ( leaf_hash ) ) ;
}
path_obj . pushKV ( " leaf_hashes " , leaf_hashes_arr ) ;
keypaths . push_back ( path_obj ) ;
}
out . pushKV ( " taproot_bip32_derivs " , keypaths ) ;
}
2019-10-02 16:58:20 -04:00
// Proprietary
if ( ! output . m_proprietary . empty ( ) ) {
UniValue proprietary ( UniValue : : VARR ) ;
for ( const auto & entry : output . m_proprietary ) {
UniValue this_prop ( UniValue : : VOBJ ) ;
this_prop . pushKV ( " identifier " , HexStr ( entry . identifier ) ) ;
this_prop . pushKV ( " subtype " , entry . subtype ) ;
this_prop . pushKV ( " key " , HexStr ( entry . key ) ) ;
this_prop . pushKV ( " value " , HexStr ( entry . value ) ) ;
proprietary . push_back ( this_prop ) ;
}
out . pushKV ( " proprietary " , proprietary ) ;
}
2018-06-28 19:04:40 -07:00
// 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
2019-10-15 17:15:22 -04:00
if ( MoneyRange ( psbtx . tx - > vout [ i ] . nValue ) & & MoneyRange ( output_value + psbtx . tx - > vout [ i ] . nValue ) ) {
output_value + = psbtx . tx - > vout [ i ] . nValue ;
} else {
// Hack to just not show fee later
have_all_utxos = false ;
}
2018-06-28 19:04:40 -07:00
}
result . pushKV ( " outputs " , outputs ) ;
if ( have_all_utxos ) {
result . pushKV ( " fee " , ValueFromAmount ( total_in - output_value ) ) ;
}
return result ;
2020-08-31 18:29:48 +02:00
} ,
} ;
2018-06-28 19:04:40 -07:00
}
2020-08-31 18:29:48 +02:00
static RPCHelpMan combinepsbt ( )
2018-06-28 19:04:40 -07:00
{
2020-08-31 18:29:48 +02:00
return 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
{
2020-03-05 10:36:27 +00:00
{ " txs " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " The 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 {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : STR , " " , " The base64-encoded partially signed transaction "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
2019-10-14 13:09:42 -04:00
HelpExampleCli ( " combinepsbt " , R " ('[ " mybase64_1 " , " mybase64_2 " , " mybase64_3 " ]') " )
2018-12-21 12:29:36 -05:00
} ,
2020-08-31 18:29:48 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2018-06-28 19:04:40 -07:00
// 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
}
2023-11-19 14:58:00 +01:00
DataStream ssTx { } ;
2018-06-28 19:04:40 -07:00
ssTx < < merged_psbt ;
2020-11-25 11:21:14 +01:00
return EncodeBase64 ( ssTx ) ;
2020-08-31 18:29:48 +02:00
} ,
} ;
2018-06-28 19:04:40 -07:00
}
2020-08-31 18:29:48 +02:00
static RPCHelpMan finalizepsbt ( )
2018-06-28 19:04:40 -07:00
{
2020-08-31 18:29:48 +02:00
return RPCHelpMan { " finalizepsbt " ,
2018-10-20 08:19:44 -04:00
" 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 " } ,
2021-04-14 15:01:00 +01:00
{ " extract " , RPCArg : : Type : : BOOL , RPCArg : : 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 {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : OBJ , " " , " " ,
{
2021-12-08 11:55:46 +01:00
{ RPCResult : : Type : : STR , " psbt " , /*optional=*/ true , " The base64-encoded partially signed transaction if not extracted " } ,
{ RPCResult : : Type : : STR_HEX , " hex " , /*optional=*/ true , " The hex-encoded network transaction if extracted " } ,
2020-01-10 00:00:57 +07:00
{ RPCResult : : Type : : BOOL , " complete " , " If the transaction has a complete set of signatures " } ,
}
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
HelpExampleCli ( " finalizepsbt " , " \" psbt \" " )
} ,
2020-08-31 18:29:48 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2018-06-28 19:04:40 -07:00
// 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 ) ;
2023-11-19 14:58:00 +01:00
DataStream ssTx { } ;
2019-01-09 03:08:32 -08:00
std : : string result_str ;
2018-06-28 19:04:40 -07:00
if ( complete & & extract ) {
2023-09-07 19:16:57 +10:00
ssTx < < TX_WITH_WITNESS ( mtx ) ;
2020-06-24 17:26:47 +02:00
result_str = HexStr ( ssTx ) ;
2019-01-09 03:08:32 -08:00
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 ;
2020-08-31 18:29:48 +02:00
} ,
} ;
2018-06-28 19:04:40 -07:00
}
2020-08-31 18:29:48 +02:00
static RPCHelpMan createpsbt ( )
2018-06-28 19:04:40 -07:00
{
2020-08-31 18:29:48 +02:00
return 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 " ,
2021-11-30 17:12:57 +08:00
CreateTxDoc ( ) ,
2018-12-21 12:29:36 -05:00
RPCResult {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : STR , " " , " The resulting raw transaction (base64-encoded string) "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
HelpExampleCli ( " createpsbt " , " \" [{ \\ \" txid \\ \" : \\ \" myid \\ \" , \\ \" vout \\ \" :0}] \" \" [{ \\ \" data \\ \" : \\ \" 00010203 \\ \" }] \" " )
} ,
2020-08-31 18:29:48 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2018-06-28 19:04:40 -07:00
2022-07-13 16:29:27 -04:00
std : : optional < bool > rbf ;
2019-04-27 19:44:38 +02:00
if ( ! request . params [ 3 ] . isNull ( ) ) {
2022-12-05 14:55:32 +01:00
rbf = request . params [ 3 ] . get_bool ( ) ;
2019-04-27 19:44:38 +02:00
}
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 ) {
2023-10-04 13:53:40 +02:00
psbtx . inputs . emplace_back ( ) ;
2018-06-28 19:04:40 -07:00
}
for ( unsigned int i = 0 ; i < rawTx . vout . size ( ) ; + + i ) {
2023-10-04 13:53:40 +02:00
psbtx . outputs . emplace_back ( ) ;
2018-06-28 19:04:40 -07:00
}
// Serialize the PSBT
2023-11-19 14:58:00 +01:00
DataStream ssTx { } ;
2018-06-28 19:04:40 -07:00
ssTx < < psbtx ;
2020-11-25 11:21:14 +01:00
return EncodeBase64 ( ssTx ) ;
2020-08-31 18:29:48 +02:00
} ,
} ;
2018-06-28 19:04:40 -07:00
}
2020-08-31 18:29:48 +02:00
static RPCHelpMan converttopsbt ( )
2018-06-28 19:04:40 -07:00
{
2020-08-31 18:29:48 +02:00
return 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 " } ,
2021-04-14 15:01:00 +01:00
{ " permitsigdata " , RPCArg : : Type : : BOOL , RPCArg : : 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. " } ,
2021-04-14 15:01:00 +01:00
{ " iswitness " , RPCArg : : Type : : BOOL , RPCArg : : DefaultHint { " 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 {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : STR , " " , " The resulting raw transaction (base64-encoded string) "
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
} ,
2020-08-31 18:29:48 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2018-06-28 19:04:40 -07:00
// 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 ) {
2023-10-04 13:53:40 +02:00
psbtx . inputs . emplace_back ( ) ;
2018-06-28 19:04:40 -07:00
}
for ( unsigned int i = 0 ; i < tx . vout . size ( ) ; + + i ) {
2023-10-04 13:53:40 +02:00
psbtx . outputs . emplace_back ( ) ;
2018-06-28 19:04:40 -07:00
}
// Serialize the PSBT
2023-11-19 14:58:00 +01:00
DataStream ssTx { } ;
2018-06-28 19:04:40 -07:00
ssTx < < psbtx ;
2020-11-25 11:21:14 +01:00
return EncodeBase64 ( ssTx ) ;
2020-08-31 18:29:48 +02:00
} ,
} ;
2018-06-28 19:04:40 -07:00
}
2020-08-31 18:29:48 +02:00
static RPCHelpMan utxoupdatepsbt ( )
2018-07-20 17:08:25 -07:00
{
2020-08-31 18:29:48 +02:00
return RPCHelpMan { " utxoupdatepsbt " ,
2022-08-23 15:24:00 -04:00
" \n Updates all segwit inputs and outputs in a PSBT with data from output descriptors, the UTXO set, txindex, 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 " } ,
2023-01-19 10:33:27 +00:00
{ " descriptors " , RPCArg : : Type : : ARR , RPCArg : : Optional : : OMITTED , " An array of either strings or objects " , {
2019-02-16 14:59:16 -08:00
{ " " , 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 " } ,
2021-04-14 15:01:00 +01:00
{ " range " , RPCArg : : Type : : RANGE , RPCArg : : Default { 1000 } , " Up to what index HD chains should be explored (either end or [begin,end]) " } ,
2019-02-16 14:59:16 -08:00
} } ,
} } ,
2018-07-20 17:08:25 -07:00
} ,
RPCResult {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : STR , " " , " The base64-encoded partially signed transaction with inputs updated "
2018-07-20 17:08:25 -07:00
} ,
RPCExamples {
HelpExampleCli ( " utxoupdatepsbt " , " \" psbt \" " )
2020-08-31 18:29:48 +02:00
} ,
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
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 ) ;
}
}
2018-07-20 17:08:25 -07:00
2022-07-27 14:24:19 +05:30
// We don't actually need private keys further on; hide them as a precaution.
const PartiallySignedTransaction & psbtx = ProcessPSBT (
request . params [ 0 ] . get_str ( ) ,
request . context ,
2022-08-03 19:32:59 -04:00
HidingSigningProvider ( & provider , /*hide_secret=*/ true , /*hide_origin=*/ false ) ,
/*sighash_type=*/ SIGHASH_ALL ,
/*finalize=*/ false ) ;
2018-07-20 17:08:25 -07:00
2023-11-19 14:58:00 +01:00
DataStream ssTx { } ;
2018-07-20 17:08:25 -07:00
ssTx < < psbtx ;
2020-11-25 11:21:14 +01:00
return EncodeBase64 ( ssTx ) ;
2020-08-31 18:29:48 +02:00
} ,
} ;
2018-07-20 17:08:25 -07:00
}
2020-08-31 18:29:48 +02:00
static RPCHelpMan joinpsbts ( )
2018-07-20 18:24:16 -07:00
{
2020-08-31 18:29:48 +02:00
return RPCHelpMan { " joinpsbts " ,
2018-07-20 18:24:16 -07:00
" \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 " ,
{
2020-03-05 10:36:27 +00:00
{ " txs " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " The base64 strings of partially signed transactions " ,
2018-07-20 18:24:16 -07:00
{
{ " psbt " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " A base64 string of a PSBT " }
} }
} ,
RPCResult {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : STR , " " , " The base64-encoded partially signed transaction "
2018-07-20 18:24:16 -07:00
} ,
RPCExamples {
HelpExampleCli ( " joinpsbts " , " \" psbt \" " )
2020-08-31 18:29:48 +02:00
} ,
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2018-07-20 18:24:16 -07:00
// 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. " ) ;
}
2019-09-03 10:53:45 -04:00
uint32_t best_version = 1 ;
2018-07-20 18:24:16 -07:00
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
2019-09-03 10:53:45 -04:00
if ( static_cast < uint32_t > ( psbtx . tx - > nVersion ) > best_version ) {
best_version = static_cast < uint32_t > ( psbtx . tx - > nVersion ) ;
2018-07-20 18:24:16 -07:00
}
// 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 ( ) ;
2019-09-03 10:53:45 -04:00
merged_psbt . tx - > nVersion = static_cast < int32_t > ( best_version ) ;
2018-07-20 18:24:16 -07:00
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 ] ) ) {
2019-10-28 13:30:20 +01:00
throw JSONRPCError ( RPC_INVALID_PARAMETER , strprintf ( " Input %s:%d exists in multiple PSBTs " , psbt . tx - > vin [ i ] . prevout . hash . ToString ( ) , psbt . tx - > vin [ i ] . prevout . n ) ) ;
2018-07-20 18:24:16 -07:00
}
}
for ( unsigned int i = 0 ; i < psbt . tx - > vout . size ( ) ; + + i ) {
merged_psbt . AddOutput ( psbt . tx - > vout [ i ] , psbt . outputs [ i ] ) ;
}
2019-07-31 17:24:44 -04:00
for ( auto & xpub_pair : psbt . m_xpubs ) {
if ( merged_psbt . m_xpubs . count ( xpub_pair . first ) = = 0 ) {
merged_psbt . m_xpubs [ xpub_pair . first ] = xpub_pair . second ;
} else {
merged_psbt . m_xpubs [ xpub_pair . first ] . insert ( xpub_pair . second . begin ( ) , xpub_pair . second . end ( ) ) ;
}
}
2018-07-20 18:24:16 -07:00
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 ) ;
2019-11-04 04:22:53 -05:00
// Shuffle input and output indices lists
2019-07-31 18:02:24 -04:00
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 ( ) ) ;
2023-11-19 14:58:00 +01:00
DataStream ssTx { } ;
2019-07-31 18:02:24 -04:00
ssTx < < shuffled_psbt ;
2020-11-25 11:21:14 +01:00
return EncodeBase64 ( ssTx ) ;
2020-08-31 18:29:48 +02:00
} ,
} ;
2018-07-20 18:24:16 -07:00
}
2020-08-31 18:29:48 +02:00
static RPCHelpMan analyzepsbt ( )
2018-07-31 17:58:01 -07:00
{
2020-08-31 18:29:48 +02:00
return RPCHelpMan { " analyzepsbt " ,
2018-07-31 17:58:01 -07:00
" \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 {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : OBJ , " " , " " ,
{
2021-12-08 11:55:46 +01:00
{ RPCResult : : Type : : ARR , " inputs " , /*optional=*/ true , " " ,
2020-01-10 00:00:57 +07:00
{
{ RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : BOOL , " has_utxo " , " Whether a UTXO is provided " } ,
{ RPCResult : : Type : : BOOL , " is_final " , " Whether the input is finalized " } ,
2021-12-08 11:55:46 +01:00
{ RPCResult : : Type : : OBJ , " missing " , /*optional=*/ true , " Things that are missing that are required to complete this input " ,
2020-01-10 00:00:57 +07:00
{
2021-12-08 11:55:46 +01:00
{ RPCResult : : Type : : ARR , " pubkeys " , /*optional=*/ true , " " ,
2020-01-10 00:00:57 +07:00
{
{ RPCResult : : Type : : STR_HEX , " keyid " , " Public key ID, hash160 of the public key, of a public key whose BIP 32 derivation path is missing " } ,
} } ,
2021-12-08 11:55:46 +01:00
{ RPCResult : : Type : : ARR , " signatures " , /*optional=*/ true , " " ,
2020-01-10 00:00:57 +07:00
{
{ RPCResult : : Type : : STR_HEX , " keyid " , " Public key ID, hash160 of the public key, of a public key whose signature is missing " } ,
} } ,
2021-12-08 11:55:46 +01:00
{ RPCResult : : Type : : STR_HEX , " redeemscript " , /*optional=*/ true , " Hash160 of the redeemScript that is missing " } ,
{ RPCResult : : Type : : STR_HEX , " witnessscript " , /*optional=*/ true , " SHA256 of the witnessScript that is missing " } ,
2020-01-10 00:00:57 +07:00
} } ,
2021-12-08 11:55:46 +01:00
{ RPCResult : : Type : : STR , " next " , /*optional=*/ true , " Role of the next person that this input needs to go to " } ,
2020-01-10 00:00:57 +07:00
} } ,
} } ,
2021-12-08 11:55:46 +01:00
{ RPCResult : : Type : : NUM , " estimated_vsize " , /*optional=*/ true , " Estimated vsize of the final signed transaction " } ,
{ RPCResult : : Type : : STR_AMOUNT , " estimated_feerate " , /*optional=*/ true , " Estimated feerate of the final signed transaction in " + CURRENCY_UNIT + " /kvB. Shown only if all UTXO slots in the PSBT have been filled " } ,
{ RPCResult : : Type : : STR_AMOUNT , " fee " , /*optional=*/ true , " The transaction fee paid. Shown only if all UTXO slots in the PSBT have been filled " } ,
2020-01-10 00:00:57 +07:00
{ RPCResult : : Type : : STR , " next " , " Role of the next person that this psbt needs to go to " } ,
2021-12-08 11:55:46 +01:00
{ RPCResult : : Type : : STR , " error " , /*optional=*/ true , " Error message (if there is one) " } ,
2020-01-10 00:00:57 +07:00
}
2018-07-31 17:58:01 -07:00
} ,
RPCExamples {
HelpExampleCli ( " analyzepsbt " , " \" psbt \" " )
2020-08-31 18:29:48 +02:00
} ,
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2018-07-31 17:58:01 -07:00
// 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 ) ;
}
2019-11-19 14:35:14 -05:00
if ( ! inputs_result . empty ( ) ) result . pushKV ( " inputs " , inputs_result ) ;
2018-07-31 17:58:01 -07:00
2021-03-15 10:41:30 +08:00
if ( psbta . estimated_vsize ! = std : : nullopt ) {
2019-03-01 00:25:10 -08:00
result . pushKV ( " estimated_vsize " , ( int ) * psbta . estimated_vsize ) ;
2018-07-31 17:58:01 -07:00
}
2021-03-15 10:41:30 +08:00
if ( psbta . estimated_feerate ! = std : : nullopt ) {
2019-03-01 00:25:10 -08:00
result . pushKV ( " estimated_feerate " , ValueFromAmount ( psbta . estimated_feerate - > GetFeePerK ( ) ) ) ;
2018-07-31 17:58:01 -07:00
}
2021-03-15 10:41:30 +08:00
if ( psbta . fee ! = std : : nullopt ) {
2019-03-01 00:25:10 -08:00
result . pushKV ( " fee " , ValueFromAmount ( * psbta . fee ) ) ;
}
result . pushKV ( " next " , PSBTRoleName ( psbta . next ) ) ;
2019-11-19 14:35:14 -05:00
if ( ! psbta . error . empty ( ) ) {
result . pushKV ( " error " , psbta . error ) ;
}
2019-03-01 00:25:10 -08:00
2018-07-31 17:58:01 -07:00
return result ;
2020-08-31 18:29:48 +02:00
} ,
} ;
2018-07-31 17:58:01 -07:00
}
2022-08-03 19:32:59 -04:00
RPCHelpMan descriptorprocesspsbt ( )
{
return RPCHelpMan { " descriptorprocesspsbt " ,
" \n Update all segwit inputs in a PSBT with information from output descriptors, the UTXO set or the mempool. \n "
" Then, sign the inputs we are able to with information from the output descriptors. " ,
{
{ " psbt " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " The transaction base64 string " } ,
{ " descriptors " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " 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 , RPCArg : : Default { 1000 } , " Up to what index HD chains should be explored (either end or [begin,end]) " } ,
} } ,
} } ,
{ " sighashtype " , RPCArg : : Type : : STR , RPCArg : : Default { " DEFAULT for Taproot, ALL otherwise " } , " The signature hash type to sign with if not specified by the PSBT. Must be one of \n "
" \" DEFAULT \" \n "
" \" ALL \" \n "
" \" NONE \" \n "
" \" SINGLE \" \n "
" \" ALL|ANYONECANPAY \" \n "
" \" NONE|ANYONECANPAY \" \n "
" \" SINGLE|ANYONECANPAY \" " } ,
{ " bip32derivs " , RPCArg : : Type : : BOOL , RPCArg : : Default { true } , " Include BIP 32 derivation paths for public keys if we know them " } ,
{ " finalize " , RPCArg : : Type : : BOOL , RPCArg : : Default { true } , " Also finalize inputs if possible " } ,
} ,
RPCResult {
RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR , " psbt " , " The base64-encoded partially signed transaction " } ,
{ RPCResult : : Type : : BOOL , " complete " , " If the transaction has a complete set of signatures " } ,
2023-09-15 16:46:09 +01:00
{ RPCResult : : Type : : STR_HEX , " hex " , /*optional=*/ true , " The hex-encoded network transaction if complete " } ,
2022-08-03 19:32:59 -04:00
}
} ,
RPCExamples {
HelpExampleCli ( " descriptorprocesspsbt " , " \" psbt \" \" [ \\ \" descriptor1 \\ \" , \\ \" descriptor2 \\ \" ] \" " ) +
HelpExampleCli ( " descriptorprocesspsbt " , " \" psbt \" \" [{ \\ \" desc \\ \" : \\ \" mydescriptor \\ \" , \\ \" range \\ \" :21}] \" " )
} ,
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
// Add descriptor information to a signing provider
FlatSigningProvider provider ;
auto descs = request . params [ 1 ] . get_array ( ) ;
for ( size_t i = 0 ; i < descs . size ( ) ; + + i ) {
EvalDescriptorStringOrObject ( descs [ i ] , provider , /*expand_priv=*/ true ) ;
}
int sighash_type = ParseSighashString ( request . params [ 2 ] ) ;
bool bip32derivs = request . params [ 3 ] . isNull ( ) ? true : request . params [ 3 ] . get_bool ( ) ;
bool finalize = request . params [ 4 ] . isNull ( ) ? true : request . params [ 4 ] . get_bool ( ) ;
const PartiallySignedTransaction & psbtx = ProcessPSBT (
request . params [ 0 ] . get_str ( ) ,
request . context ,
HidingSigningProvider ( & provider , /*hide_secret=*/ false , ! bip32derivs ) ,
sighash_type ,
finalize ) ;
// Check whether or not all of the inputs are now signed
bool complete = true ;
for ( const auto & input : psbtx . inputs ) {
complete & = PSBTInputSigned ( input ) ;
}
2023-11-19 14:58:00 +01:00
DataStream ssTx { } ;
2022-08-03 19:32:59 -04:00
ssTx < < psbtx ;
UniValue result ( UniValue : : VOBJ ) ;
result . pushKV ( " psbt " , EncodeBase64 ( ssTx ) ) ;
result . pushKV ( " complete " , complete ) ;
2023-09-15 16:46:09 +01:00
if ( complete ) {
CMutableTransaction mtx ;
PartiallySignedTransaction psbtx_copy = psbtx ;
CHECK_NONFATAL ( FinalizeAndExtractPSBT ( psbtx_copy , mtx ) ) ;
2023-09-07 19:16:57 +10:00
DataStream ssTx_final ;
ssTx_final < < TX_WITH_WITNESS ( mtx ) ;
2023-09-15 16:46:09 +01:00
result . pushKV ( " hex " , HexStr ( ssTx_final ) ) ;
}
2022-08-03 19:32:59 -04:00
return result ;
} ,
} ;
}
2022-04-24 16:44:35 +02:00
void RegisterRawTransactionRPCCommands ( CRPCTable & t )
2020-04-06 00:21:33 +08:00
{
2022-04-24 16:44:35 +02:00
static const CRPCCommand commands [ ] {
{ " rawtransactions " , & getrawtransaction } ,
{ " rawtransactions " , & createrawtransaction } ,
{ " rawtransactions " , & decoderawtransaction } ,
{ " rawtransactions " , & decodescript } ,
{ " rawtransactions " , & combinerawtransaction } ,
{ " rawtransactions " , & signrawtransactionwithkey } ,
{ " rawtransactions " , & decodepsbt } ,
{ " rawtransactions " , & combinepsbt } ,
{ " rawtransactions " , & finalizepsbt } ,
{ " rawtransactions " , & createpsbt } ,
{ " rawtransactions " , & converttopsbt } ,
{ " rawtransactions " , & utxoupdatepsbt } ,
2022-08-03 19:32:59 -04:00
{ " rawtransactions " , & descriptorprocesspsbt } ,
2022-04-24 16:44:35 +02:00
{ " rawtransactions " , & joinpsbts } ,
{ " rawtransactions " , & analyzepsbt } ,
} ;
2020-07-15 21:29:41 +02:00
for ( const auto & c : commands ) {
t . appendCommand ( c . name , & c ) ;
}
2016-03-29 19:43:02 +02:00
}