From a9218b1de78544b3f2d6dcb92a05b074ec91b1f7 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 6 Oct 2025 21:00:58 +0000 Subject: [PATCH 01/10] rpc: introduce `GetJsonHelp()` to provide help text for Dash RPC objects Currently, the most reliable source of RPC help text is the published documentation. This is fine for releases as the whole set of changes undergo evaluation but a problem for nightlies or documenting behavior changes or deprecations in-source. --- src/evo/core_write.cpp | 113 ++++++++++++++++++++++++++++++++++++- src/evo/providertx.h | 9 ++- src/rpc/rawtransaction.cpp | 14 +++-- 3 files changed, 126 insertions(+), 10 deletions(-) diff --git a/src/evo/core_write.cpp b/src/evo/core_write.cpp index 574910214294..c8a85636a213 100644 --- a/src/evo/core_write.cpp +++ b/src/evo/core_write.cpp @@ -2,9 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include -#include - #include #include #include @@ -15,8 +12,55 @@ #include #include +#include +#include +#include +#include + #include +#include +#include + +namespace { +RPCResult GetRpcResult(const std::string& key, bool optional = false) +{ +#define RESULT_MAP_ENTRY(type, name, desc) {name, {type, name, optional, desc}} + const std::map result_map{{ + {"addresses", + {RPCResult::Type::OBJ, "addresses", optional, "Network addresses of the masternode", + { + {RPCResult::Type::ARR, "core_p2p", /*optional=*/true, "Addresses used for protocol P2P", + {{RPCResult::Type::STR, "address", ""}}}, + {RPCResult::Type::ARR, "platform_p2p", /*optional=*/true, "Addresses used for Platform P2P", + {{RPCResult::Type::STR, "address", ""}}}, + {RPCResult::Type::ARR, "platform_https", /*optional=*/true, "Addresses used for Platform HTTPS API", + {{RPCResult::Type::STR, "address", ""}}}, + }}}, + RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "inputsHash", "Hash of all the outpoints of the transaction inputs"), + RESULT_MAP_ENTRY(RPCResult::Type::STR, "operatorPayoutAddress", "Dash address used for operator reward payments"), + RESULT_MAP_ENTRY(RPCResult::Type::STR, "payoutAddress", "Dash address used for masternode reward payments"), + RESULT_MAP_ENTRY(RPCResult::Type::NUM, "platformHTTPPort", "(DEPRECATED) TCP port of Platform HTTP API"), + RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "platformNodeID", "Node ID derived from P2P public key for Platform P2P"), + RESULT_MAP_ENTRY(RPCResult::Type::NUM, "platformP2PPort", "(DEPRECATED) TCP port of Platform P2P"), + RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "proTxHash", "Hash of the masternode's initial ProRegTx"), + RESULT_MAP_ENTRY(RPCResult::Type::STR, "pubKeyOperator", "BLS public key used for operator signing"), + RESULT_MAP_ENTRY(RPCResult::Type::STR, "service", "(DEPRECATED) IP address and port of the masternode"), + RESULT_MAP_ENTRY(RPCResult::Type::NUM, "type", "Masternode type"), + RESULT_MAP_ENTRY(RPCResult::Type::NUM, "version", "Special transaction version"), + RESULT_MAP_ENTRY(RPCResult::Type::STR, "votingAddress", "Dash address used for voting"), + }}; +#undef RESULT_MAP_ENTRY + + if (const auto it = result_map.find(key); it != result_map.end()) { + return it->second; + } + + throw NonFatalCheckError(strprintf("Requested invalid RPCResult for nonexistent key \"%s\"", key).c_str(), + __FILE__, __LINE__, __func__); +} +} // anonymous namespace + [[nodiscard]] UniValue CAssetLockPayload::ToJson() const { UniValue outputs(UniValue::VARR); @@ -65,6 +109,28 @@ return ret; } +[[nodiscard]] RPCResult CProRegTx::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode registration special transaction", + { + GetRpcResult("version"), + GetRpcResult("type"), + {RPCResult::Type::STR_HEX, "collateralHash", "Collateral transaction hash"}, + {RPCResult::Type::NUM, "collateralIndex", "Collateral transaction output index"}, + GetRpcResult("service"), + GetRpcResult("addresses"), + {RPCResult::Type::STR, "ownerAddress", "Dash address used for payee updates and proposal voting"}, + GetRpcResult("votingAddress"), + GetRpcResult("payoutAddress", /*optional=*/true), + GetRpcResult("pubKeyOperator"), + {RPCResult::Type::NUM, "operatorReward", "Fraction in %% of reward shared with the operator between 0 and 10000"}, + GetRpcResult("platformNodeID", /*optional=*/true), + GetRpcResult("platformP2PPort", /*optional=*/true), + GetRpcResult("platformHTTPPort", /*optional=*/true), + GetRpcResult("inputsHash"), + }}; +} + [[nodiscard]] UniValue CProRegTx::ToJson() const { UniValue ret(UniValue::VOBJ); @@ -90,6 +156,19 @@ return ret; } +[[nodiscard]] RPCResult CProUpRegTx::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode update registrar special transaction", + { + GetRpcResult("version"), + GetRpcResult("proTxHash"), + GetRpcResult("votingAddress"), + GetRpcResult("payoutAddress", /*optional=*/true), + GetRpcResult("pubKeyOperator"), + GetRpcResult("inputsHash"), + }}; +} + [[nodiscard]] UniValue CProUpRegTx::ToJson() const { UniValue ret(UniValue::VOBJ); @@ -104,6 +183,17 @@ return ret; } +[[nodiscard]] RPCResult CProUpRevTx::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode operator revocation special transaction", + { + GetRpcResult("version"), + GetRpcResult("proTxHash"), + {RPCResult::Type::NUM, "reason", "Reason for masternode service revocation"}, + GetRpcResult("inputsHash", /*optional=*/true), + }}; +} + [[nodiscard]] UniValue CProUpRevTx::ToJson() const { UniValue ret(UniValue::VOBJ); @@ -114,6 +204,23 @@ return ret; } +[[nodiscard]] RPCResult CProUpServTx::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode update service special transaction", + { + GetRpcResult("version"), + GetRpcResult("type"), + GetRpcResult("proTxHash"), + GetRpcResult("service"), + GetRpcResult("addresses"), + GetRpcResult("operatorPayoutAddress", /*optional=*/true), + GetRpcResult("platformNodeID", /*optional=*/true), + GetRpcResult("platformP2PPort", /*optional=*/true), + GetRpcResult("platformHTTPPort", /*optional=*/true), + GetRpcResult("inputsHash"), + }}; +} + [[nodiscard]] UniValue CProUpServTx::ToJson() const { UniValue ret(UniValue::VOBJ); diff --git a/src/evo/providertx.h b/src/evo/providertx.h index f2173b20e086..b4a95dd820a6 100644 --- a/src/evo/providertx.h +++ b/src/evo/providertx.h @@ -6,22 +6,23 @@ #define BITCOIN_EVO_PROVIDERTX_H #include +#include #include #include #include #include -#include #include #include #include -#include #include +#include #include class CBlockIndex; class TxValidationState; +struct RPCResult; namespace ProTxVersion { enum : uint16_t { @@ -120,6 +121,7 @@ class CProRegTx std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; bool IsTriviallyValid(gsl::not_null pindexPrev, TxValidationState& state) const; @@ -180,6 +182,7 @@ class CProUpServTx std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; bool IsTriviallyValid(gsl::not_null pindexPrev, TxValidationState& state) const; @@ -226,6 +229,7 @@ class CProUpRegTx std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; bool IsTriviallyValid(gsl::not_null pindexPrev, TxValidationState& state) const; @@ -275,6 +279,7 @@ class CProUpRevTx std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; bool IsTriviallyValid(gsl::not_null pindexPrev, TxValidationState& state) const; diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 48869e1f27df..d0e61b5e8029 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -27,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -46,17 +44,19 @@ #include #include #include -#include #include #include +#include #include -#include #include +#include #include +#include +#include +#include #include -#include #include @@ -168,6 +168,10 @@ static std::vector DecodeTxDoc(const std::string& txid_field_doc) }}, {RPCResult::Type::NUM, "extraPayloadSize", /*optional=*/true, "Size of DIP2 extra payload. Only present if it's a special TX"}, {RPCResult::Type::STR_HEX, "extraPayload", /*optional=*/true, "Hex-encoded DIP2 extra payload data. Only present if it's a special TX"}, + CProRegTx::GetJsonHelp(/*key=*/"proRegTx", /*optional=*/true), + CProUpServTx::GetJsonHelp(/*key=*/"proUpServTx", /*optional=*/true), + CProUpRegTx::GetJsonHelp(/*key=*/"proUpRegTx", /*optional=*/true), + CProUpRevTx::GetJsonHelp(/*key=*/"proUpRevTx", /*optional=*/true), }; } From 9de8c9cc8f95da96d532f01fd6498b4e64423055 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sat, 4 Oct 2025 13:41:31 +0000 Subject: [PATCH 02/10] trivial: add missing headers Header resorting in the previous commit revealed some headers that were transiently included were no longer available, this should resolve that. --- src/rpc/rawtransaction.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index d0e61b5e8029..25b96b60200c 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -46,7 +46,9 @@ #include #include +#include #include +#include #include #include #include From 7219a293417f4d2738ef646811450d71a19fbb1e Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 6 Oct 2025 20:35:19 +0000 Subject: [PATCH 03/10] rpc: `GetJsonHelp()` defs for `CbTx`, `SimplifiedMNList`, final commitm. --- src/evo/cbtx.h | 5 +++ src/evo/core_write.cpp | 76 ++++++++++++++++++++++++++++++++++++++ src/evo/simplifiedmns.h | 9 ++++- src/evo/smldiff.h | 6 ++- src/llmq/commitment.h | 15 ++++---- src/rpc/blockchain.cpp | 8 +--- src/rpc/evo.cpp | 2 +- src/rpc/rawtransaction.cpp | 3 ++ 8 files changed, 105 insertions(+), 19 deletions(-) diff --git a/src/evo/cbtx.h b/src/evo/cbtx.h index 482d880dd522..da6d92f802a8 100644 --- a/src/evo/cbtx.h +++ b/src/evo/cbtx.h @@ -6,16 +6,20 @@ #define BITCOIN_EVO_CBTX_H #include + #include + #include #include +#include class BlockValidationState; class CBlock; class CBlockIndex; class CDeterministicMNList; class TxValidationState; +struct RPCResult; namespace llmq { class CQuorumBlockProcessor; @@ -57,6 +61,7 @@ class CCbTx } + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); std::string ToString() const; [[nodiscard]] UniValue ToJson() const; diff --git a/src/evo/core_write.cpp b/src/evo/core_write.cpp index c8a85636a213..4d2d72af45a0 100644 --- a/src/evo/core_write.cpp +++ b/src/evo/core_write.cpp @@ -37,7 +37,10 @@ RPCResult GetRpcResult(const std::string& key, bool optional = false) {RPCResult::Type::ARR, "platform_https", /*optional=*/true, "Addresses used for Platform HTTPS API", {{RPCResult::Type::STR, "address", ""}}}, }}}, + RESULT_MAP_ENTRY(RPCResult::Type::NUM, "height", "Block height"), RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "inputsHash", "Hash of all the outpoints of the transaction inputs"), + RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "merkleRootMNList", "Merkle root of the masternode list"), + RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "merkleRootQuorums", "Merkle root of the quorum list"), RESULT_MAP_ENTRY(RPCResult::Type::STR, "operatorPayoutAddress", "Dash address used for operator reward payments"), RESULT_MAP_ENTRY(RPCResult::Type::STR, "payoutAddress", "Dash address used for masternode reward payments"), RESULT_MAP_ENTRY(RPCResult::Type::NUM, "platformHTTPPort", "(DEPRECATED) TCP port of Platform HTTP API"), @@ -92,6 +95,20 @@ RPCResult GetRpcResult(const std::string& key, bool optional = false) return ret; } +[[nodiscard]] RPCResult CCbTx::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The coinbase special transaction", + { + GetRpcResult("version"), + GetRpcResult("height"), + GetRpcResult("merkleRootMNList"), + GetRpcResult("merkleRootQuorums", /*optional=*/true), + {RPCResult::Type::NUM, "bestCLHeightDiff", /*optional=*/true, "Blocks between the current block and the last known block with a ChainLock"}, + {RPCResult::Type::STR_HEX, "bestCLSignature", /*optional=*/true, "Best ChainLock signature known by the miner"}, + {RPCResult::Type::NUM, "creditPoolBalance", /*optional=*/true, "Balance in the Platform credit pool"}, + }}; +} + [[nodiscard]] UniValue CCbTx::ToJson() const { UniValue ret(UniValue::VOBJ); @@ -249,6 +266,16 @@ RPCResult GetRpcResult(const std::string& key, bool optional = false) return ret; } +[[nodiscard]] RPCResult llmq::CFinalCommitmentTxPayload::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The quorum commitment special transaction", + { + GetRpcResult("version"), + GetRpcResult("height"), + // TODO: Add RPCResult for llmq::CFinalCommitment + }}; +} + [[nodiscard]] UniValue llmq::CFinalCommitmentTxPayload::ToJson() const { UniValue ret(UniValue::VOBJ); @@ -258,6 +285,26 @@ RPCResult GetRpcResult(const std::string& key, bool optional = false) return ret; } +[[nodiscard]] RPCResult CSimplifiedMNListEntry::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The simplified masternode list entry", + { + {RPCResult::Type::NUM, "nVersion", "Version of the entry"}, + {RPCResult::Type::NUM, "nType", "Masternode type"}, + {RPCResult::Type::STR_HEX, "proRegTxHash", "Hash of the ProRegTx identifying the masternode"}, + {RPCResult::Type::STR_HEX, "confirmedHash", "Hash of the block where the masternode was confirmed"}, + GetRpcResult("service"), + GetRpcResult("addresses"), + GetRpcResult("pubKeyOperator"), + GetRpcResult("votingAddress"), + {RPCResult::Type::BOOL, "isValid", "Returns true if the masternode is not Proof-of-Service banned"}, + GetRpcResult("platformHTTPPort", /*optional=*/true), + GetRpcResult("platformNodeID", /*optional=*/true), + GetRpcResult("payoutAddress", /*optional=*/true), + GetRpcResult("operatorPayoutAddress", /*optional=*/true), + }}; +} + [[nodiscard]] UniValue CSimplifiedMNListEntry::ToJson(bool extended) const { UniValue obj(UniValue::VOBJ); @@ -287,6 +334,35 @@ RPCResult GetRpcResult(const std::string& key, bool optional = false) return obj; } +[[nodiscard]] RPCResult CSimplifiedMNListDiff::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The simplified masternode list diff", + { + {RPCResult::Type::NUM, "nVersion", "Version of the diff"}, + {RPCResult::Type::STR_HEX, "baseBlockHash", "Hash of the base block"}, + {RPCResult::Type::STR_HEX, "blockHash", "Hash of the ending block"}, + {RPCResult::Type::STR_HEX, "cbTxMerkleTree", "Coinbase transaction merkle tree"}, + {RPCResult::Type::STR_HEX, "cbTx", "Coinbase raw transaction"}, + {RPCResult::Type::ARR, "deletedMNs", "ProRegTx hashes of deleted masternodes", + {{RPCResult::Type::STR_HEX, "hash", ""}}}, + {RPCResult::Type::ARR, "mnList", "Masternode list details", + {CSimplifiedMNListEntry::GetJsonHelp(/*key=*/"", /*optional=*/false)}}, + {RPCResult::Type::ARR, "deletedQuorums", "Deleted quorums", + {{RPCResult::Type::OBJ, "", "", { + {RPCResult::Type::NUM, "llmqType", "Quorum type"}, + {RPCResult::Type::STR_HEX, "quorumHash", "Hash of the quorum"}, + }}}}, + {RPCResult::Type::ARR, "newQuorums", "New quorums"}, // TODO: Add definition for llmq::CFinalCommitment + GetRpcResult("merkleRootMNList", /*optional=*/true), + GetRpcResult("merkleRootQuorums", /*optional=*/true), + {RPCResult::Type::ARR, "quorumsCLSigs", "ChainLock signature details", { + {RPCResult::Type::OBJ, "", "", { + {RPCResult::Type::ARR, "", "Array of quorum indices, keyed by BLS signature", { + {RPCResult::Type::NUM, "", "Quorum index"} + }}}}}}, + }}; +} + [[nodiscard]] UniValue CSimplifiedMNListDiff::ToJson(bool extended) const { UniValue obj(UniValue::VOBJ); diff --git a/src/evo/simplifiedmns.h b/src/evo/simplifiedmns.h index 9153d0b025e1..cbc1e9434fe4 100644 --- a/src/evo/simplifiedmns.h +++ b/src/evo/simplifiedmns.h @@ -9,15 +9,19 @@ #include #include #include -#include +#include + #include #include #include -#include + +#include #include #include +struct RPCResult; + class UniValue; class CSimplifiedMNListEntry @@ -95,6 +99,7 @@ class CSimplifiedMNListEntry uint256 CalcHash() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); std::string ToString() const; [[nodiscard]] UniValue ToJson(bool extended = false) const; }; diff --git a/src/evo/smldiff.h b/src/evo/smldiff.h index 5296ddf4941d..0154403d840b 100644 --- a/src/evo/smldiff.h +++ b/src/evo/smldiff.h @@ -5,12 +5,12 @@ #ifndef BITCOIN_EVO_SMLDIFF_H #define BITCOIN_EVO_SMLDIFF_H -#include - #include #include #include #include +#include + #include #include #include @@ -21,6 +21,7 @@ class CBlockIndex; class CDeterministicMNManager; class UniValue; class ChainstateManager; +struct RPCResult; namespace llmq { class CFinalCommitment; @@ -85,6 +86,7 @@ class CSimplifiedMNListDiff const llmq::CQuorumBlockProcessor& quorum_block_processor); bool BuildQuorumChainlockInfo(const llmq::CQuorumManager& qman, const CBlockIndex* blockIndex); + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson(bool extended = false) const; }; diff --git a/src/llmq/commitment.h b/src/llmq/commitment.h index 46d663d55105..69b9507a5e81 100644 --- a/src/llmq/commitment.h +++ b/src/llmq/commitment.h @@ -5,15 +5,15 @@ #ifndef BITCOIN_LLMQ_COMMITMENT_H #define BITCOIN_LLMQ_COMMITMENT_H -#include -#include -#include - #include #include #include #include +#include +#include +#include + #include #include @@ -29,14 +29,14 @@ class ChainstateManager; class TxValidationState; template class CCheckQueueControl; +struct RPCResult; -namespace llmq -{ +namespace llmq { class CQuorumSnapshotManager; - namespace utils { struct BlsCheck; } // namespace utils + // This message is an aggregation of all received premature commitments and only valid if // enough (>=threshold) premature commitments were aggregated // This is mined on-chain as part of TRANSACTION_QUORUM_COMMITMENT @@ -175,6 +175,7 @@ class CFinalCommitmentTxPayload READWRITE(obj.nVersion, obj.nHeight, obj.commitment); } + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; }; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 89b4ae290df7..4ca4f63ef1a2 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -922,13 +922,7 @@ static RPCHelpMan getblock() {RPCResult::Type::NUM, "size", "The block size"}, {RPCResult::Type::ARR, "tx", "The transaction ids", {{RPCResult::Type::STR_HEX, "", "The transaction id"}}}, - {RPCResult::Type::OBJ, "cbTx", "The coinbase special transaction", - { - {RPCResult::Type::NUM, "version", "The coinbase special transaction version"}, - {RPCResult::Type::NUM, "height", "The block height"}, - {RPCResult::Type::STR_HEX, "merkleRootMNList", "The merkle root of the masternode list"}, - {RPCResult::Type::STR_HEX, "merkleRootQuorums", "The merkle root of the quorum list"}, - }}, + CCbTx::GetJsonHelp(/*key=*/"cbTx", /*optional=*/true), }}, RPCResult{"for verbosity = 2", RPCResult::Type::OBJ, "", "", diff --git a/src/rpc/evo.cpp b/src/rpc/evo.cpp index cc7052b453c3..9907f19153f8 100644 --- a/src/rpc/evo.cpp +++ b/src/rpc/evo.cpp @@ -1586,7 +1586,7 @@ static RPCHelpMan protx_diff() {"block", RPCArg::Type::NUM, RPCArg::Optional::NO, "The ending block height."}, {"extended", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Show additional fields."}, }, - RPCResults{}, + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"", /*optional=*/false), RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 25b96b60200c..81d031525939 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -174,6 +175,8 @@ static std::vector DecodeTxDoc(const std::string& txid_field_doc) CProUpServTx::GetJsonHelp(/*key=*/"proUpServTx", /*optional=*/true), CProUpRegTx::GetJsonHelp(/*key=*/"proUpRegTx", /*optional=*/true), CProUpRevTx::GetJsonHelp(/*key=*/"proUpRevTx", /*optional=*/true), + CCbTx::GetJsonHelp(/*key=*/"cbTx", /*optional=*/true), + llmq::CFinalCommitmentTxPayload::GetJsonHelp(/*key=*/"qcTx", /*optional=*/true), }; } From 73da03e241f6412eed6dab575d70dd27e7bb3643 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sat, 4 Oct 2025 16:12:33 +0000 Subject: [PATCH 04/10] refactor: move LLMQ-specific `ToJson()` definitions to separate file Keeping true to separation of concerns --- src/Makefile.am | 1 + src/core_io.h | 14 +++-- src/evo/core_write.cpp | 23 +------- src/llmq/commitment.h | 18 +----- src/llmq/core_write.cpp | 127 ++++++++++++++++++++++++++++++++++++++++ src/llmq/signing.cpp | 13 ---- src/llmq/signing.h | 2 +- src/llmq/snapshot.cpp | 61 ------------------- 8 files changed, 140 insertions(+), 119 deletions(-) create mode 100644 src/llmq/core_write.cpp diff --git a/src/Makefile.am b/src/Makefile.am index d6386416c7ef..9ad66b87a276 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -906,6 +906,7 @@ libbitcoin_common_a_SOURCES = \ init/common.cpp \ key.cpp \ key_io.cpp \ + llmq/core_write.cpp \ merkleblock.cpp \ net_types.cpp \ netaddress.cpp \ diff --git a/src/core_io.h b/src/core_io.h index 00cec54e27e7..d3f424d1363f 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -5,8 +5,8 @@ #ifndef BITCOIN_CORE_IO_H #define BITCOIN_CORE_IO_H -#include #include +#include #include #include @@ -15,12 +15,13 @@ class CBlock; class CBlockHeader; class CScript; class CTransaction; -struct CMutableTransaction; -class uint256; -class UniValue; class CTxUndo; - +class uint256; +struct CMutableTransaction; struct CSpentIndexTxInfo; +struct RPCResult; + +class UniValue; /** * Verbose level for block's transaction @@ -57,4 +58,7 @@ std::string SighashToStr(unsigned char sighash_type); void ScriptToUniv(const CScript& script, UniValue& out, bool include_hex = true, bool include_address = false); void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr, TxVerbosity verbosity = TxVerbosity::SHOW_DETAILS, const CSpentIndexTxInfo* ptxSpentInfo = nullptr); +// evo/core_write.cpp +RPCResult GetRpcResult(const std::string& key, bool optional = false); + #endif // BITCOIN_CORE_IO_H diff --git a/src/evo/core_write.cpp b/src/evo/core_write.cpp index 4d2d72af45a0..1cccced0fd9b 100644 --- a/src/evo/core_write.cpp +++ b/src/evo/core_write.cpp @@ -22,8 +22,7 @@ #include #include -namespace { -RPCResult GetRpcResult(const std::string& key, bool optional = false) +RPCResult GetRpcResult(const std::string& key, bool optional) { #define RESULT_MAP_ENTRY(type, name, desc) {name, {type, name, optional, desc}} const std::map result_map{{ @@ -62,7 +61,6 @@ RPCResult GetRpcResult(const std::string& key, bool optional = false) throw NonFatalCheckError(strprintf("Requested invalid RPCResult for nonexistent key \"%s\"", key).c_str(), __FILE__, __LINE__, __func__); } -} // anonymous namespace [[nodiscard]] UniValue CAssetLockPayload::ToJson() const { @@ -266,25 +264,6 @@ RPCResult GetRpcResult(const std::string& key, bool optional = false) return ret; } -[[nodiscard]] RPCResult llmq::CFinalCommitmentTxPayload::GetJsonHelp(const std::string& key, bool optional) -{ - return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The quorum commitment special transaction", - { - GetRpcResult("version"), - GetRpcResult("height"), - // TODO: Add RPCResult for llmq::CFinalCommitment - }}; -} - -[[nodiscard]] UniValue llmq::CFinalCommitmentTxPayload::ToJson() const -{ - UniValue ret(UniValue::VOBJ); - ret.pushKV("version", nVersion); - ret.pushKV("height", nHeight); - ret.pushKV("commitment", commitment.ToJson()); - return ret; -} - [[nodiscard]] RPCResult CSimplifiedMNListEntry::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The simplified masternode list entry", diff --git a/src/llmq/commitment.h b/src/llmq/commitment.h index 69b9507a5e81..54b96c19bc96 100644 --- a/src/llmq/commitment.h +++ b/src/llmq/commitment.h @@ -130,23 +130,7 @@ class CFinalCommitment return true; } - [[nodiscard]] UniValue ToJson() const - { - UniValue obj(UniValue::VOBJ); - obj.pushKV("version", nVersion); - obj.pushKV("llmqType", ToUnderlying(llmqType)); - obj.pushKV("quorumHash", quorumHash.ToString()); - obj.pushKV("quorumIndex", quorumIndex); - obj.pushKV("signersCount", CountSigners()); - obj.pushKV("signers", BitsVectorToHexStr(signers)); - obj.pushKV("validMembersCount", CountValidMembers()); - obj.pushKV("validMembers", BitsVectorToHexStr(validMembers)); - obj.pushKV("quorumPublicKey", quorumPublicKey.ToString(nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION)); - obj.pushKV("quorumVvecHash", quorumVvecHash.ToString()); - obj.pushKV("quorumSig", quorumSig.ToString(nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION)); - obj.pushKV("membersSig", membersSig.ToString(nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION)); - return obj; - } + [[nodiscard]] UniValue ToJson() const; private: static std::string BitsVectorToHexStr(const std::vector& vBits) diff --git a/src/llmq/core_write.cpp b/src/llmq/core_write.cpp new file mode 100644 index 000000000000..47b92e1d9daa --- /dev/null +++ b/src/llmq/core_write.cpp @@ -0,0 +1,127 @@ +// Copyright (c) 2018-2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +namespace llmq { +[[nodiscard]] UniValue CFinalCommitment::ToJson() const +{ + UniValue obj(UniValue::VOBJ); + obj.pushKV("version", nVersion); + obj.pushKV("llmqType", ToUnderlying(llmqType)); + obj.pushKV("quorumHash", quorumHash.ToString()); + obj.pushKV("quorumIndex", quorumIndex); + obj.pushKV("signersCount", CountSigners()); + obj.pushKV("signers", BitsVectorToHexStr(signers)); + obj.pushKV("validMembersCount", CountValidMembers()); + obj.pushKV("validMembers", BitsVectorToHexStr(validMembers)); + obj.pushKV("quorumPublicKey", quorumPublicKey.ToString(nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION)); + obj.pushKV("quorumVvecHash", quorumVvecHash.ToString()); + obj.pushKV("quorumSig", quorumSig.ToString(nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION)); + obj.pushKV("membersSig", membersSig.ToString(nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION)); + return obj; +} + +[[nodiscard]] RPCResult CFinalCommitmentTxPayload::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The quorum commitment special transaction", + { + GetRpcResult("version"), + GetRpcResult("height"), + // TODO: Add RPCResult for llmq::CFinalCommitment + }}; +} + +[[nodiscard]] UniValue CFinalCommitmentTxPayload::ToJson() const +{ + UniValue ret(UniValue::VOBJ); + ret.pushKV("version", nVersion); + ret.pushKV("height", nHeight); + ret.pushKV("commitment", commitment.ToJson()); + return ret; +} + +[[nodiscard]] UniValue CQuorumRotationInfo::ToJson() const +{ + UniValue obj(UniValue::VOBJ); + obj.pushKV("extraShare", extraShare); + + obj.pushKV("quorumSnapshotAtHMinusC", quorumSnapshotAtHMinusC.ToJson()); + obj.pushKV("quorumSnapshotAtHMinus2C", quorumSnapshotAtHMinus2C.ToJson()); + obj.pushKV("quorumSnapshotAtHMinus3C", quorumSnapshotAtHMinus3C.ToJson()); + + if (extraShare) { + obj.pushKV("quorumSnapshotAtHMinus4C", quorumSnapshotAtHMinus4C.ToJson()); + } + + obj.pushKV("mnListDiffTip", mnListDiffTip.ToJson()); + obj.pushKV("mnListDiffH", mnListDiffH.ToJson()); + obj.pushKV("mnListDiffAtHMinusC", mnListDiffAtHMinusC.ToJson()); + obj.pushKV("mnListDiffAtHMinus2C", mnListDiffAtHMinus2C.ToJson()); + obj.pushKV("mnListDiffAtHMinus3C", mnListDiffAtHMinus3C.ToJson()); + + if (extraShare) { + obj.pushKV("mnListDiffAtHMinus4C", mnListDiffAtHMinus4C.ToJson()); + } + UniValue hqclists(UniValue::VARR); + for (const auto& qc : lastCommitmentPerIndex) { + hqclists.push_back(qc.ToJson()); + } + obj.pushKV("lastCommitmentPerIndex", hqclists); + + UniValue snapshotlist(UniValue::VARR); + for (const auto& snap : quorumSnapshotList) { + snapshotlist.push_back(snap.ToJson()); + } + obj.pushKV("quorumSnapshotList", snapshotlist); + + UniValue mnlistdifflist(UniValue::VARR); + for (const auto& mnlist : mnListDiffList) { + mnlistdifflist.push_back(mnlist.ToJson()); + } + obj.pushKV("mnListDiffList", mnlistdifflist); + return obj; +} + +[[nodiscard]] UniValue CQuorumSnapshot::ToJson() const +{ + UniValue obj(UniValue::VOBJ); + UniValue activeQ(UniValue::VARR); + for (const bool h : activeQuorumMembers) { + // cppcheck-suppress useStlAlgorithm + activeQ.push_back(h); + } + obj.pushKV("activeQuorumMembers", activeQ); + obj.pushKV("mnSkipListMode", mnSkipListMode); + UniValue skipList(UniValue::VARR); + for (const auto& h : mnSkipList) { + // cppcheck-suppress useStlAlgorithm + skipList.push_back(h); + } + obj.pushKV("mnSkipList", skipList); + return obj; +} + +[[nodiscard]] UniValue CRecoveredSig::ToJson() const +{ + UniValue ret(UniValue::VOBJ); + ret.pushKV("llmqType", ToUnderlying(llmqType)); + ret.pushKV("quorumHash", quorumHash.ToString()); + ret.pushKV("id", id.ToString()); + ret.pushKV("msgHash", msgHash.ToString()); + ret.pushKV("sig", sig.Get().ToString()); + ret.pushKV("hash", sig.Get().GetHash().ToString()); + return ret; +} +} // namespace llmq diff --git a/src/llmq/signing.cpp b/src/llmq/signing.cpp index f66effa2d02d..55c0ab19db25 100644 --- a/src/llmq/signing.cpp +++ b/src/llmq/signing.cpp @@ -27,19 +27,6 @@ namespace llmq { -UniValue CRecoveredSig::ToJson() const -{ - UniValue ret(UniValue::VOBJ); - ret.pushKV("llmqType", ToUnderlying(llmqType)); - ret.pushKV("quorumHash", quorumHash.ToString()); - ret.pushKV("id", id.ToString()); - ret.pushKV("msgHash", msgHash.ToString()); - ret.pushKV("sig", sig.Get().ToString()); - ret.pushKV("hash", sig.Get().GetHash().ToString()); - return ret; -} - - CRecoveredSigsDb::CRecoveredSigsDb(bool fMemory, bool fWipe) : db(std::make_unique(fMemory ? "" : (gArgs.GetDataDirNet() / "llmq/recsigdb"), 8 << 20, fMemory, fWipe)) { diff --git a/src/llmq/signing.h b/src/llmq/signing.h index b835079d5b19..1097240c590e 100644 --- a/src/llmq/signing.h +++ b/src/llmq/signing.h @@ -106,7 +106,7 @@ class CRecoveredSig : virtual public CSigBase return hash; } - UniValue ToJson() const; + [[nodiscard]] UniValue ToJson() const; }; class CRecoveredSigsDb diff --git a/src/llmq/snapshot.cpp b/src/llmq/snapshot.cpp index 3544177dc575..3e6ccd6955b5 100644 --- a/src/llmq/snapshot.cpp +++ b/src/llmq/snapshot.cpp @@ -17,67 +17,6 @@ namespace llmq { static const std::string DB_QUORUM_SNAPSHOT = "llmq_S"; -UniValue CQuorumSnapshot::ToJson() const -{ - UniValue obj(UniValue::VOBJ); - UniValue activeQ(UniValue::VARR); - for (const bool h : activeQuorumMembers) { - // cppcheck-suppress useStlAlgorithm - activeQ.push_back(h); - } - obj.pushKV("activeQuorumMembers", activeQ); - obj.pushKV("mnSkipListMode", mnSkipListMode); - UniValue skipList(UniValue::VARR); - for (const auto& h : mnSkipList) { - // cppcheck-suppress useStlAlgorithm - skipList.push_back(h); - } - obj.pushKV("mnSkipList", skipList); - return obj; -} - -UniValue CQuorumRotationInfo::ToJson() const -{ - UniValue obj(UniValue::VOBJ); - obj.pushKV("extraShare", extraShare); - - obj.pushKV("quorumSnapshotAtHMinusC", quorumSnapshotAtHMinusC.ToJson()); - obj.pushKV("quorumSnapshotAtHMinus2C", quorumSnapshotAtHMinus2C.ToJson()); - obj.pushKV("quorumSnapshotAtHMinus3C", quorumSnapshotAtHMinus3C.ToJson()); - - if (extraShare) { - obj.pushKV("quorumSnapshotAtHMinus4C", quorumSnapshotAtHMinus4C.ToJson()); - } - - obj.pushKV("mnListDiffTip", mnListDiffTip.ToJson()); - obj.pushKV("mnListDiffH", mnListDiffH.ToJson()); - obj.pushKV("mnListDiffAtHMinusC", mnListDiffAtHMinusC.ToJson()); - obj.pushKV("mnListDiffAtHMinus2C", mnListDiffAtHMinus2C.ToJson()); - obj.pushKV("mnListDiffAtHMinus3C", mnListDiffAtHMinus3C.ToJson()); - - if (extraShare) { - obj.pushKV("mnListDiffAtHMinus4C", mnListDiffAtHMinus4C.ToJson()); - } - UniValue hqclists(UniValue::VARR); - for (const auto& qc : lastCommitmentPerIndex) { - hqclists.push_back(qc.ToJson()); - } - obj.pushKV("lastCommitmentPerIndex", hqclists); - - UniValue snapshotlist(UniValue::VARR); - for (const auto& snap : quorumSnapshotList) { - snapshotlist.push_back(snap.ToJson()); - } - obj.pushKV("quorumSnapshotList", snapshotlist); - - UniValue mnlistdifflist(UniValue::VARR); - for (const auto& mnlist : mnListDiffList) { - mnlistdifflist.push_back(mnlist.ToJson()); - } - obj.pushKV("mnListDiffList", mnlistdifflist); - return obj; -} - bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, const CQuorumManager& qman, const CQuorumBlockProcessor& qblockman, const CGetQuorumRotationInfo& request, From ddc698bd3df670d6245d80d2bac353e216e431ce Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 5 Oct 2025 12:08:56 +0000 Subject: [PATCH 05/10] refactor: move pending `evo/`-specific definitions to `core_write.cpp` We exclude the following: - `evo/netinfo.{cpp,h}` (already a part of `libbitcoin_common`) as it as an inheritance structure and the help text for it is relatively uncomplicated. - `CDeterministicMN::ToJson() `and `CDeterministicMNStateDiff::ToJson()` as it relies on `g_txindex` that is part of `libbitcoin_node` so it cannot be part of `evo/core_write.cpp`. --- src/evo/core_write.cpp | 156 ++++++++++++++++++++++++++--------------- src/evo/dmnstate.cpp | 32 --------- src/evo/mnhftx.h | 9 +-- 3 files changed, 100 insertions(+), 97 deletions(-) diff --git a/src/evo/core_write.cpp b/src/evo/core_write.cpp index 1cccced0fd9b..673ddf70e32b 100644 --- a/src/evo/core_write.cpp +++ b/src/evo/core_write.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -124,6 +125,38 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return ret; } +[[nodiscard]] UniValue CDeterministicMNState::ToJson(MnType nType) const +{ + UniValue obj(UniValue::VOBJ); + obj.pushKV("version", nVersion); + obj.pushKV("service", netInfo->GetPrimary().ToStringAddrPort()); + obj.pushKV("addresses", GetNetInfoWithLegacyFields(*this, nType)); + obj.pushKV("registeredHeight", nRegisteredHeight); + obj.pushKV("lastPaidHeight", nLastPaidHeight); + obj.pushKV("consecutivePayments", nConsecutivePayments); + obj.pushKV("PoSePenalty", nPoSePenalty); + obj.pushKV("PoSeRevivedHeight", nPoSeRevivedHeight); + obj.pushKV("PoSeBanHeight", nPoSeBanHeight); + obj.pushKV("revocationReason", nRevocationReason); + obj.pushKV("ownerAddress", EncodeDestination(PKHash(keyIDOwner))); + obj.pushKV("votingAddress", EncodeDestination(PKHash(keyIDVoting))); + if (nType == MnType::Evo) { + obj.pushKV("platformNodeID", platformNodeID.ToString()); + obj.pushKV("platformP2PPort", GetPlatformPort(*this)); + obj.pushKV("platformHTTPPort", GetPlatformPort(*this)); + } + + CTxDestination dest; + if (ExtractDestination(scriptPayout, dest)) { + obj.pushKV("payoutAddress", EncodeDestination(dest)); + } + obj.pushKV("pubKeyOperator", pubKeyOperator.ToString()); + if (ExtractDestination(scriptOperatorPayout, dest)) { + obj.pushKV("operatorPayoutAddress", EncodeDestination(dest)); + } + return obj; +} + [[nodiscard]] RPCResult CProRegTx::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode registration special transaction", @@ -256,63 +289,6 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return ret; } -[[nodiscard]] UniValue MNHFTxPayload::ToJson() const -{ - UniValue ret(UniValue::VOBJ); - ret.pushKV("version", nVersion); - ret.pushKV("signal", signal.ToJson()); - return ret; -} - -[[nodiscard]] RPCResult CSimplifiedMNListEntry::GetJsonHelp(const std::string& key, bool optional) -{ - return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The simplified masternode list entry", - { - {RPCResult::Type::NUM, "nVersion", "Version of the entry"}, - {RPCResult::Type::NUM, "nType", "Masternode type"}, - {RPCResult::Type::STR_HEX, "proRegTxHash", "Hash of the ProRegTx identifying the masternode"}, - {RPCResult::Type::STR_HEX, "confirmedHash", "Hash of the block where the masternode was confirmed"}, - GetRpcResult("service"), - GetRpcResult("addresses"), - GetRpcResult("pubKeyOperator"), - GetRpcResult("votingAddress"), - {RPCResult::Type::BOOL, "isValid", "Returns true if the masternode is not Proof-of-Service banned"}, - GetRpcResult("platformHTTPPort", /*optional=*/true), - GetRpcResult("platformNodeID", /*optional=*/true), - GetRpcResult("payoutAddress", /*optional=*/true), - GetRpcResult("operatorPayoutAddress", /*optional=*/true), - }}; -} - -[[nodiscard]] UniValue CSimplifiedMNListEntry::ToJson(bool extended) const -{ - UniValue obj(UniValue::VOBJ); - obj.pushKV("nVersion", nVersion); - obj.pushKV("nType", ToUnderlying(nType)); - obj.pushKV("proRegTxHash", proRegTxHash.ToString()); - obj.pushKV("confirmedHash", confirmedHash.ToString()); - obj.pushKV("service", netInfo->GetPrimary().ToStringAddrPort()); - obj.pushKV("addresses", GetNetInfoWithLegacyFields(*this, nType)); - obj.pushKV("pubKeyOperator", pubKeyOperator.ToString()); - obj.pushKV("votingAddress", EncodeDestination(PKHash(keyIDVoting))); - obj.pushKV("isValid", isValid); - if (nType == MnType::Evo) { - obj.pushKV("platformHTTPPort", GetPlatformPort(*this)); - obj.pushKV("platformNodeID", platformNodeID.ToString()); - } - - if (extended) { - CTxDestination dest; - if (ExtractDestination(scriptPayout, dest)) { - obj.pushKV("payoutAddress", EncodeDestination(dest)); - } - if (ExtractDestination(scriptOperatorPayout, dest)) { - obj.pushKV("operatorPayoutAddress", EncodeDestination(dest)); - } - } - return obj; -} - [[nodiscard]] RPCResult CSimplifiedMNListDiff::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The simplified masternode list diff", @@ -404,3 +380,69 @@ RPCResult GetRpcResult(const std::string& key, bool optional) obj.pushKV("quorumsCLSigs", quorumsCLSigsArr); return obj; } + +[[nodiscard]] RPCResult CSimplifiedMNListEntry::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The simplified masternode list entry", + { + {RPCResult::Type::NUM, "nVersion", "Version of the entry"}, + {RPCResult::Type::NUM, "nType", "Masternode type"}, + {RPCResult::Type::STR_HEX, "proRegTxHash", "Hash of the ProRegTx identifying the masternode"}, + {RPCResult::Type::STR_HEX, "confirmedHash", "Hash of the block where the masternode was confirmed"}, + GetRpcResult("service"), + GetRpcResult("addresses"), + GetRpcResult("pubKeyOperator"), + GetRpcResult("votingAddress"), + {RPCResult::Type::BOOL, "isValid", "Returns true if the masternode is not Proof-of-Service banned"}, + GetRpcResult("platformHTTPPort", /*optional=*/true), + GetRpcResult("platformNodeID", /*optional=*/true), + GetRpcResult("payoutAddress", /*optional=*/true), + GetRpcResult("operatorPayoutAddress", /*optional=*/true), + }}; +} + +[[nodiscard]] UniValue CSimplifiedMNListEntry::ToJson(bool extended) const +{ + UniValue obj(UniValue::VOBJ); + obj.pushKV("nVersion", nVersion); + obj.pushKV("nType", ToUnderlying(nType)); + obj.pushKV("proRegTxHash", proRegTxHash.ToString()); + obj.pushKV("confirmedHash", confirmedHash.ToString()); + obj.pushKV("service", netInfo->GetPrimary().ToStringAddrPort()); + obj.pushKV("addresses", GetNetInfoWithLegacyFields(*this, nType)); + obj.pushKV("pubKeyOperator", pubKeyOperator.ToString()); + obj.pushKV("votingAddress", EncodeDestination(PKHash(keyIDVoting))); + obj.pushKV("isValid", isValid); + if (nType == MnType::Evo) { + obj.pushKV("platformHTTPPort", GetPlatformPort(*this)); + obj.pushKV("platformNodeID", platformNodeID.ToString()); + } + + if (extended) { + CTxDestination dest; + if (ExtractDestination(scriptPayout, dest)) { + obj.pushKV("payoutAddress", EncodeDestination(dest)); + } + if (ExtractDestination(scriptOperatorPayout, dest)) { + obj.pushKV("operatorPayoutAddress", EncodeDestination(dest)); + } + } + return obj; +} + +[[nodiscard]] UniValue MNHFTx::ToJson() const +{ + UniValue obj(UniValue::VOBJ); + obj.pushKV("versionBit", versionBit); + obj.pushKV("quorumHash", quorumHash.ToString()); + obj.pushKV("sig", sig.ToString()); + return obj; +} + +[[nodiscard]] UniValue MNHFTxPayload::ToJson() const +{ + UniValue ret(UniValue::VOBJ); + ret.pushKV("version", nVersion); + ret.pushKV("signal", signal.ToJson()); + return ret; +} diff --git a/src/evo/dmnstate.cpp b/src/evo/dmnstate.cpp index c9d9a9e71948..54d463db3d13 100644 --- a/src/evo/dmnstate.cpp +++ b/src/evo/dmnstate.cpp @@ -32,38 +32,6 @@ std::string CDeterministicMNState::ToString() const EncodeDestination(PKHash(keyIDVoting)), netInfo->ToString(), payoutAddress, operatorPayoutAddress); } -UniValue CDeterministicMNState::ToJson(MnType nType) const -{ - UniValue obj(UniValue::VOBJ); - obj.pushKV("version", nVersion); - obj.pushKV("service", netInfo->GetPrimary().ToStringAddrPort()); - obj.pushKV("addresses", GetNetInfoWithLegacyFields(*this, nType)); - obj.pushKV("registeredHeight", nRegisteredHeight); - obj.pushKV("lastPaidHeight", nLastPaidHeight); - obj.pushKV("consecutivePayments", nConsecutivePayments); - obj.pushKV("PoSePenalty", nPoSePenalty); - obj.pushKV("PoSeRevivedHeight", nPoSeRevivedHeight); - obj.pushKV("PoSeBanHeight", nPoSeBanHeight); - obj.pushKV("revocationReason", nRevocationReason); - obj.pushKV("ownerAddress", EncodeDestination(PKHash(keyIDOwner))); - obj.pushKV("votingAddress", EncodeDestination(PKHash(keyIDVoting))); - if (nType == MnType::Evo) { - obj.pushKV("platformNodeID", platformNodeID.ToString()); - obj.pushKV("platformP2PPort", GetPlatformPort(*this)); - obj.pushKV("platformHTTPPort", GetPlatformPort(*this)); - } - - CTxDestination dest; - if (ExtractDestination(scriptPayout, dest)) { - obj.pushKV("payoutAddress", EncodeDestination(dest)); - } - obj.pushKV("pubKeyOperator", pubKeyOperator.ToString()); - if (ExtractDestination(scriptOperatorPayout, dest)) { - obj.pushKV("operatorPayoutAddress", EncodeDestination(dest)); - } - return obj; -} - UniValue CDeterministicMNStateDiff::ToJson(MnType nType) const { UniValue obj(UniValue::VOBJ); diff --git a/src/evo/mnhftx.h b/src/evo/mnhftx.h index 8adda3655368..f3d995be652d 100644 --- a/src/evo/mnhftx.h +++ b/src/evo/mnhftx.h @@ -50,14 +50,7 @@ class MNHFTx std::string ToString() const; - [[nodiscard]] UniValue ToJson() const - { - UniValue obj(UniValue::VOBJ); - obj.pushKV("versionBit", versionBit); - obj.pushKV("quorumHash", quorumHash.ToString()); - obj.pushKV("sig", sig.ToString()); - return obj; - } + [[nodiscard]] UniValue ToJson() const; }; class MNHFTxPayload From ae4e05c14792cb90be1c2f7ea978d4eb131107e4 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 6 Oct 2025 20:24:20 +0000 Subject: [PATCH 06/10] rpc: `GetJsonHelp()` defs for `MNHFTx`, `CAsset{Un,}lock` --- src/evo/assetlocktx.h | 3 +++ src/evo/core_write.cpp | 52 +++++++++++++++++++++++++++++++++++++- src/evo/mnhftx.h | 3 +++ src/rpc/rawtransaction.cpp | 4 +++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/evo/assetlocktx.h b/src/evo/assetlocktx.h index 2fc44643fa8f..433dd098ee47 100644 --- a/src/evo/assetlocktx.h +++ b/src/evo/assetlocktx.h @@ -17,6 +17,7 @@ class CBlockIndex; class CRangesSet; class TxValidationState; +struct RPCResult; namespace llmq { class CQuorumManager; } // namespace llmq @@ -51,6 +52,7 @@ class CAssetLockPayload std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; // getters @@ -108,6 +110,7 @@ class CAssetUnlockPayload std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; bool VerifySig(const llmq::CQuorumManager& qman, const uint256& msgHash, gsl::not_null pindexTip, TxValidationState& state) const; diff --git a/src/evo/core_write.cpp b/src/evo/core_write.cpp index 673ddf70e32b..1524d24a143f 100644 --- a/src/evo/core_write.cpp +++ b/src/evo/core_write.cpp @@ -48,6 +48,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) RESULT_MAP_ENTRY(RPCResult::Type::NUM, "platformP2PPort", "(DEPRECATED) TCP port of Platform P2P"), RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "proTxHash", "Hash of the masternode's initial ProRegTx"), RESULT_MAP_ENTRY(RPCResult::Type::STR, "pubKeyOperator", "BLS public key used for operator signing"), + RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "quorumHash", "Hash of the quorum"), RESULT_MAP_ENTRY(RPCResult::Type::STR, "service", "(DEPRECATED) IP address and port of the masternode"), RESULT_MAP_ENTRY(RPCResult::Type::NUM, "type", "Masternode type"), RESULT_MAP_ENTRY(RPCResult::Type::NUM, "version", "Special transaction version"), @@ -63,6 +64,23 @@ RPCResult GetRpcResult(const std::string& key, bool optional) __FILE__, __LINE__, __func__); } +[[nodiscard]] RPCResult CAssetLockPayload::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The asset lock special transaction", + { + GetRpcResult("version"), + {RPCResult::Type::ARR, "creditOutputs", "", { + {RPCResult::Type::OBJ, "", "", { + {RPCResult::Type::NUM, "value", "The value in Dash"}, + {RPCResult::Type::NUM, "valueSat", "The value in duffs"}, + {RPCResult::Type::OBJ, "scriptPubKey", "", { + {RPCResult::Type::STR, "asm", "The asm"}, + {RPCResult::Type::STR_HEX, "hex", "The hex"}, + {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, + }}}}}} + }}; +} + [[nodiscard]] UniValue CAssetLockPayload::ToJson() const { UniValue outputs(UniValue::VARR); @@ -82,6 +100,19 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return ret; } +[[nodiscard]] RPCResult CAssetUnlockPayload::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The asset unlock special transaction", + { + GetRpcResult("version"), + {RPCResult::Type::NUM, "index", "Index of the transaction"}, + {RPCResult::Type::NUM, "fee", "Transaction fee in duffs awarded to the miner"}, + {RPCResult::Type::NUM, "requestedHeight", "Payment chain block height known by Platform when signing the withdrawal"}, + GetRpcResult("quorumHash"), + {RPCResult::Type::STR_HEX, "quorumSig", "BLS signature by a quorum public key"}, + }}; +} + [[nodiscard]] UniValue CAssetUnlockPayload::ToJson() const { UniValue ret(UniValue::VOBJ); @@ -305,7 +336,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) {RPCResult::Type::ARR, "deletedQuorums", "Deleted quorums", {{RPCResult::Type::OBJ, "", "", { {RPCResult::Type::NUM, "llmqType", "Quorum type"}, - {RPCResult::Type::STR_HEX, "quorumHash", "Hash of the quorum"}, + GetRpcResult("quorumHash"), }}}}, {RPCResult::Type::ARR, "newQuorums", "New quorums"}, // TODO: Add definition for llmq::CFinalCommitment GetRpcResult("merkleRootMNList", /*optional=*/true), @@ -430,6 +461,16 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return obj; } +[[nodiscard]] RPCResult MNHFTx::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode hard fork payload", + { + {RPCResult::Type::NUM, "versionBit", "Version bit associated with the hard fork"}, + GetRpcResult("quorumHash"), + {RPCResult::Type::STR_HEX, "sig", "BLS signature by a quorum public key"}, + }}; +} + [[nodiscard]] UniValue MNHFTx::ToJson() const { UniValue obj(UniValue::VOBJ); @@ -439,6 +480,15 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return obj; } +[[nodiscard]] RPCResult MNHFTxPayload::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode hard fork signal special transaction", + { + GetRpcResult("version"), + MNHFTx::GetJsonHelp(/*key=*/"signal", /*optional=*/false), + }}; +} + [[nodiscard]] UniValue MNHFTxPayload::ToJson() const { UniValue ret(UniValue::VOBJ); diff --git a/src/evo/mnhftx.h b/src/evo/mnhftx.h index f3d995be652d..855607b21698 100644 --- a/src/evo/mnhftx.h +++ b/src/evo/mnhftx.h @@ -26,6 +26,7 @@ class CEvoDB; class CTransaction; class ChainstateManager; class TxValidationState; +struct RPCResult; namespace llmq { class CQuorumManager; } @@ -50,6 +51,7 @@ class MNHFTx std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; }; @@ -80,6 +82,7 @@ class MNHFTxPayload std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; }; diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 81d031525939..77de92f39f67 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -177,6 +178,9 @@ static std::vector DecodeTxDoc(const std::string& txid_field_doc) CProUpRevTx::GetJsonHelp(/*key=*/"proUpRevTx", /*optional=*/true), CCbTx::GetJsonHelp(/*key=*/"cbTx", /*optional=*/true), llmq::CFinalCommitmentTxPayload::GetJsonHelp(/*key=*/"qcTx", /*optional=*/true), + MNHFTxPayload::GetJsonHelp(/*key=*/"mnhfTx", /*optional=*/true), + CAssetLockPayload::GetJsonHelp(/*key=*/"assetLockTx", /*optional=*/true), + CAssetUnlockPayload::GetJsonHelp(/*key=*/"assetUnlockTx", /*optional=*/true), }; } From 1be22261cc06dd46d3549c40c863615f5fa47ad7 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:52:22 +0000 Subject: [PATCH 07/10] rpc: `GetJsonHelp()` defs for `Quorum{Rotation,Snapshot}`,`RecoveredSig` --- src/evo/core_write.cpp | 9 +++-- src/llmq/commitment.h | 1 + src/llmq/core_write.cpp | 75 ++++++++++++++++++++++++++++++++++++++++- src/llmq/signing.h | 3 ++ src/llmq/snapshot.h | 4 +++ src/rpc/quorums.cpp | 5 +-- 6 files changed, 91 insertions(+), 6 deletions(-) diff --git a/src/evo/core_write.cpp b/src/evo/core_write.cpp index 1524d24a143f..63a988f2ec32 100644 --- a/src/evo/core_write.cpp +++ b/src/evo/core_write.cpp @@ -39,6 +39,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) }}}, RESULT_MAP_ENTRY(RPCResult::Type::NUM, "height", "Block height"), RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "inputsHash", "Hash of all the outpoints of the transaction inputs"), + RESULT_MAP_ENTRY(RPCResult::Type::NUM, "llmqType", "Quorum type"), RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "merkleRootMNList", "Merkle root of the masternode list"), RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "merkleRootQuorums", "Merkle root of the quorum list"), RESULT_MAP_ENTRY(RPCResult::Type::STR, "operatorPayoutAddress", "Dash address used for operator reward payments"), @@ -49,6 +50,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "proTxHash", "Hash of the masternode's initial ProRegTx"), RESULT_MAP_ENTRY(RPCResult::Type::STR, "pubKeyOperator", "BLS public key used for operator signing"), RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "quorumHash", "Hash of the quorum"), + RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "quorumSig", "BLS recovered threshold signature of quorum"), RESULT_MAP_ENTRY(RPCResult::Type::STR, "service", "(DEPRECATED) IP address and port of the masternode"), RESULT_MAP_ENTRY(RPCResult::Type::NUM, "type", "Masternode type"), RESULT_MAP_ENTRY(RPCResult::Type::NUM, "version", "Special transaction version"), @@ -109,7 +111,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) {RPCResult::Type::NUM, "fee", "Transaction fee in duffs awarded to the miner"}, {RPCResult::Type::NUM, "requestedHeight", "Payment chain block height known by Platform when signing the withdrawal"}, GetRpcResult("quorumHash"), - {RPCResult::Type::STR_HEX, "quorumSig", "BLS signature by a quorum public key"}, + GetRpcResult("quorumSig"), }}; } @@ -335,10 +337,11 @@ RPCResult GetRpcResult(const std::string& key, bool optional) {CSimplifiedMNListEntry::GetJsonHelp(/*key=*/"", /*optional=*/false)}}, {RPCResult::Type::ARR, "deletedQuorums", "Deleted quorums", {{RPCResult::Type::OBJ, "", "", { - {RPCResult::Type::NUM, "llmqType", "Quorum type"}, + GetRpcResult("llmqType"), GetRpcResult("quorumHash"), }}}}, - {RPCResult::Type::ARR, "newQuorums", "New quorums"}, // TODO: Add definition for llmq::CFinalCommitment + {RPCResult::Type::ARR, "newQuorums", "New quorums", + {llmq::CFinalCommitment::GetJsonHelp(/*key=*/"", /*optional=*/false)}}, GetRpcResult("merkleRootMNList", /*optional=*/true), GetRpcResult("merkleRootQuorums", /*optional=*/true), {RPCResult::Type::ARR, "quorumsCLSigs", "ChainLock signature details", { diff --git a/src/llmq/commitment.h b/src/llmq/commitment.h index 54b96c19bc96..60cf499d5a2a 100644 --- a/src/llmq/commitment.h +++ b/src/llmq/commitment.h @@ -130,6 +130,7 @@ class CFinalCommitment return true; } + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; private: diff --git a/src/llmq/core_write.cpp b/src/llmq/core_write.cpp index 47b92e1d9daa..8a8137ed7072 100644 --- a/src/llmq/core_write.cpp +++ b/src/llmq/core_write.cpp @@ -15,6 +15,25 @@ #include namespace llmq { +[[nodiscard]] RPCResult CFinalCommitment::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The quorum commitment payload", + { + {RPCResult::Type::NUM, "version", "Quorum commitment payload version"}, + GetRpcResult("llmqType"), + GetRpcResult("quorumHash"), + {RPCResult::Type::NUM, "quorumIndex", "Index of the quorum"}, + {RPCResult::Type::NUM, "signersCount", "Number of signers for the quorum"}, + {RPCResult::Type::STR_HEX, "signers", "Bitset representing the aggregated signers"}, + {RPCResult::Type::NUM, "validMembersCount", "Number of valid members in the quorum"}, + {RPCResult::Type::STR_HEX, "validMembers", "Bitset of valid members"}, + {RPCResult::Type::STR_HEX, "quorumPublicKey", "BLS public key of the quorum"}, + {RPCResult::Type::STR_HEX, "quorumVvecHash", "Hash of the quorum verification vector"}, + GetRpcResult("quorumSig"), + {RPCResult::Type::STR_HEX, "membersSig", "BLS signature from all included commitments"}, + }}; +} + [[nodiscard]] UniValue CFinalCommitment::ToJson() const { UniValue obj(UniValue::VOBJ); @@ -39,7 +58,7 @@ namespace llmq { { GetRpcResult("version"), GetRpcResult("height"), - // TODO: Add RPCResult for llmq::CFinalCommitment + CFinalCommitment::GetJsonHelp(/*key=*/"commitment", /*optional=*/false), }}; } @@ -52,6 +71,33 @@ namespace llmq { return ret; } +[[nodiscard]] RPCResult CQuorumRotationInfo::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The quorum rotation", + { + {RPCResult::Type::BOOL, "extraShare", "Returns true if an extra share is returned"}, + CQuorumSnapshot::GetJsonHelp(/*key=*/"quorumSnapshotAtHMinusC", /*optional=*/false), + CQuorumSnapshot::GetJsonHelp(/*key=*/"quorumSnapshotAtHMinus2C", /*optional=*/false), + CQuorumSnapshot::GetJsonHelp(/*key=*/"quorumSnapshotAtHMinus3C", /*optional=*/false), + CQuorumSnapshot::GetJsonHelp(/*key=*/"quorumSnapshotAtHMinus4C", /*optional=*/true), + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"mnListDiffTip", /*optional=*/false), + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"mnListDiffH", /*optional=*/false), + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"mnListDiffAtHMinusC", /*optional=*/false), + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"mnListDiffAtHMinus2C", /*optional=*/false), + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"mnListDiffAtHMinus3C", /*optional=*/false), + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"mnListDiffAtHMinus4C", /*optional=*/true), + {RPCResult::Type::ARR, "lastCommitmentPerIndex", "Most recent commitment for each quorumIndex", { + CFinalCommitment::GetJsonHelp(/*key=*/"", /*optional=*/false), + }}, + {RPCResult::Type::ARR, "quorumSnapshotList", "Snapshots required to reconstruct the quorums built at h' in lastCommitmentPerIndex", { + CQuorumSnapshot::GetJsonHelp(/*key=*/"", /*optional=*/false), + }}, + {RPCResult::Type::ARR, "mnListDiffList", "MnListDiffs required to calculate older quorums", { + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"", /*optional=*/false), + }}, + }}; +} + [[nodiscard]] UniValue CQuorumRotationInfo::ToJson() const { UniValue obj(UniValue::VOBJ); @@ -94,6 +140,20 @@ namespace llmq { return obj; } +[[nodiscard]] RPCResult CQuorumSnapshot::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The quorum snapshot", + { + {RPCResult::Type::ARR, "activeQuorumMembers", "Bitset of nodes already in quarters at the start of cycle", { + {RPCResult::Type::BOOL, "bit", ""} + }}, + {RPCResult::Type::NUM, "mnSkipListMode", "Mode of the skip list"}, + {RPCResult::Type::ARR, "mnSkipList", "Skiplist at height", { + {RPCResult::Type::NUM, "height", ""} + }}, + }}; +} + [[nodiscard]] UniValue CQuorumSnapshot::ToJson() const { UniValue obj(UniValue::VOBJ); @@ -113,6 +173,19 @@ namespace llmq { return obj; } +[[nodiscard]] RPCResult CRecoveredSig::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The recovered signature", + { + GetRpcResult("llmqType"), + GetRpcResult("quorumHash"), + {RPCResult::Type::NUM, "id", "Signing session ID"}, + {RPCResult::Type::STR_HEX, "msgHash", "Hash of message"}, + {RPCResult::Type::STR_HEX, "sig", "BLS signature recovered"}, + {RPCResult::Type::STR_HEX, "hash", "Hash of the BLS signature recovered"}, + }}; +} + [[nodiscard]] UniValue CRecoveredSig::ToJson() const { UniValue ret(UniValue::VOBJ); diff --git a/src/llmq/signing.h b/src/llmq/signing.h index 1097240c590e..2425de093604 100644 --- a/src/llmq/signing.h +++ b/src/llmq/signing.h @@ -30,6 +30,8 @@ class CDBBatch; class CDBWrapper; class CInv; class PeerManager; +struct RPCResult; + class UniValue; namespace llmq { @@ -106,6 +108,7 @@ class CRecoveredSig : virtual public CSigBase return hash; } + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; }; diff --git a/src/llmq/snapshot.h b/src/llmq/snapshot.h index 2d161ed00faf..3b1035a37b12 100644 --- a/src/llmq/snapshot.h +++ b/src/llmq/snapshot.h @@ -19,6 +19,8 @@ class CBlockIndex; class CEvoDB; +struct RPCResult; + class UniValue; namespace llmq { @@ -82,6 +84,7 @@ class CQuorumSnapshot } } + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; }; @@ -198,6 +201,7 @@ class CQuorumRotationInfo CQuorumRotationInfo() = default; CQuorumRotationInfo(const CQuorumRotationInfo& dmn) {} + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; }; diff --git a/src/rpc/quorums.cpp b/src/rpc/quorums.cpp index d4776d97e745..a9b3b88d3455 100644 --- a/src/rpc/quorums.cpp +++ b/src/rpc/quorums.cpp @@ -365,6 +365,7 @@ static RPCHelpMan quorum_dkgstatus() std::optional> vfqc = llmq_ctx.quorum_block_processor->GetMineableCommitments(llmq_params, tipHeight); if (vfqc.has_value()) { for (const auto& fqc : vfqc.value()) { + // TODO: Use CFinalCommitment::GetJsonHelp() for fqc minableCommitments.push_back(fqc.ToJson()); } } @@ -651,7 +652,7 @@ static RPCHelpMan quorum_getrecsig() {"id", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Request id."}, {"msgHash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Message hash."}, }, - RPCResults{}, + llmq::CRecoveredSig::GetJsonHelp(/*key=*/"", /*optional=*/false), RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -847,7 +848,7 @@ static RPCHelpMan quorum_rotationinfo() {"baseBlockHash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, }}, }, - RPCResults{}, + llmq::CQuorumRotationInfo::GetJsonHelp(/*key=*/"", /*optional=*/false), RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { From b7eb196545f6f4359bb3afe62f1b61d96f2c0a4e Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 6 Oct 2025 20:23:39 +0000 Subject: [PATCH 08/10] rpc: `GetJsonHelp()` defs for `DeterministicMN{,State{,{Diff}}}` --- src/evo/core_write.cpp | 86 ++++++++++++++++++++++++++++++++++++-- src/evo/deterministicmns.h | 6 ++- src/evo/dmnstate.h | 15 +++---- src/rpc/evo.cpp | 2 + src/rpc/masternode.cpp | 1 + 5 files changed, 97 insertions(+), 13 deletions(-) diff --git a/src/evo/core_write.cpp b/src/evo/core_write.cpp index 63a988f2ec32..e7b9f3e852d5 100644 --- a/src/evo/core_write.cpp +++ b/src/evo/core_write.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -37,20 +38,31 @@ RPCResult GetRpcResult(const std::string& key, bool optional) {RPCResult::Type::ARR, "platform_https", /*optional=*/true, "Addresses used for Platform HTTPS API", {{RPCResult::Type::STR, "address", ""}}}, }}}, + RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "collateralHash", "Collateral transaction hash"), + RESULT_MAP_ENTRY(RPCResult::Type::NUM, "collateralIndex", "Collateral transaction output index"), + RESULT_MAP_ENTRY(RPCResult::Type::NUM, "consecutivePayments", "Consecutive payments masternode has received in payment cycle"), RESULT_MAP_ENTRY(RPCResult::Type::NUM, "height", "Block height"), RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "inputsHash", "Hash of all the outpoints of the transaction inputs"), + RESULT_MAP_ENTRY(RPCResult::Type::NUM, "lastPaidHeight", "Height masternode was last paid"), RESULT_MAP_ENTRY(RPCResult::Type::NUM, "llmqType", "Quorum type"), RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "merkleRootMNList", "Merkle root of the masternode list"), RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "merkleRootQuorums", "Merkle root of the quorum list"), RESULT_MAP_ENTRY(RPCResult::Type::STR, "operatorPayoutAddress", "Dash address used for operator reward payments"), + RESULT_MAP_ENTRY(RPCResult::Type::NUM, "operatorReward", "Fraction in %% of reward shared with the operator between 0 and 10000"), + RESULT_MAP_ENTRY(RPCResult::Type::STR, "ownerAddress", "Dash address used for payee updates and proposal voting"), RESULT_MAP_ENTRY(RPCResult::Type::STR, "payoutAddress", "Dash address used for masternode reward payments"), RESULT_MAP_ENTRY(RPCResult::Type::NUM, "platformHTTPPort", "(DEPRECATED) TCP port of Platform HTTP API"), RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "platformNodeID", "Node ID derived from P2P public key for Platform P2P"), RESULT_MAP_ENTRY(RPCResult::Type::NUM, "platformP2PPort", "(DEPRECATED) TCP port of Platform P2P"), + RESULT_MAP_ENTRY(RPCResult::Type::NUM, "PoSeBanHeight", "Height masternode was banned for Proof of Service violations"), + RESULT_MAP_ENTRY(RPCResult::Type::NUM, "PoSePenalty", "Proof of Service penalty score"), + RESULT_MAP_ENTRY(RPCResult::Type::NUM, "PoSeRevivedHeight", "Height masternode recovered from Proof of Service violations"), RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "proTxHash", "Hash of the masternode's initial ProRegTx"), RESULT_MAP_ENTRY(RPCResult::Type::STR, "pubKeyOperator", "BLS public key used for operator signing"), RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "quorumHash", "Hash of the quorum"), RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "quorumSig", "BLS recovered threshold signature of quorum"), + RESULT_MAP_ENTRY(RPCResult::Type::NUM, "registeredHeight", "Height masternode was registered"), + RESULT_MAP_ENTRY(RPCResult::Type::NUM, "revocationReason", "Reason for ProUpRegTx revocation"), RESULT_MAP_ENTRY(RPCResult::Type::STR, "service", "(DEPRECATED) IP address and port of the masternode"), RESULT_MAP_ENTRY(RPCResult::Type::NUM, "type", "Masternode type"), RESULT_MAP_ENTRY(RPCResult::Type::NUM, "version", "Special transaction version"), @@ -158,6 +170,46 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return ret; } +// CDeterministicMN::ToJson() defined in evo/deterministicmns.cpp +[[nodiscard]] RPCResult CDeterministicMN::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode's details", + { + {RPCResult::Type::STR, "type", "Masternode type"}, + GetRpcResult("proTxHash"), + GetRpcResult("collateralHash"), + GetRpcResult("collateralIndex"), + {RPCResult::Type::STR, "collateralAddress", /*optional=*/true, "Dash address used for collateral"}, + GetRpcResult("operatorReward"), + CDeterministicMNState::GetJsonHelp(/*key=*/"state", /*optional=*/false), + }}; +} + +[[nodiscard]] RPCResult CDeterministicMNState::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode state", + { + {RPCResult::Type::NUM, "version", "Version of the masternode state"}, + GetRpcResult("service"), + GetRpcResult("addresses"), + GetRpcResult("registeredHeight"), + GetRpcResult("lastPaidHeight"), + GetRpcResult("consecutivePayments"), + GetRpcResult("PoSePenalty"), + GetRpcResult("PoSeRevivedHeight"), + GetRpcResult("PoSeBanHeight"), + GetRpcResult("revocationReason"), + GetRpcResult("ownerAddress"), + GetRpcResult("votingAddress"), + GetRpcResult("platformNodeID", /*optional=*/true), + GetRpcResult("platformP2PPort", /*optional=*/true), + GetRpcResult("platformHTTPPort", /*optional=*/true), + GetRpcResult("payoutAddress", /*optional=*/true), + GetRpcResult("pubKeyOperator"), + GetRpcResult("operatorPayoutAddress", /*optional=*/true), + }}; +} + [[nodiscard]] UniValue CDeterministicMNState::ToJson(MnType nType) const { UniValue obj(UniValue::VOBJ); @@ -190,21 +242,47 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return obj; } +// CDeterministicMNStateDiff::ToJson() defined in evo/dmnstate.cpp +[[nodiscard]] RPCResult CDeterministicMNStateDiff::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode state diff", + { + {RPCResult::Type::NUM, "version", "Version of the masternode state diff"}, + GetRpcResult("service", /*optional=*/true), + GetRpcResult("registeredHeight", /*optional=*/true), + GetRpcResult("lastPaidHeight", /*optional=*/true), + GetRpcResult("consecutivePayments", /*optional=*/true), + GetRpcResult("PoSePenalty", /*optional=*/true), + GetRpcResult("PoSeRevivedHeight", /*optional=*/true), + GetRpcResult("PoSeBanHeight", /*optional=*/true), + GetRpcResult("revocationReason", /*optional=*/true), + GetRpcResult("ownerAddress", /*optional=*/true), + GetRpcResult("votingAddress", /*optional=*/true), + GetRpcResult("payoutAddress", /*optional=*/true), + GetRpcResult("operatorPayoutAddress", /*optional=*/true), + GetRpcResult("pubKeyOperator", /*optional=*/true), + GetRpcResult("platformNodeID", /*optional=*/true), + GetRpcResult("platformP2PPort", /*optional=*/true), + GetRpcResult("platformHTTPPort", /*optional=*/true), + GetRpcResult("addresses", /*optional=*/true), + }}; +} + [[nodiscard]] RPCResult CProRegTx::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode registration special transaction", { GetRpcResult("version"), GetRpcResult("type"), - {RPCResult::Type::STR_HEX, "collateralHash", "Collateral transaction hash"}, - {RPCResult::Type::NUM, "collateralIndex", "Collateral transaction output index"}, + GetRpcResult("collateralHash"), + GetRpcResult("collateralIndex"), GetRpcResult("service"), GetRpcResult("addresses"), - {RPCResult::Type::STR, "ownerAddress", "Dash address used for payee updates and proposal voting"}, + GetRpcResult("ownerAddress"), GetRpcResult("votingAddress"), GetRpcResult("payoutAddress", /*optional=*/true), GetRpcResult("pubKeyOperator"), - {RPCResult::Type::NUM, "operatorReward", "Fraction in %% of reward shared with the operator between 0 and 10000"}, + GetRpcResult("operatorReward"), GetRpcResult("platformNodeID", /*optional=*/true), GetRpcResult("platformP2PPort", /*optional=*/true), GetRpcResult("platformHTTPPort", /*optional=*/true), diff --git a/src/evo/deterministicmns.h b/src/evo/deterministicmns.h index 12643e5f1f1a..6fdf3604e9c3 100644 --- a/src/evo/deterministicmns.h +++ b/src/evo/deterministicmns.h @@ -5,9 +5,8 @@ #ifndef BITCOIN_EVO_DETERMINISTICMNS_H #define BITCOIN_EVO_DETERMINISTICMNS_H -#include - #include +#include #include #include @@ -36,6 +35,7 @@ class CSimplifiedMNList; class CSimplifiedMNListEntry; class CMasternodeMetaMan; class TxValidationState; +struct RPCResult; extern RecursiveMutex cs_main; @@ -86,6 +86,8 @@ class CDeterministicMN [[nodiscard]] CSimplifiedMNListEntry to_sml_entry() const; [[nodiscard]] std::string ToString() const; + + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; }; diff --git a/src/evo/dmnstate.h b/src/evo/dmnstate.h index d63460b2d931..7fa609465002 100644 --- a/src/evo/dmnstate.h +++ b/src/evo/dmnstate.h @@ -19,16 +19,15 @@ #include #include -class CProRegTx; -class UniValue; - class CDeterministicMNState; - -namespace llmq -{ - class CFinalCommitment; +class CProRegTx; +struct RPCResult; +namespace llmq { +class CFinalCommitment; } // namespace llmq +class UniValue; + class CDeterministicMNState { private: @@ -150,6 +149,7 @@ class CDeterministicMNState public: std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson(MnType nType) const; }; @@ -243,6 +243,7 @@ class CDeterministicMNStateDiff template CDeterministicMNStateDiff(deserialize_type, Stream& s) { s >> *this; } + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson(MnType nType) const; SERIALIZE_METHODS(CDeterministicMNStateDiff, obj) diff --git a/src/rpc/evo.cpp b/src/rpc/evo.cpp index 9907f19153f8..3e0dcc641636 100644 --- a/src/rpc/evo.cpp +++ b/src/rpc/evo.cpp @@ -1679,6 +1679,7 @@ static RPCHelpMan protx_listdiff() for(const auto& mn : mnDiff.addedMNs) { jaddedMNs.push_back(mn->ToJson()); } + // TODO: Use CDeterministicMN::GetJsonHelp() for mn ret.pushKV("addedMNs", jaddedMNs); UniValue jremovedMNs(UniValue::VARR); @@ -1701,6 +1702,7 @@ static RPCHelpMan protx_listdiff() obj.pushKV(dmn->proTxHash.ToString(), stateDiff.ToJson(dmn->nType)); jupdatedMNs.push_back(obj); } + // TODO: Use CDeterministicMNStateDiff::GetJsonHelp() for stateDiff ret.pushKV("updatedMNs", jupdatedMNs); return ret; diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index b87670e3766c..727b20e9ebf5 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -177,6 +177,7 @@ static RPCHelpMan masternode_status() mnObj.pushKV("type", std::string(GetMnType(dmn->nType).description)); mnObj.pushKV("collateralHash", dmn->collateralOutpoint.hash.ToString()); mnObj.pushKV("collateralIndex", dmn->collateralOutpoint.n); + // TODO: Use CDeterministicMNState::GetJsonHelp() for dmnState mnObj.pushKV("dmnState", dmn->pdmnState->ToJson(dmn->nType)); } mnObj.pushKV("state", node.mn_activeman->GetStateString()); From f01930b975f61be2af5c1229df6766d714bdc329 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 5 Oct 2025 12:55:46 +0000 Subject: [PATCH 09/10] chore: remove redundant `[[nodiscard]]` attributions in source file --- src/evo/core_write.cpp | 52 ++++++++++++++++++++--------------------- src/llmq/core_write.cpp | 20 ++++++++-------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/evo/core_write.cpp b/src/evo/core_write.cpp index e7b9f3e852d5..eef000b1b2be 100644 --- a/src/evo/core_write.cpp +++ b/src/evo/core_write.cpp @@ -78,7 +78,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) __FILE__, __LINE__, __func__); } -[[nodiscard]] RPCResult CAssetLockPayload::GetJsonHelp(const std::string& key, bool optional) +RPCResult CAssetLockPayload::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The asset lock special transaction", { @@ -95,7 +95,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) }}; } -[[nodiscard]] UniValue CAssetLockPayload::ToJson() const +UniValue CAssetLockPayload::ToJson() const { UniValue outputs(UniValue::VARR); for (const CTxOut& credit_output : creditOutputs) { @@ -114,7 +114,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return ret; } -[[nodiscard]] RPCResult CAssetUnlockPayload::GetJsonHelp(const std::string& key, bool optional) +RPCResult CAssetUnlockPayload::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The asset unlock special transaction", { @@ -127,7 +127,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) }}; } -[[nodiscard]] UniValue CAssetUnlockPayload::ToJson() const +UniValue CAssetUnlockPayload::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -139,7 +139,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return ret; } -[[nodiscard]] RPCResult CCbTx::GetJsonHelp(const std::string& key, bool optional) +RPCResult CCbTx::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The coinbase special transaction", { @@ -153,7 +153,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) }}; } -[[nodiscard]] UniValue CCbTx::ToJson() const +UniValue CCbTx::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", ToUnderlying(nVersion)); @@ -171,7 +171,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) } // CDeterministicMN::ToJson() defined in evo/deterministicmns.cpp -[[nodiscard]] RPCResult CDeterministicMN::GetJsonHelp(const std::string& key, bool optional) +RPCResult CDeterministicMN::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode's details", { @@ -185,7 +185,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) }}; } -[[nodiscard]] RPCResult CDeterministicMNState::GetJsonHelp(const std::string& key, bool optional) +RPCResult CDeterministicMNState::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode state", { @@ -210,7 +210,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) }}; } -[[nodiscard]] UniValue CDeterministicMNState::ToJson(MnType nType) const +UniValue CDeterministicMNState::ToJson(MnType nType) const { UniValue obj(UniValue::VOBJ); obj.pushKV("version", nVersion); @@ -243,7 +243,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) } // CDeterministicMNStateDiff::ToJson() defined in evo/dmnstate.cpp -[[nodiscard]] RPCResult CDeterministicMNStateDiff::GetJsonHelp(const std::string& key, bool optional) +RPCResult CDeterministicMNStateDiff::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode state diff", { @@ -268,7 +268,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) }}; } -[[nodiscard]] RPCResult CProRegTx::GetJsonHelp(const std::string& key, bool optional) +RPCResult CProRegTx::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode registration special transaction", { @@ -290,7 +290,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) }}; } -[[nodiscard]] UniValue CProRegTx::ToJson() const +UniValue CProRegTx::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -315,7 +315,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return ret; } -[[nodiscard]] RPCResult CProUpRegTx::GetJsonHelp(const std::string& key, bool optional) +RPCResult CProUpRegTx::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode update registrar special transaction", { @@ -328,7 +328,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) }}; } -[[nodiscard]] UniValue CProUpRegTx::ToJson() const +UniValue CProUpRegTx::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -342,7 +342,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return ret; } -[[nodiscard]] RPCResult CProUpRevTx::GetJsonHelp(const std::string& key, bool optional) +RPCResult CProUpRevTx::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode operator revocation special transaction", { @@ -353,7 +353,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) }}; } -[[nodiscard]] UniValue CProUpRevTx::ToJson() const +UniValue CProUpRevTx::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -363,7 +363,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return ret; } -[[nodiscard]] RPCResult CProUpServTx::GetJsonHelp(const std::string& key, bool optional) +RPCResult CProUpServTx::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode update service special transaction", { @@ -380,7 +380,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) }}; } -[[nodiscard]] UniValue CProUpServTx::ToJson() const +UniValue CProUpServTx::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -400,7 +400,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return ret; } -[[nodiscard]] RPCResult CSimplifiedMNListDiff::GetJsonHelp(const std::string& key, bool optional) +RPCResult CSimplifiedMNListDiff::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The simplified masternode list diff", { @@ -430,7 +430,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) }}; } -[[nodiscard]] UniValue CSimplifiedMNListDiff::ToJson(bool extended) const +UniValue CSimplifiedMNListDiff::ToJson(bool extended) const { UniValue obj(UniValue::VOBJ); @@ -493,7 +493,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return obj; } -[[nodiscard]] RPCResult CSimplifiedMNListEntry::GetJsonHelp(const std::string& key, bool optional) +RPCResult CSimplifiedMNListEntry::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The simplified masternode list entry", { @@ -513,7 +513,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) }}; } -[[nodiscard]] UniValue CSimplifiedMNListEntry::ToJson(bool extended) const +UniValue CSimplifiedMNListEntry::ToJson(bool extended) const { UniValue obj(UniValue::VOBJ); obj.pushKV("nVersion", nVersion); @@ -542,7 +542,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return obj; } -[[nodiscard]] RPCResult MNHFTx::GetJsonHelp(const std::string& key, bool optional) +RPCResult MNHFTx::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode hard fork payload", { @@ -552,7 +552,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) }}; } -[[nodiscard]] UniValue MNHFTx::ToJson() const +UniValue MNHFTx::ToJson() const { UniValue obj(UniValue::VOBJ); obj.pushKV("versionBit", versionBit); @@ -561,7 +561,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) return obj; } -[[nodiscard]] RPCResult MNHFTxPayload::GetJsonHelp(const std::string& key, bool optional) +RPCResult MNHFTxPayload::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode hard fork signal special transaction", { @@ -570,7 +570,7 @@ RPCResult GetRpcResult(const std::string& key, bool optional) }}; } -[[nodiscard]] UniValue MNHFTxPayload::ToJson() const +UniValue MNHFTxPayload::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); diff --git a/src/llmq/core_write.cpp b/src/llmq/core_write.cpp index 8a8137ed7072..5ffe3c46f956 100644 --- a/src/llmq/core_write.cpp +++ b/src/llmq/core_write.cpp @@ -15,7 +15,7 @@ #include namespace llmq { -[[nodiscard]] RPCResult CFinalCommitment::GetJsonHelp(const std::string& key, bool optional) +RPCResult CFinalCommitment::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The quorum commitment payload", { @@ -34,7 +34,7 @@ namespace llmq { }}; } -[[nodiscard]] UniValue CFinalCommitment::ToJson() const +UniValue CFinalCommitment::ToJson() const { UniValue obj(UniValue::VOBJ); obj.pushKV("version", nVersion); @@ -52,7 +52,7 @@ namespace llmq { return obj; } -[[nodiscard]] RPCResult CFinalCommitmentTxPayload::GetJsonHelp(const std::string& key, bool optional) +RPCResult CFinalCommitmentTxPayload::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The quorum commitment special transaction", { @@ -62,7 +62,7 @@ namespace llmq { }}; } -[[nodiscard]] UniValue CFinalCommitmentTxPayload::ToJson() const +UniValue CFinalCommitmentTxPayload::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -71,7 +71,7 @@ namespace llmq { return ret; } -[[nodiscard]] RPCResult CQuorumRotationInfo::GetJsonHelp(const std::string& key, bool optional) +RPCResult CQuorumRotationInfo::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The quorum rotation", { @@ -98,7 +98,7 @@ namespace llmq { }}; } -[[nodiscard]] UniValue CQuorumRotationInfo::ToJson() const +UniValue CQuorumRotationInfo::ToJson() const { UniValue obj(UniValue::VOBJ); obj.pushKV("extraShare", extraShare); @@ -140,7 +140,7 @@ namespace llmq { return obj; } -[[nodiscard]] RPCResult CQuorumSnapshot::GetJsonHelp(const std::string& key, bool optional) +RPCResult CQuorumSnapshot::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The quorum snapshot", { @@ -154,7 +154,7 @@ namespace llmq { }}; } -[[nodiscard]] UniValue CQuorumSnapshot::ToJson() const +UniValue CQuorumSnapshot::ToJson() const { UniValue obj(UniValue::VOBJ); UniValue activeQ(UniValue::VARR); @@ -173,7 +173,7 @@ namespace llmq { return obj; } -[[nodiscard]] RPCResult CRecoveredSig::GetJsonHelp(const std::string& key, bool optional) +RPCResult CRecoveredSig::GetJsonHelp(const std::string& key, bool optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The recovered signature", { @@ -186,7 +186,7 @@ namespace llmq { }}; } -[[nodiscard]] UniValue CRecoveredSig::ToJson() const +UniValue CRecoveredSig::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("llmqType", ToUnderlying(llmqType)); From 56514c767d6faa01d0076136a3d37bb5158f6125 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 5 Oct 2025 15:08:43 +0000 Subject: [PATCH 10/10] chore: move RpcResult map outside `GetRpcResult()` We are using it extensively and could do with some cleanup --- src/evo/core_write.cpp | 96 +++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/src/evo/core_write.cpp b/src/evo/core_write.cpp index eef000b1b2be..4e83e8bc4630 100644 --- a/src/evo/core_write.cpp +++ b/src/evo/core_write.cpp @@ -24,56 +24,58 @@ #include #include +namespace { +#define RESULT_MAP_ENTRY(name, type, desc) {name, {type, name, desc}} +const std::map RPCRESULT_MAP{{ + {"addresses", + {RPCResult::Type::OBJ, "addresses", "Network addresses of the masternode", + { + {RPCResult::Type::ARR, "core_p2p", /*optional=*/true, "Addresses used for protocol P2P", + {{RPCResult::Type::STR, "address", ""}}}, + {RPCResult::Type::ARR, "platform_p2p", /*optional=*/true, "Addresses used for Platform P2P", + {{RPCResult::Type::STR, "address", ""}}}, + {RPCResult::Type::ARR, "platform_https", /*optional=*/true, "Addresses used for Platform HTTPS API", + {{RPCResult::Type::STR, "address", ""}}}, + }}}, + RESULT_MAP_ENTRY("collateralHash", RPCResult::Type::STR_HEX, "Collateral transaction hash"), + RESULT_MAP_ENTRY("collateralIndex", RPCResult::Type::NUM, "Collateral transaction output index"), + RESULT_MAP_ENTRY("consecutivePayments", RPCResult::Type::NUM, "Consecutive payments masternode has received in payment cycle"), + RESULT_MAP_ENTRY("height", RPCResult::Type::NUM, "Block height"), + RESULT_MAP_ENTRY("inputsHash", RPCResult::Type::STR_HEX, "Hash of all the outpoints of the transaction inputs"), + RESULT_MAP_ENTRY("lastPaidHeight", RPCResult::Type::NUM, "Height masternode was last paid"), + RESULT_MAP_ENTRY("llmqType", RPCResult::Type::NUM, "Quorum type"), + RESULT_MAP_ENTRY("merkleRootMNList", RPCResult::Type::STR_HEX, "Merkle root of the masternode list"), + RESULT_MAP_ENTRY("merkleRootQuorums", RPCResult::Type::STR_HEX, "Merkle root of the quorum list"), + RESULT_MAP_ENTRY("operatorPayoutAddress", RPCResult::Type::STR, "Dash address used for operator reward payments"), + RESULT_MAP_ENTRY("operatorReward", RPCResult::Type::NUM, "Fraction in %% of reward shared with the operator between 0 and 10000"), + RESULT_MAP_ENTRY("ownerAddress", RPCResult::Type::STR, "Dash address used for payee updates and proposal voting"), + RESULT_MAP_ENTRY("payoutAddress", RPCResult::Type::STR, "Dash address used for masternode reward payments"), + RESULT_MAP_ENTRY("platformHTTPPort", RPCResult::Type::NUM, "(DEPRECATED) TCP port of Platform HTTP API"), + RESULT_MAP_ENTRY("platformNodeID", RPCResult::Type::STR_HEX, "Node ID derived from P2P public key for Platform P2P"), + RESULT_MAP_ENTRY("platformP2PPort", RPCResult::Type::NUM, "(DEPRECATED) TCP port of Platform P2P"), + RESULT_MAP_ENTRY("PoSeBanHeight", RPCResult::Type::NUM, "Height masternode was banned for Proof of Service violations"), + RESULT_MAP_ENTRY("PoSePenalty", RPCResult::Type::NUM, "Proof of Service penalty score"), + RESULT_MAP_ENTRY("PoSeRevivedHeight", RPCResult::Type::NUM, "Height masternode recovered from Proof of Service violations"), + RESULT_MAP_ENTRY("proTxHash", RPCResult::Type::STR_HEX, "Hash of the masternode's initial ProRegTx"), + RESULT_MAP_ENTRY("pubKeyOperator", RPCResult::Type::STR, "BLS public key used for operator signing"), + RESULT_MAP_ENTRY("quorumHash", RPCResult::Type::STR_HEX, "Hash of the quorum"), + RESULT_MAP_ENTRY("quorumSig", RPCResult::Type::STR_HEX, "BLS recovered threshold signature of quorum"), + RESULT_MAP_ENTRY("registeredHeight", RPCResult::Type::NUM, "Height masternode was registered"), + RESULT_MAP_ENTRY("revocationReason", RPCResult::Type::NUM, "Reason for ProUpRegTx revocation"), + RESULT_MAP_ENTRY("service", RPCResult::Type::STR, "(DEPRECATED) IP address and port of the masternode"), + RESULT_MAP_ENTRY("type", RPCResult::Type::NUM, "Masternode type"), + RESULT_MAP_ENTRY("version", RPCResult::Type::NUM, "Special transaction version"), + RESULT_MAP_ENTRY("votingAddress", RPCResult::Type::STR, "Dash address used for voting"), +}}; +#undef RESULT_MAP_ENTRY +} // anonymous namespace + RPCResult GetRpcResult(const std::string& key, bool optional) { -#define RESULT_MAP_ENTRY(type, name, desc) {name, {type, name, optional, desc}} - const std::map result_map{{ - {"addresses", - {RPCResult::Type::OBJ, "addresses", optional, "Network addresses of the masternode", - { - {RPCResult::Type::ARR, "core_p2p", /*optional=*/true, "Addresses used for protocol P2P", - {{RPCResult::Type::STR, "address", ""}}}, - {RPCResult::Type::ARR, "platform_p2p", /*optional=*/true, "Addresses used for Platform P2P", - {{RPCResult::Type::STR, "address", ""}}}, - {RPCResult::Type::ARR, "platform_https", /*optional=*/true, "Addresses used for Platform HTTPS API", - {{RPCResult::Type::STR, "address", ""}}}, - }}}, - RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "collateralHash", "Collateral transaction hash"), - RESULT_MAP_ENTRY(RPCResult::Type::NUM, "collateralIndex", "Collateral transaction output index"), - RESULT_MAP_ENTRY(RPCResult::Type::NUM, "consecutivePayments", "Consecutive payments masternode has received in payment cycle"), - RESULT_MAP_ENTRY(RPCResult::Type::NUM, "height", "Block height"), - RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "inputsHash", "Hash of all the outpoints of the transaction inputs"), - RESULT_MAP_ENTRY(RPCResult::Type::NUM, "lastPaidHeight", "Height masternode was last paid"), - RESULT_MAP_ENTRY(RPCResult::Type::NUM, "llmqType", "Quorum type"), - RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "merkleRootMNList", "Merkle root of the masternode list"), - RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "merkleRootQuorums", "Merkle root of the quorum list"), - RESULT_MAP_ENTRY(RPCResult::Type::STR, "operatorPayoutAddress", "Dash address used for operator reward payments"), - RESULT_MAP_ENTRY(RPCResult::Type::NUM, "operatorReward", "Fraction in %% of reward shared with the operator between 0 and 10000"), - RESULT_MAP_ENTRY(RPCResult::Type::STR, "ownerAddress", "Dash address used for payee updates and proposal voting"), - RESULT_MAP_ENTRY(RPCResult::Type::STR, "payoutAddress", "Dash address used for masternode reward payments"), - RESULT_MAP_ENTRY(RPCResult::Type::NUM, "platformHTTPPort", "(DEPRECATED) TCP port of Platform HTTP API"), - RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "platformNodeID", "Node ID derived from P2P public key for Platform P2P"), - RESULT_MAP_ENTRY(RPCResult::Type::NUM, "platformP2PPort", "(DEPRECATED) TCP port of Platform P2P"), - RESULT_MAP_ENTRY(RPCResult::Type::NUM, "PoSeBanHeight", "Height masternode was banned for Proof of Service violations"), - RESULT_MAP_ENTRY(RPCResult::Type::NUM, "PoSePenalty", "Proof of Service penalty score"), - RESULT_MAP_ENTRY(RPCResult::Type::NUM, "PoSeRevivedHeight", "Height masternode recovered from Proof of Service violations"), - RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "proTxHash", "Hash of the masternode's initial ProRegTx"), - RESULT_MAP_ENTRY(RPCResult::Type::STR, "pubKeyOperator", "BLS public key used for operator signing"), - RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "quorumHash", "Hash of the quorum"), - RESULT_MAP_ENTRY(RPCResult::Type::STR_HEX, "quorumSig", "BLS recovered threshold signature of quorum"), - RESULT_MAP_ENTRY(RPCResult::Type::NUM, "registeredHeight", "Height masternode was registered"), - RESULT_MAP_ENTRY(RPCResult::Type::NUM, "revocationReason", "Reason for ProUpRegTx revocation"), - RESULT_MAP_ENTRY(RPCResult::Type::STR, "service", "(DEPRECATED) IP address and port of the masternode"), - RESULT_MAP_ENTRY(RPCResult::Type::NUM, "type", "Masternode type"), - RESULT_MAP_ENTRY(RPCResult::Type::NUM, "version", "Special transaction version"), - RESULT_MAP_ENTRY(RPCResult::Type::STR, "votingAddress", "Dash address used for voting"), - }}; -#undef RESULT_MAP_ENTRY - - if (const auto it = result_map.find(key); it != result_map.end()) { - return it->second; + if (const auto it = RPCRESULT_MAP.find(key); it != RPCRESULT_MAP.end()) { + const auto& ret{it->second}; + return RPCResult{ret.m_type, ret.m_key_name, optional, ret.m_description, ret.m_inner}; } - throw NonFatalCheckError(strprintf("Requested invalid RPCResult for nonexistent key \"%s\"", key).c_str(), __FILE__, __LINE__, __func__); }