feat(rpc): quorum dkginfo rpc (#5853)

## Issue being fixed or feature implemented
Dashmate wanted a way to know if it is safe to restart the masternode.
This new RPC indicates the number of active DKG sessions, and the number
of blocks until next potential DKG.

## What was done?
Examples of responses:
`{'active_dkgs': 0, 'next_dkg': 22}`

## How Has This Been Tested?
`feature_llmq_rotation.py` was updated

## Breaking Changes
no

## Checklist:
- [x] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [x] I have added or updated relevant unit/integration/functional/e2e
tests
- [x] I have made corresponding changes to the documentation
- [x] I have assigned this pull request to a milestone _(for repository
code-owners and collaborators only)_

---------

Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
This commit is contained in:
Odysseas Gabrielides 2024-02-01 17:17:40 +02:00 committed by GitHub
parent 82310b0984
commit f5b7aa0802
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 71 additions and 0 deletions

View File

@ -0,0 +1,6 @@
Added RPC
--------
- `quorum dkginfo` RPC returns information about DKGs:
- `active_dkgs`: Total number of active DKG sessions this node is participating in right now.
- `next_dkg`: The number of blocks until the next potential DKG session.

View File

@ -789,6 +789,49 @@ static UniValue quorum_rotationinfo(const JSONRPCRequest& request, const LLMQCon
return quorumRotationInfoRet.ToJson(); return quorumRotationInfoRet.ToJson();
} }
static void quorum_dkginfo_help(const JSONRPCRequest& request)
{
RPCHelpMan{
"quorum dkginfo",
"Return information regarding DKGs.\n",
{
{},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::NUM, "active_dkgs", "Total number of active DKG sessions this node is participating in right now"},
{RPCResult::Type::NUM, "next_dkg", "The number of blocks until the next potential DKG session"},
}
},
RPCExamples{""},
}.Check(request);
}
static UniValue quorum_dkginfo(const JSONRPCRequest& request, const LLMQContext& llmq_ctx, const ChainstateManager& chainman)
{
quorum_dkginfo_help(request);
llmq::CDKGDebugStatus status;
llmq_ctx.dkg_debugman->GetLocalDebugStatus(status);
UniValue ret(UniValue::VOBJ);
ret.pushKV("active_dkgs", int(status.sessions.size()));
const int nTipHeight{WITH_LOCK(cs_main, return chainman.ActiveChain().Height())};
auto minNextDKG = [](const Consensus::Params& consensusParams, int nTipHeight) {
int minDkgWindow{std::numeric_limits<int>::max()};
for (const auto& params: consensusParams.llmqs) {
if (params.useRotation && (nTipHeight % params.dkgInterval <= params.signingActiveQuorumCount)) {
return 1;
}
minDkgWindow = std::min(minDkgWindow, params.dkgInterval - (nTipHeight % params.dkgInterval));
}
return minDkgWindow;
};
ret.pushKV("next_dkg", minNextDKG(Params().GetConsensus(), nTipHeight));
return ret;
}
[[ noreturn ]] static void quorum_help() [[ noreturn ]] static void quorum_help()
{ {
@ -801,6 +844,7 @@ static UniValue quorum_rotationinfo(const JSONRPCRequest& request, const LLMQCon
" list - List of on-chain quorums\n" " list - List of on-chain quorums\n"
" listextended - Extended list of on-chain quorums\n" " listextended - Extended list of on-chain quorums\n"
" info - Return information about a quorum\n" " info - Return information about a quorum\n"
" dkginfo - Return information about DKGs\n"
" dkgsimerror - Simulates DKG errors and malicious behavior\n" " dkgsimerror - Simulates DKG errors and malicious behavior\n"
" dkgstatus - Return the status of the current DKG process\n" " dkgstatus - Return the status of the current DKG process\n"
" memberof - Checks which quorums the given masternode is a member of\n" " memberof - Checks which quorums the given masternode is a member of\n"
@ -836,6 +880,8 @@ static UniValue _quorum(const JSONRPCRequest& request)
return quorum_list_extended(new_request, chainman, llmq_ctx); return quorum_list_extended(new_request, chainman, llmq_ctx);
} else if (command == "quoruminfo") { } else if (command == "quoruminfo") {
return quorum_info(new_request, llmq_ctx); return quorum_info(new_request, llmq_ctx);
} else if (command == "quorumdkginfo") {
return quorum_dkginfo(new_request, llmq_ctx, chainman);
} else if (command == "quorumdkgstatus") { } else if (command == "quorumdkgstatus") {
return quorum_dkgstatus(new_request, chainman, llmq_ctx); return quorum_dkgstatus(new_request, chainman, llmq_ctx);
} else if (command == "quorummemberof") { } else if (command == "quorummemberof") {

View File

@ -76,6 +76,13 @@ class LLMQQuorumRotationTest(DashTestFramework):
b_h_0 = self.nodes[0].getbestblockhash() b_h_0 = self.nodes[0].getbestblockhash()
tip = self.nodes[0].getblockcount()
next_dkg = 24 - (tip % 24)
for node in self.nodes:
dkg_info = node.quorum("dkginfo")
assert_equal(dkg_info['active_dkgs'], 0)
assert_equal(dkg_info['next_dkg'], next_dkg)
#Mine 2 quorums so that Chainlocks can be available: Need them to include CL in CbTx as soon as v20 activates #Mine 2 quorums so that Chainlocks can be available: Need them to include CL in CbTx as soon as v20 activates
self.log.info("Mining 2 quorums") self.log.info("Mining 2 quorums")
h_0 = self.mine_quorum() h_0 = self.mine_quorum()
@ -93,6 +100,18 @@ class LLMQQuorumRotationTest(DashTestFramework):
b_h_1 = self.nodes[0].getbestblockhash() b_h_1 = self.nodes[0].getbestblockhash()
tip = self.nodes[0].getblockcount()
next_dkg = 24 - (tip % 24)
assert next_dkg < 24
nonzero_dkgs = 0
for i in range(len(self.nodes)):
dkg_info = self.nodes[i].quorum("dkginfo")
if i == 0:
assert_equal(dkg_info['active_dkgs'], 0)
nonzero_dkgs += dkg_info['active_dkgs']
assert_equal(dkg_info['next_dkg'], next_dkg)
assert_equal(nonzero_dkgs, 11) # 2 quorums 4 nodes each and 1 quorum of 3 nodes
expectedDeleted = [] expectedDeleted = []
expectedNew = [h_100_0, h_106_0, h_104_0, h_100_1, h_106_1, h_104_1] expectedNew = [h_100_0, h_106_0, h_104_0, h_100_1, h_106_1, h_104_1]
quorumList = self.test_getmnlistdiff_quorums(b_h_0, b_h_1, {}, expectedDeleted, expectedNew, testQuorumsCLSigs=False) quorumList = self.test_getmnlistdiff_quorums(b_h_0, b_h_1, {}, expectedDeleted, expectedNew, testQuorumsCLSigs=False)