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/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/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 574910214294..4e83e8bc4630 100644 --- a/src/evo/core_write.cpp +++ b/src/evo/core_write.cpp @@ -2,11 +2,10 @@ // 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 #include @@ -15,9 +14,90 @@ #include #include +#include +#include +#include +#include + #include -[[nodiscard]] UniValue CAssetLockPayload::ToJson() const +#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) +{ + 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__); +} + +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'"}, + }}}}}} + }}; +} + +UniValue CAssetLockPayload::ToJson() const { UniValue outputs(UniValue::VARR); for (const CTxOut& credit_output : creditOutputs) { @@ -36,7 +116,20 @@ return ret; } -[[nodiscard]] UniValue CAssetUnlockPayload::ToJson() const +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"), + GetRpcResult("quorumSig"), + }}; +} + +UniValue CAssetUnlockPayload::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -48,7 +141,21 @@ return ret; } -[[nodiscard]] UniValue CCbTx::ToJson() const +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"}, + }}; +} + +UniValue CCbTx::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", ToUnderlying(nVersion)); @@ -65,7 +172,127 @@ return ret; } -[[nodiscard]] UniValue CProRegTx::ToJson() const +// CDeterministicMN::ToJson() defined in evo/deterministicmns.cpp +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), + }}; +} + +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), + }}; +} + +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; +} + +// CDeterministicMNStateDiff::ToJson() defined in evo/dmnstate.cpp +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), + }}; +} + +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"), + GetRpcResult("collateralHash"), + GetRpcResult("collateralIndex"), + GetRpcResult("service"), + GetRpcResult("addresses"), + GetRpcResult("ownerAddress"), + GetRpcResult("votingAddress"), + GetRpcResult("payoutAddress", /*optional=*/true), + GetRpcResult("pubKeyOperator"), + GetRpcResult("operatorReward"), + GetRpcResult("platformNodeID", /*optional=*/true), + GetRpcResult("platformP2PPort", /*optional=*/true), + GetRpcResult("platformHTTPPort", /*optional=*/true), + GetRpcResult("inputsHash"), + }}; +} + +UniValue CProRegTx::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -90,7 +317,20 @@ return ret; } -[[nodiscard]] UniValue CProUpRegTx::ToJson() const +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"), + }}; +} + +UniValue CProUpRegTx::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -104,7 +344,18 @@ return ret; } -[[nodiscard]] UniValue CProUpRevTx::ToJson() const +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), + }}; +} + +UniValue CProUpRevTx::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -114,7 +365,24 @@ return ret; } -[[nodiscard]] UniValue CProUpServTx::ToJson() const +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"), + }}; +} + +UniValue CProUpServTx::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -134,53 +402,37 @@ return ret; } -[[nodiscard]] UniValue MNHFTxPayload::ToJson() const -{ - UniValue ret(UniValue::VOBJ); - ret.pushKV("version", nVersion); - ret.pushKV("signal", signal.ToJson()); - return ret; -} - -[[nodiscard]] UniValue llmq::CFinalCommitmentTxPayload::ToJson() const +RPCResult CSimplifiedMNListDiff::GetJsonHelp(const std::string& key, bool optional) { - UniValue ret(UniValue::VOBJ); - ret.pushKV("version", nVersion); - ret.pushKV("height", nHeight); - ret.pushKV("commitment", commitment.ToJson()); - return ret; -} - -[[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; + 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, "", "", { + GetRpcResult("llmqType"), + GetRpcResult("quorumHash"), + }}}}, + {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", { + {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 CSimplifiedMNListDiff::ToJson(bool extended) const { UniValue obj(UniValue::VOBJ); @@ -242,3 +494,88 @@ obj.pushKV("quorumsCLSigs", quorumsCLSigsArr); return obj; } + +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), + }}; +} + +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; +} + +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"}, + }}; +} + +UniValue MNHFTx::ToJson() const +{ + UniValue obj(UniValue::VOBJ); + obj.pushKV("versionBit", versionBit); + obj.pushKV("quorumHash", quorumHash.ToString()); + obj.pushKV("sig", sig.ToString()); + return obj; +} + +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), + }}; +} + +UniValue MNHFTxPayload::ToJson() const +{ + UniValue ret(UniValue::VOBJ); + ret.pushKV("version", nVersion); + ret.pushKV("signal", signal.ToJson()); + return ret; +} 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.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/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/evo/mnhftx.h b/src/evo/mnhftx.h index 8adda3655368..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,14 +51,8 @@ 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]] static RPCResult GetJsonHelp(const std::string& key, bool optional); + [[nodiscard]] UniValue ToJson() const; }; class MNHFTxPayload @@ -87,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/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/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..60cf499d5a2a 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 @@ -130,23 +130,8 @@ 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]] static RPCResult GetJsonHelp(const std::string& key, bool optional); + [[nodiscard]] UniValue ToJson() const; private: static std::string BitsVectorToHexStr(const std::vector& vBits) @@ -175,6 +160,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/llmq/core_write.cpp b/src/llmq/core_write.cpp new file mode 100644 index 000000000000..5ffe3c46f956 --- /dev/null +++ b/src/llmq/core_write.cpp @@ -0,0 +1,200 @@ +// 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 { +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"}, + }}; +} + +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; +} + +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"), + CFinalCommitment::GetJsonHelp(/*key=*/"commitment", /*optional=*/false), + }}; +} + +UniValue CFinalCommitmentTxPayload::ToJson() const +{ + UniValue ret(UniValue::VOBJ); + ret.pushKV("version", nVersion); + ret.pushKV("height", nHeight); + ret.pushKV("commitment", commitment.ToJson()); + return ret; +} + +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), + }}, + }}; +} + +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; +} + +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", ""} + }}, + }}; +} + +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; +} + +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"}, + }}; +} + +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..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,7 +108,8 @@ class CRecoveredSig : virtual public CSigBase return hash; } - UniValue ToJson() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); + [[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, 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/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..3e0dcc641636 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 { @@ -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()); 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 { diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 48869e1f27df..77de92f39f67 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,23 @@ #include #include #include -#include #include +#include #include +#include +#include +#include #include -#include #include +#include +#include #include +#include +#include +#include #include -#include #include @@ -168,6 +172,15 @@ 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), + 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), }; }