diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 950c7e04004..de762767576 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -916,6 +916,37 @@ const RPCResult decodepsbt_inputs{ }}, {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::ARR, "musig2_participant_pubkeys", /*optional=*/true, "", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR_HEX, "aggregate_pubkey", "The compressed aggregate public key for which the participants create."}, + {RPCResult::Type::ARR, "participant_pubkeys", "", + { + {RPCResult::Type::STR_HEX, "pubkey", "The compressed public keys that are aggregated for aggregate_pubkey."}, + }}, + }}, + }}, + {RPCResult::Type::ARR, "musig2_pubnonces", /*optional=*/true, "", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR_HEX, "participant_pubkey", "The compressed public key of the participant that created this pubnonce."}, + {RPCResult::Type::STR_HEX, "aggregate_pubkey", "The compressed aggregate public key for which this pubnonce is for."}, + {RPCResult::Type::STR_HEX, "leaf_hash", /*optional=*/true, "The hash of the leaf script that contains the aggregate pubkey being signed for. Omitted when signing for the internal key."}, + {RPCResult::Type::STR_HEX, "pubnonce", "The public nonce itself."}, + }}, + }}, + {RPCResult::Type::ARR, "musig2_partial_sigs", /*optional=*/true, "", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR_HEX, "participant_pubkey", "The compressed public key of the participant that created this partial signature."}, + {RPCResult::Type::STR_HEX, "aggregate_pubkey", "The compressed aggregate public key for which this partial signature is for."}, + {RPCResult::Type::STR_HEX, "leaf_hash", /*optional=*/true, "The hash of the leaf script that contains the aggregate pubkey being signed for. Omitted when signing for the internal key."}, + {RPCResult::Type::STR_HEX, "partial_sig", "The partial signature itself."}, + }}, + }}, {RPCResult::Type::OBJ_DYN, "unknown", /*optional=*/ true, "The unknown input fields", { {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, @@ -983,6 +1014,17 @@ const RPCResult decodepsbt_outputs{ }}, }}, }}, + {RPCResult::Type::ARR, "musig2_participant_pubkeys", /*optional=*/true, "", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR_HEX, "aggregate_pubkey", "The compressed aggregate public key for which the participants create."}, + {RPCResult::Type::ARR, "participant_pubkeys", "", + { + {RPCResult::Type::STR_HEX, "pubkey", "The compressed public keys that are aggregated for aggregate_pubkey."}, + }}, + }}, + }}, {RPCResult::Type::OBJ_DYN, "unknown", /*optional=*/true, "The unknown output fields", { {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, @@ -1304,6 +1346,52 @@ static RPCHelpMan decodepsbt() in.pushKV("taproot_merkle_root", HexStr(input.m_tap_merkle_root)); } + // Write MuSig2 fields + if (!input.m_musig2_participants.empty()) { + UniValue musig_pubkeys(UniValue::VARR); + for (const auto& [agg, parts] : input.m_musig2_participants) { + UniValue musig_part(UniValue::VOBJ); + musig_part.pushKV("aggregate_pubkey", HexStr(agg)); + UniValue part_pubkeys(UniValue::VARR); + for (const auto& pub : parts) { + part_pubkeys.push_back(HexStr(pub)); + } + musig_part.pushKV("participant_pubkeys", part_pubkeys); + musig_pubkeys.push_back(musig_part); + } + in.pushKV("musig2_participant_pubkeys", musig_pubkeys); + } + if (!input.m_musig2_pubnonces.empty()) { + UniValue musig_pubnonces(UniValue::VARR); + for (const auto& [agg_lh, part_pubnonce] : input.m_musig2_pubnonces) { + const auto& [agg, lh] = agg_lh; + for (const auto& [part, pubnonce] : part_pubnonce) { + UniValue info(UniValue::VOBJ); + info.pushKV("participant_pubkey", HexStr(part)); + info.pushKV("aggregate_pubkey", HexStr(agg)); + if (!lh.IsNull()) info.pushKV("leaf_hash", HexStr(lh)); + info.pushKV("pubnonce", HexStr(pubnonce)); + musig_pubnonces.push_back(info); + } + } + in.pushKV("musig2_pubnonces", musig_pubnonces); + } + if (!input.m_musig2_partial_sigs.empty()) { + UniValue musig_partial_sigs(UniValue::VARR); + for (const auto& [agg_lh, part_psig] : input.m_musig2_partial_sigs) { + const auto& [agg, lh] = agg_lh; + for (const auto& [part, psig] : part_psig) { + UniValue info(UniValue::VOBJ); + info.pushKV("participant_pubkey", HexStr(part)); + info.pushKV("aggregate_pubkey", HexStr(agg)); + if (!lh.IsNull()) info.pushKV("leaf_hash", HexStr(lh)); + info.pushKV("partial_sig", HexStr(psig)); + musig_partial_sigs.push_back(info); + } + } + in.pushKV("musig2_partial_sigs", musig_partial_sigs); + } + // Proprietary if (!input.m_proprietary.empty()) { UniValue proprietary(UniValue::VARR); @@ -1399,6 +1487,22 @@ static RPCHelpMan decodepsbt() out.pushKV("taproot_bip32_derivs", std::move(keypaths)); } + // Write MuSig2 fields + if (!output.m_musig2_participants.empty()) { + UniValue musig_pubkeys(UniValue::VARR); + for (const auto& [agg, parts] : output.m_musig2_participants) { + UniValue musig_part(UniValue::VOBJ); + musig_part.pushKV("aggregate_pubkey", HexStr(agg)); + UniValue part_pubkeys(UniValue::VARR); + for (const auto& pub : parts) { + part_pubkeys.push_back(HexStr(pub)); + } + musig_part.pushKV("participant_pubkeys", part_pubkeys); + musig_pubkeys.push_back(musig_part); + } + out.pushKV("musig2_participant_pubkeys", musig_pubkeys); + } + // Proprietary if (!output.m_proprietary.empty()) { UniValue proprietary(UniValue::VARR);