diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 7eb1c68ce69..dfabf073b15 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -845,6 +845,11 @@ const RPCResult& DecodePSBTInputs() { {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, }}, + {RPCResult::Type::STR_HEX, "previous_txid", /*optional=*/true, "TXID of the transaction containing the output being spent by this input"}, + {RPCResult::Type::NUM, "previous_vout", /*optional=*/true, "Index of the output being spent"}, + {RPCResult::Type::NUM, "sequence", /*optional=*/true, "Sequence number for this input"}, + {RPCResult::Type::NUM, "time_locktime", /*optional=*/true, "Time-based locktime required for this input"}, + {RPCResult::Type::NUM, "height_locktime", /*optional=*/true, "Height-based locktime required for this input"}, {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, "", { @@ -961,6 +966,10 @@ const RPCResult& DecodePSBTOutputs() {RPCResult::Type::STR, "path", "The path"}, }}, }}, + {RPCResult::Type::NUM, "amount", /* optional=*/ true, "The amount (nValue) for this output"}, + {RPCResult::Type::OBJ, "script", /* optional=*/ true, "The output script (scriptPubKey) for this output", + {{RPCResult::Type::ELISION, "", "The layout is the same as the output of scriptPubKeys in decoderawtransaction."}}, + }, {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", { @@ -1026,7 +1035,7 @@ static RPCMethod decodepsbt() RPCResult{ RPCResult::Type::OBJ, "", "", { - {RPCResult::Type::OBJ, "tx", "The decoded network-serialized unsigned transaction.", + {RPCResult::Type::OBJ, "tx", /*optional=*/true, "The decoded network-serialized unsigned transaction.", TxDoc({.elision_description="The layout is the same as the output of decoderawtransaction."}) }, {RPCResult::Type::ARR, "global_xpubs", "", @@ -1038,7 +1047,14 @@ static RPCMethod decodepsbt() {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::NUM, "tx_version", /* optional */ true, "The version number of the unsigned transaction. Not to be confused with PSBT version"}, + {RPCResult::Type::NUM, "fallback_locktime", /* optional */ true, "The locktime to fallback to if no inputs specify a required locktime."}, + {RPCResult::Type::NUM, "input_count", /* optional */ true, "The number of inputs in this psbt"}, + {RPCResult::Type::NUM, "output_count", /* optional */ true, "The number of outputs in this psbt."}, + {RPCResult::Type::BOOL, "inputs_modifiable", /* optional */ true, "Whether inputs can be modified"}, + {RPCResult::Type::BOOL, "outputs_modifiable", /* optional */ true, "Whether outputs can be modified"}, + {RPCResult::Type::BOOL, "has_sighash_single", /* optional */ true, "Whether this PSBT has SIGHASH_SINGLE inputs"}, + {RPCResult::Type::NUM, "psbt_version", /* optional */ true, "The PSBT version number. Not to be confused with the unsigned transaction version"}, {RPCResult::Type::ARR, "proprietary", "The global proprietary map", { {RPCResult::Type::OBJ, "", "", @@ -1072,10 +1088,12 @@ static RPCMethod decodepsbt() UniValue result(UniValue::VOBJ); - // Add the decoded tx - UniValue tx_univ(UniValue::VOBJ); - TxToUniv(CTransaction(*CHECK_NONFATAL(psbtx.GetUnsignedTx())), /*block_hash=*/uint256(), /*entry=*/tx_univ, /*include_hex=*/false); - result.pushKV("tx", std::move(tx_univ)); + if (psbtx.GetVersion() < 2) { + // Add the decoded tx + UniValue tx_univ(UniValue::VOBJ); + TxToUniv(CTransaction(*CHECK_NONFATAL(psbtx.GetUnsignedTx())), /*block_hash=*/uint256(), /*entry=*/tx_univ, /*include_hex=*/false); + result.pushKV("tx", std::move(tx_univ)); + } // Add the global xpubs UniValue global_xpubs(UniValue::VARR); @@ -1094,6 +1112,21 @@ static RPCMethod decodepsbt() } result.pushKV("global_xpubs", std::move(global_xpubs)); + // Add PSBTv2 stuff + if (psbtx.GetVersion() >= 2) { + result.pushKV("tx_version", psbtx.tx_version); + if (psbtx.fallback_locktime.has_value()) { + result.pushKV("fallback_locktime", static_cast(*psbtx.fallback_locktime)); + } + result.pushKV("input_count", (uint64_t)psbtx.inputs.size()); + result.pushKV("output_count", (uint64_t)psbtx.outputs.size()); + if (psbtx.m_tx_modifiable.has_value()) { + result.pushKV("inputs_modifiable", psbtx.m_tx_modifiable->test(0)); + result.pushKV("outputs_modifiable", psbtx.m_tx_modifiable->test(1)); + result.pushKV("has_sighash_single", psbtx.m_tx_modifiable->test(2)); + } + } + // PSBT version result.pushKV("psbt_version", psbtx.GetVersion()); @@ -1251,6 +1284,21 @@ static RPCMethod decodepsbt() in.pushKV("hash256_preimages", std::move(hash256_preimages)); } + // PSBTv2 + if (psbtx.GetVersion() >= 2) { + in.pushKV("previous_txid", input.prev_txid.GetHex()); + in.pushKV("previous_vout", static_cast(input.prev_out)); + if (input.sequence.has_value()) { + in.pushKV("sequence", static_cast(*input.sequence)); + } + if (input.time_locktime.has_value()) { + in.pushKV("time_locktime", static_cast(*input.time_locktime)); + } + if (input.height_locktime.has_value()) { + in.pushKV("height_locktime", static_cast(*input.height_locktime)); + } + } + // Taproot key path signature if (!input.m_tap_key_sig.empty()) { in.pushKV("taproot_key_path_sig", HexStr(input.m_tap_key_sig)); @@ -1421,6 +1469,14 @@ static RPCMethod decodepsbt() out.pushKV("bip32_derivs", std::move(keypaths)); } + // PSBTv2 stuff + if (psbtx.GetVersion() >= 2) { + out.pushKV("amount", ValueFromAmount(output.amount)); + UniValue spk(UniValue::VOBJ); + ScriptToUniv(output.script, spk, /*include_hex=*/true, /*include_address=*/true); + out.pushKV("script", spk); + } + // Taproot internal key if (!output.m_tap_internal_key.IsNull()) { out.pushKV("taproot_internal_key", HexStr(output.m_tap_internal_key));