aboutsummaryrefslogtreecommitdiff
path: root/src/rpc/rawtransaction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc/rawtransaction.cpp')
-rw-r--r--src/rpc/rawtransaction.cpp338
1 files changed, 274 insertions, 64 deletions
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index b369cce014..3c9e0625e6 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -1,8 +1,9 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <base58.h>
#include <chain.h>
#include <coins.h>
#include <consensus/amount.h>
@@ -25,6 +26,7 @@
#include <rpc/blockchain.h>
#include <rpc/rawtransaction_util.h>
#include <rpc/server.h>
+#include <rpc/server_util.h>
#include <rpc/util.h>
#include <script/script.h>
#include <script/sign.h>
@@ -132,7 +134,7 @@ static RPCHelpMan getrawtransaction()
RPCResult{"if verbose is set to true",
RPCResult::Type::OBJ, "", "",
{
- {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::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, "hex", "The serialized, hex-encoded data for 'txid'"},
{RPCResult::Type::STR_HEX, "txid", "The transaction id (same as provided)"},
{RPCResult::Type::STR_HEX, "hash", "The transaction hash (differs from txid for witness transactions)"},
@@ -153,7 +155,7 @@ static RPCHelpMan getrawtransaction()
{RPCResult::Type::STR_HEX, "hex", "hex"},
}},
{RPCResult::Type::NUM, "sequence", "The script sequence number"},
- {RPCResult::Type::ARR, "txinwitness", /* optional */ true, "",
+ {RPCResult::Type::ARR, "txinwitness", /*optional=*/true, "",
{
{RPCResult::Type::STR_HEX, "hex", "hex-encoded witness data (if any)"},
}},
@@ -170,14 +172,14 @@ static RPCHelpMan getrawtransaction()
{RPCResult::Type::STR, "asm", "the asm"},
{RPCResult::Type::STR, "hex", "the hex"},
{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::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
}},
}},
}},
- {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\""},
+ {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\""},
}
},
},
@@ -471,15 +473,15 @@ static RPCHelpMan decoderawtransaction()
{
{RPCResult::Type::OBJ, "", "",
{
- {RPCResult::Type::STR_HEX, "coinbase", /* optional */ true, ""},
- {RPCResult::Type::STR_HEX, "txid", /* optional */ true, "The transaction id"},
- {RPCResult::Type::NUM, "vout", /* optional */ true, "The output number"},
- {RPCResult::Type::OBJ, "scriptSig", /* optional */ true, "The script",
+ {RPCResult::Type::STR_HEX, "coinbase", /*optional=*/true, ""},
+ {RPCResult::Type::STR_HEX, "txid", /*optional=*/true, "The transaction id"},
+ {RPCResult::Type::NUM, "vout", /*optional=*/true, "The output number"},
+ {RPCResult::Type::OBJ, "scriptSig", /*optional=*/true, "The script",
{
{RPCResult::Type::STR, "asm", "asm"},
{RPCResult::Type::STR_HEX, "hex", "hex"},
}},
- {RPCResult::Type::ARR, "txinwitness", /* optional */ true, "",
+ {RPCResult::Type::ARR, "txinwitness", /*optional=*/true, "",
{
{RPCResult::Type::STR_HEX, "hex", "hex-encoded witness data (if any)"},
}},
@@ -497,7 +499,7 @@ static RPCHelpMan decoderawtransaction()
{RPCResult::Type::STR, "asm", "the asm"},
{RPCResult::Type::STR_HEX, "hex", "the hex"},
{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::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
}},
}},
}},
@@ -551,14 +553,16 @@ static RPCHelpMan decodescript()
{
{RPCResult::Type::STR, "asm", "Script public key"},
{RPCResult::Type::STR, "type", "The output type (e.g. " + GetAllOutputTypes() + ")"},
- {RPCResult::Type::STR, "address", /* optional */ true, "The Bitcoin address (only if a well-defined address exists)"},
- {RPCResult::Type::STR, "p2sh", /* optional */ true, "address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH)"},
- {RPCResult::Type::OBJ, "segwit", /* optional */ true, "Result of a witness script public key wrapping this redeem script (not returned if the script is a P2SH or witness)",
+ {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
+ {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)",
{
{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)"},
- {RPCResult::Type::STR, "address", /* optional */ true, "The Bitcoin address (only if a well-defined address exists)"},
+ {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
{RPCResult::Type::STR, "p2sh-segwit", "address of the P2SH script wrapping this witness redeem script"},
}},
},
@@ -584,22 +588,68 @@ static RPCHelpMan decodescript()
std::vector<std::vector<unsigned char>> solutions_data;
const TxoutType which_type{Solver(script, solutions_data)};
- if (which_type != TxoutType::SCRIPTHASH) {
- // P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,
- // don't return the address for a P2SH of the P2SH.
+ 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) {
r.pushKV("p2sh", EncodeDestination(ScriptHash(script)));
// P2SH and witness programs cannot be wrapped in P2WSH, if this script
// is a witness program, don't return addresses for a segwit programs.
- if (which_type == TxoutType::PUBKEY || which_type == TxoutType::PUBKEYHASH || which_type == TxoutType::MULTISIG || which_type == TxoutType::NONSTANDARD) {
+ const bool can_wrap_P2WSH{[&] {
+ switch (which_type) {
+ case TxoutType::MULTISIG:
+ case TxoutType::PUBKEY:
// Uncompressed pubkeys cannot be used with segwit checksigs.
// If the script contains an uncompressed pubkey, skip encoding of a segwit program.
- if ((which_type == TxoutType::PUBKEY) || (which_type == TxoutType::MULTISIG)) {
for (const auto& solution : solutions_data) {
if ((solution.size() != 1) && !CPubKey(solution).IsCompressed()) {
- return r;
+ return false;
}
}
- }
+ 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
+ CHECK_NONFATAL(false);
+ }()};
+ if (can_wrap_P2WSH) {
UniValue sr(UniValue::VOBJ);
CScript segwitScr;
if (which_type == TxoutType::PUBKEY) {
@@ -608,7 +658,6 @@ static RPCHelpMan decodescript()
segwitScr = GetScriptForDestination(WitnessV0KeyHash(uint160{solutions_data[0]}));
} else {
// Scripts that are not fit for P2WPKH are encoded as P2WSH.
- // Newer segwit program versions should be considered when then become available.
segwitScr = GetScriptForDestination(WitnessV0ScriptHash(script));
}
ScriptPubKeyToUniv(segwitScr, sr, /* include_hex */ true);
@@ -737,7 +786,7 @@ static RPCHelpMan signrawtransactionwithkey()
},
},
},
- {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"DEFAULT"}, "The signature hash type. Must be one of:\n"
+ {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"DEFAULT for Taproot, ALL otherwise"}, "The signature hash type. Must be one of:\n"
" \"DEFAULT\"\n"
" \"ALL\"\n"
" \"NONE\"\n"
@@ -752,7 +801,7 @@ static RPCHelpMan signrawtransactionwithkey()
{
{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"},
- {RPCResult::Type::ARR, "errors", /* optional */ true, "Script verification errors (if there are any)",
+ {RPCResult::Type::ARR, "errors", /*optional=*/true, "Script verification errors (if there are any)",
{
{RPCResult::Type::OBJ, "", "",
{
@@ -899,15 +948,15 @@ static RPCHelpMan testmempoolaccept()
{
{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
{RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
- {RPCResult::Type::STR, "package-error", /* optional */ true, "Package validation error, if any (only possible if rawtxs had more than 1 transaction)."},
- {RPCResult::Type::BOOL, "allowed", /* optional */ true, "Whether this tx would be accepted to the mempool and pass client-specified maxfeerate. "
+ {RPCResult::Type::STR, "package-error", /*optional=*/true, "Package validation error, if any (only possible if rawtxs had more than 1 transaction)."},
+ {RPCResult::Type::BOOL, "allowed", /*optional=*/true, "Whether this tx would be accepted to the mempool and pass client-specified maxfeerate. "
"If not present, the tx was not fully validated due to a failure in another tx in the list."},
- {RPCResult::Type::NUM, "vsize", /* optional */ true, "Virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted (only present when 'allowed' is true)"},
- {RPCResult::Type::OBJ, "fees", /* optional */ true, "Transaction fees (only present if 'allowed' is true)",
+ {RPCResult::Type::NUM, "vsize", /*optional=*/true, "Virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted (only present when 'allowed' is true)"},
+ {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees (only present if 'allowed' is true)",
{
{RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
}},
- {RPCResult::Type::STR, "reject-reason", /* optional */ true, "Rejection string (only present when 'allowed' is false)"},
+ {RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection string (only present when 'allowed' is false)"},
}},
}
},
@@ -979,6 +1028,8 @@ static RPCHelpMan testmempoolaccept()
continue;
}
const auto& tx_result = it->second;
+ // Package testmempoolaccept doesn't allow transactions to already be in the mempool.
+ CHECK_NONFATAL(tx_result.m_result_type != MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
const CAmount fee = tx_result.m_base_fees.value();
// Check that fee does not exceed maximum fee
@@ -1027,6 +1078,26 @@ static RPCHelpMan decodepsbt()
{
{RPCResult::Type::ELISION, "", "The layout is the same as the output of decoderawtransaction."},
}},
+ {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"},
+ }},
+ }},
+ {RPCResult::Type::NUM, "psbt_version", "The PSBT version number. Not to be confused with the unsigned transaction version"},
+ {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"},
+ }},
+ }},
{RPCResult::Type::OBJ_DYN, "unknown", "The unknown global fields",
{
{RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"},
@@ -1035,11 +1106,11 @@ static RPCHelpMan decodepsbt()
{
{RPCResult::Type::OBJ, "", "",
{
- {RPCResult::Type::OBJ, "non_witness_utxo", /* optional */ true, "Decoded network transaction for non-witness UTXOs",
+ {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::OBJ, "witness_utxo", /*optional=*/true, "Transaction output for witness UTXOs",
{
{RPCResult::Type::NUM, "amount", "The value in " + CURRENCY_UNIT},
{RPCResult::Type::OBJ, "scriptPubKey", "",
@@ -1047,27 +1118,27 @@ static RPCHelpMan decodepsbt()
{RPCResult::Type::STR, "asm", "The asm"},
{RPCResult::Type::STR_HEX, "hex", "The hex"},
{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::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
}},
}},
- {RPCResult::Type::OBJ_DYN, "partial_signatures", /* optional */ true, "",
+ {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, "",
+ {RPCResult::Type::STR, "sighash", /*optional=*/true, "The sighash type to be used"},
+ {RPCResult::Type::OBJ, "redeem_script", /*optional=*/true, "",
{
{RPCResult::Type::STR, "asm", "The asm"},
{RPCResult::Type::STR_HEX, "hex", "The hex"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
}},
- {RPCResult::Type::OBJ, "witness_script", /* optional */ true, "",
+ {RPCResult::Type::OBJ, "witness_script", /*optional=*/true, "",
{
{RPCResult::Type::STR, "asm", "The asm"},
{RPCResult::Type::STR_HEX, "hex", "The hex"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
}},
- {RPCResult::Type::ARR, "bip32_derivs", /* optional */ true, "",
+ {RPCResult::Type::ARR, "bip32_derivs", /*optional=*/true, "",
{
{RPCResult::Type::OBJ, "", "",
{
@@ -1076,38 +1147,64 @@ static RPCHelpMan decodepsbt()
{RPCResult::Type::STR, "path", "The path"},
}},
}},
- {RPCResult::Type::OBJ, "final_scriptSig", /* optional */ true, "",
+ {RPCResult::Type::OBJ, "final_scriptSig", /*optional=*/true, "",
{
{RPCResult::Type::STR, "asm", "The asm"},
{RPCResult::Type::STR, "hex", "The hex"},
}},
- {RPCResult::Type::ARR, "final_scriptwitness", /* optional */ true, "",
+ {RPCResult::Type::ARR, "final_scriptwitness", /*optional=*/true, "",
{
{RPCResult::Type::STR_HEX, "", "hex-encoded witness data (if any)"},
}},
- {RPCResult::Type::OBJ_DYN, "unknown", /* optional */ true, "The unknown global fields",
+ {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::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", "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"},
+ }},
+ }},
}},
}},
{RPCResult::Type::ARR, "outputs", "",
{
{RPCResult::Type::OBJ, "", "",
{
- {RPCResult::Type::OBJ, "redeem_script", /* optional */ true, "",
+ {RPCResult::Type::OBJ, "redeem_script", /*optional=*/true, "",
{
{RPCResult::Type::STR, "asm", "The asm"},
{RPCResult::Type::STR_HEX, "hex", "The hex"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
}},
- {RPCResult::Type::OBJ, "witness_script", /* optional */ true, "",
+ {RPCResult::Type::OBJ, "witness_script", /*optional=*/true, "",
{
{RPCResult::Type::STR, "asm", "The asm"},
{RPCResult::Type::STR_HEX, "hex", "The hex"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
}},
- {RPCResult::Type::ARR, "bip32_derivs", /* optional */ true, "",
+ {RPCResult::Type::ARR, "bip32_derivs", /*optional=*/true, "",
{
{RPCResult::Type::OBJ, "", "",
{
@@ -1116,13 +1213,23 @@ static RPCHelpMan decodepsbt()
{RPCResult::Type::STR, "path", "The path"},
}},
}},
- {RPCResult::Type::OBJ_DYN, "unknown", /* optional */ true, "The unknown global fields",
+ {RPCResult::Type::OBJ_DYN, "unknown", /*optional=*/true, "The unknown global fields",
{
{RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"},
}},
+ {RPCResult::Type::ARR, "proprietary", "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"},
+ }},
+ }},
}},
}},
- {RPCResult::Type::STR_AMOUNT, "fee", /* optional */ true, "The transaction fee paid if all UTXOs slots in the PSBT have been filled."},
+ {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The transaction fee paid if all UTXOs slots in the PSBT have been filled."},
}
},
RPCExamples{
@@ -1146,6 +1253,38 @@ static RPCHelpMan decodepsbt()
TxToUniv(CTransaction(*psbtx.tx), uint256(), tx_univ, false);
result.pushKV("tx", tx_univ);
+ // 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);
+
+ // PSBT version
+ result.pushKV("psbt_version", static_cast<uint64_t>(psbtx.GetVersion()));
+
+ // 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);
+
// Unknown data
UniValue unknowns(UniValue::VOBJ);
for (auto entry : psbtx.unknown) {
@@ -1207,8 +1346,8 @@ static RPCHelpMan decodepsbt()
}
// Sighash
- if (input.sighash_type > 0) {
- in.pushKV("sighash", SighashToStr((unsigned char)input.sighash_type));
+ if (input.sighash_type != std::nullopt) {
+ in.pushKV("sighash", SighashToStr((unsigned char)*input.sighash_type));
}
// Redeem script and witness script
@@ -1252,6 +1391,56 @@ static RPCHelpMan decodepsbt()
in.pushKV("final_scriptwitness", txinwitness);
}
+ // 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);
+ }
+
+ // 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);
+ }
+
// Unknown data
if (input.unknown.size() > 0) {
UniValue unknowns(UniValue::VOBJ);
@@ -1296,6 +1485,20 @@ static RPCHelpMan decodepsbt()
out.pushKV("bip32_derivs", keypaths);
}
+ // 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);
+ }
+
// Unknown data
if (output.unknown.size() > 0) {
UniValue unknowns(UniValue::VOBJ);
@@ -1390,8 +1593,8 @@ static RPCHelpMan finalizepsbt()
RPCResult{
RPCResult::Type::OBJ, "", "",
{
- {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"},
+ {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"},
{RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
}
},
@@ -1709,6 +1912,13 @@ static RPCHelpMan joinpsbts()
for (unsigned int i = 0; i < psbt.tx->vout.size(); ++i) {
merged_psbt.AddOutput(psbt.tx->vout[i], psbt.outputs[i]);
}
+ 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());
+ }
+ }
merged_psbt.unknown.insert(psbt.unknown.begin(), psbt.unknown.end());
}
@@ -1751,33 +1961,33 @@ static RPCHelpMan analyzepsbt()
RPCResult {
RPCResult::Type::OBJ, "", "",
{
- {RPCResult::Type::ARR, "inputs", /* optional */ true, "",
+ {RPCResult::Type::ARR, "inputs", /*optional=*/true, "",
{
{RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::BOOL, "has_utxo", "Whether a UTXO is provided"},
{RPCResult::Type::BOOL, "is_final", "Whether the input is finalized"},
- {RPCResult::Type::OBJ, "missing", /* optional */ true, "Things that are missing that are required to complete this input",
+ {RPCResult::Type::OBJ, "missing", /*optional=*/true, "Things that are missing that are required to complete this input",
{
- {RPCResult::Type::ARR, "pubkeys", /* optional */ true, "",
+ {RPCResult::Type::ARR, "pubkeys", /*optional=*/true, "",
{
{RPCResult::Type::STR_HEX, "keyid", "Public key ID, hash160 of the public key, of a public key whose BIP 32 derivation path is missing"},
}},
- {RPCResult::Type::ARR, "signatures", /* optional */ true, "",
+ {RPCResult::Type::ARR, "signatures", /*optional=*/true, "",
{
{RPCResult::Type::STR_HEX, "keyid", "Public key ID, hash160 of the public key, of a public key whose signature is missing"},
}},
- {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"},
+ {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"},
}},
- {RPCResult::Type::STR, "next", /* optional */ true, "Role of the next person that this input needs to go to"},
+ {RPCResult::Type::STR, "next", /*optional=*/true, "Role of the next person that this input needs to go to"},
}},
}},
- {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"},
+ {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"},
{RPCResult::Type::STR, "next", "Role of the next person that this psbt needs to go to"},
- {RPCResult::Type::STR, "error", /* optional */ true, "Error message (if there is one)"},
+ {RPCResult::Type::STR, "error", /*optional=*/true, "Error message (if there is one)"},
}
},
RPCExamples {