From 5809c5c3d017b301b9fba96462d25ae669b4d981 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Thu, 27 Jun 2019 22:25:59 +0200 Subject: [PATCH] Implement "quorum memberof" (#3004) * Implement BuildQuorumInfo and call it from quorum_info * Add type to result of BuildQuorumInfo * Implement "quorum memberof" --- src/rpc/rpcquorums.cpp | 121 +++++++++++++++++++++++++++++++---------- 1 file changed, 92 insertions(+), 29 deletions(-) diff --git a/src/rpc/rpcquorums.cpp b/src/rpc/rpcquorums.cpp index 66218aab0..4cfd5caf2 100644 --- a/src/rpc/rpcquorums.cpp +++ b/src/rpc/rpcquorums.cpp @@ -76,6 +76,41 @@ void quorum_info_help() ); } +UniValue BuildQuorumInfo(const llmq::CQuorumCPtr& quorum, bool includeMembers, bool includeSkShare) +{ + UniValue ret(UniValue::VOBJ); + + ret.push_back(Pair("height", quorum->height)); + ret.push_back(Pair("type", quorum->params.name)); + ret.push_back(Pair("quorumHash", quorum->qc.quorumHash.ToString())); + ret.push_back(Pair("minedBlock", quorum->minedBlockHash.ToString())); + + if (includeMembers) { + UniValue membersArr(UniValue::VARR); + for (size_t i = 0; i < quorum->members.size(); i++) { + auto& dmn = quorum->members[i]; + UniValue mo(UniValue::VOBJ); + mo.push_back(Pair("proTxHash", dmn->proTxHash.ToString())); + mo.push_back(Pair("valid", quorum->qc.validMembers[i])); + if (quorum->qc.validMembers[i]) { + CBLSPublicKey pubKey = quorum->GetPubKeyShare(i); + if (pubKey.IsValid()) { + mo.push_back(Pair("pubKeyShare", pubKey.ToString())); + } + } + membersArr.push_back(mo); + } + + ret.push_back(Pair("members", membersArr)); + } + ret.push_back(Pair("quorumPublicKey", quorum->qc.quorumPublicKey.ToString())); + CBLSSecretKey skShare = quorum->GetSkShare(); + if (includeSkShare && skShare.IsValid()) { + ret.push_back(Pair("secretKeyShare", skShare.ToString())); + } + return ret; +} + UniValue quorum_info(const JSONRPCRequest& request) { if (request.fHelp || (request.params.size() != 3 && request.params.size() != 4)) @@ -101,35 +136,7 @@ UniValue quorum_info(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, "quorum not found"); } - UniValue ret(UniValue::VOBJ); - - ret.push_back(Pair("height", quorum->height)); - ret.push_back(Pair("quorumHash", quorum->qc.quorumHash.ToString())); - ret.push_back(Pair("minedBlock", quorum->minedBlockHash.ToString())); - - UniValue membersArr(UniValue::VARR); - for (size_t i = 0; i < quorum->members.size(); i++) { - auto& dmn = quorum->members[i]; - UniValue mo(UniValue::VOBJ); - mo.push_back(Pair("proTxHash", dmn->proTxHash.ToString())); - mo.push_back(Pair("valid", quorum->qc.validMembers[i])); - if (quorum->qc.validMembers[i]) { - CBLSPublicKey pubKey = quorum->GetPubKeyShare(i); - if (pubKey.IsValid()) { - mo.push_back(Pair("pubKeyShare", pubKey.ToString())); - } - } - membersArr.push_back(mo); - } - - ret.push_back(Pair("members", membersArr)); - ret.push_back(Pair("quorumPublicKey", quorum->qc.quorumPublicKey.ToString())); - CBLSSecretKey skShare = quorum->GetSkShare(); - if (includeSkShare && skShare.IsValid()) { - ret.push_back(Pair("secretKeyShare", skShare.ToString())); - } - - return ret; + return BuildQuorumInfo(quorum, true, includeSkShare); } void quorum_dkgstatus_help() @@ -182,6 +189,59 @@ UniValue quorum_dkgstatus(const JSONRPCRequest& request) return ret; } +void quorum_memberof_help() +{ + throw std::runtime_error( + "quorum memberof \"proTxHash\"\n" + "Checks which quorums the given masternode is a member of.\n" + "\nArguments:\n" + "1. \"proTxHash\" (string, required) ProTxHash of the masternode.\n" + ); +} + +UniValue quorum_memberof(const JSONRPCRequest& request) +{ + if (request.fHelp || (request.params.size() != 2)) { + quorum_memberof_help(); + } + + uint256 protxHash = ParseHashV(request.params[1], "proTxHash"); + + const CBlockIndex* pindexTip; + { + LOCK(cs_main); + pindexTip = chainActive.Tip(); + } + + auto mnList = deterministicMNManager->GetListForBlock(pindexTip->GetBlockHash()); + auto dmn = mnList.GetMN(protxHash); + if (!dmn) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "masternode not found"); + } + + std::set> quorumHashes; + for (const auto& p : Params().GetConsensus().llmqs) { + auto& params = p.second; + auto quorums = llmq::quorumManager->ScanQuorums(params.type, params.signingActiveQuorumCount); + for (auto& quorum : quorums) { + for (auto& m : quorum->members) { + if (m->proTxHash == dmn->proTxHash) { + quorumHashes.emplace(params.type, quorum->qc.quorumHash); + } + } + } + } + + UniValue result(UniValue::VARR); + for (auto& p : quorumHashes) { + auto quorum = llmq::quorumManager->GetQuorum(p.first, p.second); + assert(quorum); + result.push_back(BuildQuorumInfo(quorum, false, false)); + } + + return result; +} + void quorum_sign_help() { throw std::runtime_error( @@ -318,6 +378,7 @@ UniValue quorum_dkgsimerror(const JSONRPCRequest& request) " info - Return information about a quorum\n" " dkgsimerror - Simulates DKG errors and malicious behavior.\n" " dkgstatus - Return the status of the current DKG process\n" + " memberof - Checks which quorums the given masternode is a member of\n" " sign - Threshold-sign a message\n" " hasrecsig - Test if a valid recovered signature is present\n" " getrecsig - Get a recovered signature\n" @@ -342,6 +403,8 @@ UniValue quorum(const JSONRPCRequest& request) return quorum_info(request); } else if (command == "dkgstatus") { return quorum_dkgstatus(request); + } else if (command == "memberof") { + return quorum_memberof(request); } else if (command == "sign" || command == "hasrecsig" || command == "getrecsig" || command == "isconflicting") { return quorum_sigs_cmd(request); } else if (command == "dkgsimerror") {