From db828177bf315cad8efb0f8f65d31b81b190617d Mon Sep 17 00:00:00 2001 From: pasta Date: Mon, 15 Jul 2024 11:47:39 -0500 Subject: [PATCH] Merge #6106: feat: create new composite quorum-command platformsign 2db69d7b8115f075092563fe67c486fbd6a86836 chore: add release notes for "quorum platformsign" (Konstantin Akimov) 283c5f89a2d8cce91d85b5aeeca0e93fcb159430 feat: create new composite command "quorum platformsign" (Konstantin Akimov) Pull request description: ## Issue being fixed or feature implemented It splits from #6100 With just whitelist it is impossible to limit the RPC `quorum sign` to use only one specific quorum type, this PR aim to provide ability for quorum signing for platform quorum only. ## What was done? Implemented a new composite command "quorum platformsign" This composite command let to limit quorum type for signing for case of whitelist. After that old way to limit platform commands can be deprecated - #6105 ## How Has This Been Tested? Updated a functional tests to use platform signing for Asset Unlocks feature. ## Breaking Changes N/A ## Checklist: - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone ACKs for top commit: UdjinM6: utACK 2db69d7b8115f075092563fe67c486fbd6a86836 PastaPastaPasta: utACK 2db69d7b8115f075092563fe67c486fbd6a86836 Tree-SHA512: b0dff9934137c4faa85664058e1e77f85067cc8d931e6d76ee5b9e610164ac8b0609736d5f09475256cb78d65bf92466624d784f0b13d20136df7e75613662cb --- doc/release-notes-6106.md | 6 ++ src/rpc/quorums.cpp | 77 +++++++++++++------ test/functional/feature_asset_locks.py | 2 +- .../test_framework/test_framework.py | 7 +- 4 files changed, 67 insertions(+), 25 deletions(-) create mode 100644 doc/release-notes-6106.md diff --git a/doc/release-notes-6106.md b/doc/release-notes-6106.md new file mode 100644 index 0000000000..b161888a9b --- /dev/null +++ b/doc/release-notes-6106.md @@ -0,0 +1,6 @@ +## Remote Procedure Call (RPC) Changes + +### The new RPCs are: + +- `quorum signplatform` This RPC is added for Platform needs. This composite command let to limit quorum type for signing by platform. It is equivalent of `quorum sign `. + diff --git a/src/rpc/quorums.cpp b/src/rpc/quorums.cpp index 7b523541ba..ee6c990391 100644 --- a/src/rpc/quorums.cpp +++ b/src/rpc/quorums.cpp @@ -427,42 +427,27 @@ static RPCHelpMan quorum_memberof() }; } -static RPCHelpMan quorum_sign() -{ - return RPCHelpMan{"quorum sign", - "Threshold-sign a message\n", - { - {"llmqType", RPCArg::Type::NUM, RPCArg::Optional::NO, "LLMQ type."}, - {"id", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Request id."}, - {"msgHash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Message hash."}, - {"quorumHash", RPCArg::Type::STR_HEX, /* default */ "", "The quorum identifier."}, - {"submit", RPCArg::Type::BOOL, /* default */ "true", "Submits the signature share to the network if this is true. " - "Returns an object containing the signature share if this is false."}, - }, - RPCResults{}, - RPCExamples{""}, - [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +static UniValue quorum_sign_helper(const JSONRPCRequest& request, Consensus::LLMQType llmqType) { const NodeContext& node = EnsureAnyNodeContext(request.context); const ChainstateManager& chainman = EnsureChainman(node); const LLMQContext& llmq_ctx = EnsureLLMQContext(node); - const Consensus::LLMQType llmqType{static_cast(ParseInt32V(request.params[0], "llmqType"))}; const auto llmq_params_opt = Params().GetLLMQ(llmqType); if (!llmq_params_opt.has_value()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type"); } - const uint256 id(ParseHashV(request.params[1], "id")); - const uint256 msgHash(ParseHashV(request.params[2], "msgHash")); + const uint256 id(ParseHashV(request.params[0], "id")); + const uint256 msgHash(ParseHashV(request.params[1], "msgHash")); uint256 quorumHash; - if (!request.params[3].isNull() && !request.params[3].get_str().empty()) { - quorumHash = ParseHashV(request.params[3], "quorumHash"); + if (!request.params[2].isNull() && !request.params[2].get_str().empty()) { + quorumHash = ParseHashV(request.params[2], "quorumHash"); } bool fSubmit{true}; - if (!request.params[4].isNull()) { - fSubmit = ParseBoolV(request.params[4], "submit"); + if (!request.params[3].isNull()) { + fSubmit = ParseBoolV(request.params[3], "submit"); } if (fSubmit) { return llmq_ctx.sigman->AsyncSignIfMember(llmqType, *llmq_ctx.shareman, id, msgHash, quorumHash); @@ -496,6 +481,53 @@ static RPCHelpMan quorum_sign() return obj; } +} + +static RPCHelpMan quorum_sign() +{ + return RPCHelpMan{"quorum sign", + "Threshold-sign a message\n", + { + {"llmqType", RPCArg::Type::NUM, RPCArg::Optional::NO, "LLMQ type."}, + {"id", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Request id."}, + {"msgHash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Message hash."}, + {"quorumHash", RPCArg::Type::STR_HEX, /* default */ "", "The quorum identifier."}, + {"submit", RPCArg::Type::BOOL, /* default */ "true", "Submits the signature share to the network if this is true. " + "Returns an object containing the signature share if this is false."}, + }, + RPCResults{}, + RPCExamples{""}, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + const Consensus::LLMQType llmqType{static_cast(ParseInt32V(request.params[0], "llmqType"))}; + + JSONRPCRequest new_request{request}; + new_request.params.setArray(); + for (unsigned int i = 1; i < request.params.size(); ++i) { + new_request.params.push_back(request.params[i]); + } + return quorum_sign_helper(new_request, llmqType); +}, + }; +} + +static RPCHelpMan quorum_platformsign() +{ + return RPCHelpMan{"quorum platformsign", + "Threshold-sign a message. It signs messages only for platform quorums\n", + { + {"id", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Request id."}, + {"msgHash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Message hash."}, + {"quorumHash", RPCArg::Type::STR_HEX, /* default */ "", "The quorum identifier."}, + {"submit", RPCArg::Type::BOOL, /* default */ "true", "Submits the signature share to the network if this is true. " + "Returns an object containing the signature share if this is false."}, + }, + RPCResults{}, + RPCExamples{""}, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + const Consensus::LLMQType llmqType{Params().GetConsensus().llmqTypePlatform}; + return quorum_sign_helper(request, llmqType); }, }; } @@ -1110,6 +1142,7 @@ static const CRPCCommand commands[] = { "evo", "quorum", "dkgstatus", &quorum_dkgstatus, {"detail_level"} }, { "evo", "quorum", "memberof", &quorum_memberof, {"proTxHash", "scanQuorumsCount"} }, { "evo", "quorum", "sign", &quorum_sign, {"llmqType", "id", "msgHash", "quorumHash", "submit"} }, + { "evo", "quorum", "platformsign", &quorum_platformsign, {"id", "msgHash", "quorumHash", "submit"} }, { "evo", "quorum", "verify", &quorum_verify, {"llmqType", "id", "msgHash", "signature", "quorumHash", "signHeight"} }, { "evo", "quorum", "hasrecsig", &quorum_hasrecsig, {"llmqType", "id", "msgHash"} }, { "evo", "quorum", "getrecsig", &quorum_getrecsig, {"llmqType", "id", "msgHash"} }, diff --git a/test/functional/feature_asset_locks.py b/test/functional/feature_asset_locks.py index 45a80fc152..c4a1b030be 100755 --- a/test/functional/feature_asset_locks.py +++ b/test/functional/feature_asset_locks.py @@ -119,7 +119,7 @@ class AssetLocksTest(DashTestFramework): unlock_tx.calc_sha256() msgHash = format(unlock_tx.sha256, '064x') - recsig = self.get_recovered_sig(request_id, msgHash, llmq_type=llmq_type_test) + recsig = self.get_recovered_sig(request_id, msgHash, llmq_type=llmq_type_test, use_platformsign=True) unlockTx_payload.quorumSig = bytearray.fromhex(recsig["sig"]) unlock_tx.vExtraPayload = unlockTx_payload.serialize() diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index f0a9f974db..f419f58d0c 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -2033,13 +2033,16 @@ class DashTestFramework(BitcoinTestFramework): return True wait_until_helper(check_recovered_sig, timeout=timeout, sleep=1) - def get_recovered_sig(self, rec_sig_id, rec_sig_msg_hash, llmq_type=100): + def get_recovered_sig(self, rec_sig_id, rec_sig_msg_hash, llmq_type=100, use_platformsign=False): # Note: recsigs aren't relayed to regular nodes by default, # make sure to pick a mn as a node to query for recsigs. try: quorumHash = self.mninfo[0].node.quorum("selectquorum", llmq_type, rec_sig_id)["quorumHash"] for mn in self.mninfo: - mn.node.quorum("sign", llmq_type, rec_sig_id, rec_sig_msg_hash, quorumHash) + if use_platformsign: + mn.node.quorum("platformsign", rec_sig_id, rec_sig_msg_hash, quorumHash) + else: + mn.node.quorum("sign", llmq_type, rec_sig_id, rec_sig_msg_hash, quorumHash) self.wait_for_recovered_sig(rec_sig_id, rec_sig_msg_hash, llmq_type, 10) return self.mninfo[0].node.quorum("getrecsig", llmq_type, rec_sig_id, rec_sig_msg_hash) except JSONRPCException as e: