refactor: quorum sign methods

They are separated to own commit because the code move is not trivial to review
This commit is contained in:
Konstantin Akimov 2024-06-11 20:26:08 +07:00
parent 2af9d86654
commit e3c4d66ef3
No known key found for this signature in database
GPG Key ID: 2176C4A5D01EA524

View File

@ -436,12 +436,68 @@ static RPCHelpMan quorum_sign()
}, },
RPCResults{}, RPCResults{},
RPCExamples{""}, RPCExamples{""},
}.Check(request); [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const NodeContext& node = EnsureAnyNodeContext(request.context);
const LLMQContext& llmq_ctx = EnsureLLMQContext(node);
Consensus::LLMQType llmqType = (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");
}
uint256 id(ParseHashV(request.params[1], "id"));
uint256 msgHash(ParseHashV(request.params[2], "msgHash"));
uint256 quorumHash;
if (!request.params[3].isNull() && !request.params[3].get_str().empty()) {
quorumHash = ParseHashV(request.params[3], "quorumHash");
}
bool fSubmit{true};
if (!request.params[4].isNull()) {
fSubmit = ParseBoolV(request.params[4], "submit");
}
if (fSubmit) {
return llmq_ctx.sigman->AsyncSignIfMember(llmqType, *llmq_ctx.shareman, id, msgHash, quorumHash);
} else {
llmq::CQuorumCPtr pQuorum;
if (quorumHash.IsNull()) {
pQuorum = llmq::SelectQuorumForSigning(llmq_params_opt.value(), *llmq_ctx.qman, id);
} else {
pQuorum = llmq_ctx.qman->GetQuorum(llmqType, quorumHash);
}
if (pQuorum == nullptr) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "quorum not found");
}
auto sigShare = llmq_ctx.shareman->CreateSigShare(pQuorum, id, msgHash);
if (!sigShare.has_value() || !sigShare->sigShare.Get().IsValid()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "failed to create sigShare");
}
UniValue obj(UniValue::VOBJ);
obj.pushKV("llmqType", static_cast<uint8_t>(llmqType));
obj.pushKV("quorumHash", sigShare->getQuorumHash().ToString());
obj.pushKV("quorumMember", sigShare->getQuorumMember());
obj.pushKV("id", id.ToString());
obj.pushKV("msgHash", msgHash.ToString());
obj.pushKV("signHash", sigShare->GetSignHash().ToString());
obj.pushKV("signature", sigShare->sigShare.Get().ToString());
return obj;
}
},
};
} }
static void quorum_verify_help(const JSONRPCRequest& request) static RPCHelpMan quorum_verify()
{ {
RPCHelpMan{"quorum verify", return RPCHelpMan{"quorum verify",
"Test if a quorum signature is valid for a request id and a message hash\n", "Test if a quorum signature is valid for a request id and a message hash\n",
{ {
{"llmqType", RPCArg::Type::NUM, RPCArg::Optional::NO, "LLMQ type."}, {"llmqType", RPCArg::Type::NUM, RPCArg::Optional::NO, "LLMQ type."},
@ -457,70 +513,10 @@ static void quorum_verify_help(const JSONRPCRequest& request)
}, },
RPCResults{}, RPCResults{},
RPCExamples{""}, RPCExamples{""},
}.Check(request); [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
}
static void quorum_hasrecsig_help(const JSONRPCRequest& request)
{ {
RPCHelpMan{"quorum hasrecsig", const NodeContext& node = EnsureAnyNodeContext(request.context);
"Test if a valid recovered signature is present\n", const LLMQContext& llmq_ctx = EnsureLLMQContext(node);
{
{"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."},
},
RPCResults{},
RPCExamples{""},
}.Check(request);
}
static void quorum_getrecsig_help(const JSONRPCRequest& request)
{
RPCHelpMan{"quorum getrecsig",
"Get a recovered signature\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."},
},
RPCResults{},
RPCExamples{""},
}.Check(request);
}
static void quorum_isconflicting_help(const JSONRPCRequest& request)
{
RPCHelpMan{"quorum isconflicting",
"Test if a conflict exists\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."},
},
RPCResults{},
RPCExamples{""},
}.Check(request);
}
static UniValue quorum_sigs_cmd(const JSONRPCRequest& request, const LLMQContext& llmq_ctx)
{
auto cmd = request.strMethod;
if (request.fHelp || (request.params.size() != 3)) {
if (cmd == "quorumsign") {
quorum_sign_help(request);
} else if (cmd == "quorumverify") {
quorum_verify_help(request);
} else if (cmd == "quorumhasrecsig") {
quorum_hasrecsig_help(request);
} else if (cmd == "quorumgetrecsig") {
quorum_getrecsig_help(request);
} else if (cmd == "quorumisconflicting") {
quorum_isconflicting_help(request);
} else {
// shouldn't happen as it's already handled by the caller
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid cmd");
}
}
Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[0], "llmqType"); Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[0], "llmqType");
@ -532,91 +528,134 @@ static UniValue quorum_sigs_cmd(const JSONRPCRequest& request, const LLMQContext
uint256 id(ParseHashV(request.params[1], "id")); uint256 id(ParseHashV(request.params[1], "id"));
uint256 msgHash(ParseHashV(request.params[2], "msgHash")); uint256 msgHash(ParseHashV(request.params[2], "msgHash"));
if (cmd == "quorumsign") { const bool use_bls_legacy = bls::bls_legacy_scheme.load();
uint256 quorumHash; CBLSSignature sig;
if (!request.params[3].isNull() && !request.params[3].get_str().empty()) { if (!sig.SetHexStr(request.params[3].get_str(), use_bls_legacy)) {
quorumHash = ParseHashV(request.params[3], "quorumHash"); throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid signature format");
}
bool fSubmit{true};
if (!request.params[4].isNull()) {
fSubmit = ParseBoolV(request.params[4], "submit");
}
if (fSubmit) {
return llmq_ctx.sigman->AsyncSignIfMember(llmqType, *llmq_ctx.shareman, id, msgHash, quorumHash);
} else {
llmq::CQuorumCPtr pQuorum;
if (quorumHash.IsNull()) {
pQuorum = llmq::SelectQuorumForSigning(llmq_params_opt.value(), *llmq_ctx.qman, id);
} else {
pQuorum = llmq_ctx.qman->GetQuorum(llmqType, quorumHash);
}
if (pQuorum == nullptr) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "quorum not found");
}
auto sigShare = llmq_ctx.shareman->CreateSigShare(pQuorum, id, msgHash);
if (!sigShare.has_value() || !sigShare->sigShare.Get().IsValid()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "failed to create sigShare");
}
UniValue obj(UniValue::VOBJ);
obj.pushKV("llmqType", static_cast<uint8_t>(llmqType));
obj.pushKV("quorumHash", sigShare->getQuorumHash().ToString());
obj.pushKV("quorumMember", sigShare->getQuorumMember());
obj.pushKV("id", id.ToString());
obj.pushKV("msgHash", msgHash.ToString());
obj.pushKV("signHash", sigShare->GetSignHash().ToString());
obj.pushKV("signature", sigShare->sigShare.Get().ToString());
return obj;
}
} else if (cmd == "quorumverify") {
const bool use_bls_legacy = bls::bls_legacy_scheme.load();
CBLSSignature sig;
if (!sig.SetHexStr(request.params[3].get_str(), use_bls_legacy)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid signature format");
}
if (request.params[4].isNull() || (request.params[4].get_str().empty() && !request.params[5].isNull())) {
int signHeight{-1};
if (!request.params[5].isNull()) {
signHeight = ParseInt32V(request.params[5], "signHeight");
}
// First check against the current active set, if it fails check against the last active set
int signOffset{llmq_params_opt->dkgInterval};
return llmq::VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, msgHash, sig, 0) ||
llmq::VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, msgHash, sig, signOffset);
} else {
uint256 quorumHash(ParseHashV(request.params[4], "quorumHash"));
llmq::CQuorumCPtr quorum = llmq_ctx.qman->GetQuorum(llmqType, quorumHash);
if (!quorum) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "quorum not found");
}
uint256 signHash = llmq::BuildSignHash(llmqType, quorum->qc->quorumHash, id, msgHash);
return sig.VerifyInsecure(quorum->qc->quorumPublicKey, signHash);
}
} else if (cmd == "quorumhasrecsig") {
return llmq_ctx.sigman->HasRecoveredSig(llmqType, id, msgHash);
} else if (cmd == "quorumgetrecsig") {
llmq::CRecoveredSig recSig;
if (!llmq_ctx.sigman->GetRecoveredSigForId(llmqType, id, recSig)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "recovered signature not found");
}
if (recSig.getMsgHash() != msgHash) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "recovered signature not found");
}
return recSig.ToJson();
} else if (cmd == "quorumisconflicting") {
return llmq_ctx.sigman->IsConflicting(llmqType, id, msgHash);
} else {
// shouldn't happen as it's already handled by the caller
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid cmd");
} }
if (request.params[4].isNull() || (request.params[4].get_str().empty() && !request.params[5].isNull())) {
int signHeight{-1};
if (!request.params[5].isNull()) {
signHeight = ParseInt32V(request.params[5], "signHeight");
}
// First check against the current active set, if it fails check against the last active set
int signOffset{llmq_params_opt->dkgInterval};
return llmq::VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, msgHash, sig, 0) ||
llmq::VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, msgHash, sig, signOffset);
}
uint256 quorumHash(ParseHashV(request.params[4], "quorumHash"));
llmq::CQuorumCPtr quorum = llmq_ctx.qman->GetQuorum(llmqType, quorumHash);
if (!quorum) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "quorum not found");
}
uint256 signHash = llmq::BuildSignHash(llmqType, quorum->qc->quorumHash, id, msgHash);
return sig.VerifyInsecure(quorum->qc->quorumPublicKey, signHash);
},
};
}
static RPCHelpMan quorum_hasrecsig()
{
return RPCHelpMan{"quorum hasrecsig",
"Test if a valid recovered signature is present\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."},
},
RPCResults{},
RPCExamples{""},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const NodeContext& node = EnsureAnyNodeContext(request.context);
const LLMQContext& llmq_ctx = EnsureLLMQContext(node);
Consensus::LLMQType llmqType = (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");
}
uint256 id(ParseHashV(request.params[1], "id"));
uint256 msgHash(ParseHashV(request.params[2], "msgHash"));
return llmq_ctx.sigman->HasRecoveredSig(llmqType, id, msgHash);
},
};
}
static RPCHelpMan quorum_getrecsig()
{
return RPCHelpMan{"quorum getrecsig",
"Get a recovered signature\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."},
},
RPCResults{},
RPCExamples{""},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const NodeContext& node = EnsureAnyNodeContext(request.context);
const LLMQContext& llmq_ctx = EnsureLLMQContext(node);
Consensus::LLMQType llmqType = (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");
}
uint256 id(ParseHashV(request.params[1], "id"));
uint256 msgHash(ParseHashV(request.params[2], "msgHash"));
llmq::CRecoveredSig recSig;
if (!llmq_ctx.sigman->GetRecoveredSigForId(llmqType, id, recSig)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "recovered signature not found");
}
if (recSig.getMsgHash() != msgHash) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "recovered signature not found");
}
return recSig.ToJson();
},
};
}
static RPCHelpMan quorum_isconflicting()
{
return RPCHelpMan{"quorum isconflicting",
"Test if a conflict exists\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."},
},
RPCResults{},
RPCExamples{""},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const NodeContext& node = EnsureAnyNodeContext(request.context);
const LLMQContext& llmq_ctx = EnsureLLMQContext(node);
Consensus::LLMQType llmqType = (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");
}
uint256 id(ParseHashV(request.params[1], "id"));
uint256 msgHash(ParseHashV(request.params[2], "msgHash"));
return llmq_ctx.sigman->IsConflicting(llmqType, id, msgHash);
},
};
} }
static RPCHelpMan quorum_selectquorum() static RPCHelpMan quorum_selectquorum()