Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions doc/release-notes-6106.md
Original file line number Diff line number Diff line change
@@ -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 <platform type>`.

77 changes: 55 additions & 22 deletions src/rpc/quorums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Consensus::LLMQType>(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);
Expand Down Expand Up @@ -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<Consensus::LLMQType>(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);
},
};
}
Expand Down Expand Up @@ -1096,6 +1128,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"} },
Expand Down
2 changes: 1 addition & 1 deletion test/functional/feature_asset_locks.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def create_assetunlock(self, index, withdrawal, pubkey=None, fee=tiny_amount):
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()
Expand Down
7 changes: 5 additions & 2 deletions test/functional/test_framework/test_framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -2033,13 +2033,16 @@ def check_recovered_sig():
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:
Expand Down