Implement debugging messages and RPC for LLMQ DKGs

This commit is contained in:
Alexander Block 2019-01-08 09:55:19 +01:00
parent 098b094959
commit 324406bfed
12 changed files with 706 additions and 1 deletions

View File

@ -143,6 +143,7 @@ BITCOIN_CORE_H = \
limitedmap.h \ limitedmap.h \
llmq/quorums_blockprocessor.h \ llmq/quorums_blockprocessor.h \
llmq/quorums_commitment.h \ llmq/quorums_commitment.h \
llmq/quorums_debug.h \
llmq/quorums_dkgsessionhandler.h \ llmq/quorums_dkgsessionhandler.h \
llmq/quorums_dkgsessionmgr.h \ llmq/quorums_dkgsessionmgr.h \
llmq/quorums_dkgsession.h \ llmq/quorums_dkgsession.h \
@ -254,6 +255,7 @@ libdash_server_a_SOURCES = \
governance-votedb.cpp \ governance-votedb.cpp \
llmq/quorums_blockprocessor.cpp \ llmq/quorums_blockprocessor.cpp \
llmq/quorums_commitment.cpp \ llmq/quorums_commitment.cpp \
llmq/quorums_debug.cpp \
llmq/quorums_dkgsessionhandler.cpp \ llmq/quorums_dkgsessionhandler.cpp \
llmq/quorums_dkgsessionmgr.cpp \ llmq/quorums_dkgsessionmgr.cpp \
llmq/quorums_dkgsession.cpp \ llmq/quorums_dkgsession.cpp \
@ -284,6 +286,7 @@ libdash_server_a_SOURCES = \
rpc/net.cpp \ rpc/net.cpp \
rpc/rawtransaction.cpp \ rpc/rawtransaction.cpp \
rpc/rpcevo.cpp \ rpc/rpcevo.cpp \
rpc/rpcquorums.cpp \
rpc/server.cpp \ rpc/server.cpp \
script/sigcache.cpp \ script/sigcache.cpp \
script/ismine.cpp \ script/ismine.cpp \

347
src/llmq/quorums_debug.cpp Normal file
View File

@ -0,0 +1,347 @@
// Copyright (c) 2018 The Dash Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "quorums_debug.h"
#include "activemasternode.h"
#include "chainparams.h"
#include "net.h"
#include "net_processing.h"
#include "scheduler.h"
#include "validation.h"
#include "evo/deterministicmns.h"
#include "quorums_utils.h"
namespace llmq
{
CDKGDebugManager* quorumDKGDebugManager;
UniValue CDKGDebugSessionStatus::ToJson(int detailLevel) const
{
UniValue ret(UniValue::VOBJ);
if (!Params().GetConsensus().llmqs.count((Consensus::LLMQType)llmqType) || quorumHash.IsNull()) {
return ret;
}
std::vector<CDeterministicMNCPtr> dmnMembers;
if (detailLevel == 2) {
dmnMembers = CLLMQUtils::GetAllQuorumMembers((Consensus::LLMQType) llmqType, quorumHash);
}
ret.push_back(Pair("llmqType", llmqType));
ret.push_back(Pair("quorumHash", quorumHash.ToString()));
ret.push_back(Pair("quorumHeight", (int)quorumHeight));
ret.push_back(Pair("phase", (int)phase));
ret.push_back(Pair("sentContributions", sentContributions));
ret.push_back(Pair("sentComplaint", sentComplaint));
ret.push_back(Pair("sentJustification", sentJustification));
ret.push_back(Pair("sentPrematureCommitment", sentPrematureCommitment));
ret.push_back(Pair("aborted", aborted));
struct ArrOrCount {
int count{0};
UniValue arr{UniValue::VARR};
};
ArrOrCount badMembers;
ArrOrCount weComplain;
ArrOrCount receivedContributions;
ArrOrCount receivedComplaints;
ArrOrCount receivedJustifications;
ArrOrCount receivedPrematureCommitments;
ArrOrCount complaintsFromMembers;
auto add = [&](ArrOrCount& v, size_t idx, bool flag) {
if (flag) {
if (detailLevel == 0) {
v.count++;
} else if (detailLevel == 1) {
v.arr.push_back((int)idx);
} else if (detailLevel == 2) {
UniValue a(UniValue::VOBJ);
a.push_back(Pair("memberIndex", idx));
if (idx < dmnMembers.size()) {
a.push_back(Pair("proTxHash", dmnMembers[idx]->proTxHash.ToString()));
}
v.arr.push_back(a);
}
}
};
auto push = [&](ArrOrCount& v, const std::string& name) {
if (detailLevel == 0) {
ret.push_back(Pair(name, v.count));
} else {
ret.push_back(Pair(name, v.arr));
}
};
for (size_t i = 0; i < members.size(); i++) {
const auto& m = members[i];
add(badMembers, i, m.bad);
add(weComplain, i, m.weComplain);
add(receivedContributions, i, m.receivedContribution);
add(receivedComplaints, i, m.receivedComplaint);
add(receivedJustifications, i, m.receivedJustification);
add(receivedPrematureCommitments, i, m.receivedPrematureCommitment);
}
push(badMembers, "badMembers");
push(weComplain, "weComplain");
push(receivedContributions, "receivedContributions");
push(receivedComplaints, "receivedComplaints");
push(receivedJustifications, "receivedJustifications");
push(receivedPrematureCommitments, "receivedPrematureCommitments");
if (detailLevel == 2) {
UniValue arr(UniValue::VARR);
for (const auto& dmn : dmnMembers) {
arr.push_back(dmn->proTxHash.ToString());
}
ret.push_back(Pair("allMembers", arr));
}
return ret;
}
CDKGDebugManager::CDKGDebugManager(CScheduler* scheduler)
{
for (const auto& p : Params().GetConsensus().llmqs) {
ResetLocalSessionStatus(p.first, uint256(), 0);
}
if (scheduler) {
scheduler->scheduleEvery([&]() {
SendLocalStatus();
}, 10);
}
}
void CDKGDebugManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
{
if (strCommand == NetMsgType::QDEBUGSTATUS) {
CDKGDebugStatus status;
vRecv >> status;
{
LOCK(cs_main);
connman.RemoveAskFor(::SerializeHash(status));
}
ProcessDebugStatusMessage(pfrom->id, status);
}
}
void CDKGDebugManager::ProcessDebugStatusMessage(NodeId nodeId, llmq::CDKGDebugStatus& status)
{
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(status.proTxHash);
if (!dmn) {
if (nodeId != -1) {
LOCK(cs_main);
Misbehaving(nodeId, 10);
}
return;
}
{
LOCK(cs);
auto it = statusesForMasternodes.find(status.proTxHash);
if (it != statusesForMasternodes.end()) {
if (statuses[it->second].nTime >= status.nTime) {
// we know a more recent status already
return;
}
}
}
// check if all expected LLMQ types are present and valid
std::set<Consensus::LLMQType> llmqTypes;
for (const auto& p : status.sessions) {
if (!Params().GetConsensus().llmqs.count((Consensus::LLMQType)p.first)) {
if (nodeId != -1) {
LOCK(cs_main);
Misbehaving(nodeId, 10);
}
return;
}
const auto& params = Params().GetConsensus().llmqs.at((Consensus::LLMQType)p.first);
if (p.second.llmqType != p.first || p.second.members.size() != (size_t)params.size) {
if (nodeId != -1) {
LOCK(cs_main);
Misbehaving(nodeId, 10);
}
return;
}
llmqTypes.emplace((Consensus::LLMQType)p.first);
}
for (const auto& p : Params().GetConsensus().llmqs) {
if (!llmqTypes.count(p.first)) {
if (nodeId != -1) {
LOCK(cs_main);
Misbehaving(nodeId, 10);
}
return;
}
}
// TODO batch verification/processing
if (!status.sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator, status.GetSignHash())) {
if (nodeId != -1) {
LOCK(cs_main);
Misbehaving(nodeId, 10);
}
return;
}
LOCK(cs);
auto it = statusesForMasternodes.find(status.proTxHash);
if (it != statusesForMasternodes.end()) {
statuses.erase(it->second);
statusesForMasternodes.erase(it);
}
auto hash = ::SerializeHash(status);
statuses[hash] = status;
statusesForMasternodes[status.proTxHash] = hash;
CInv inv(MSG_QUORUM_DEBUG_STATUS, hash);
g_connman->RelayInv(inv, DMN_PROTO_VERSION);
}
UniValue CDKGDebugStatus::ToJson(int detailLevel) const
{
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("proTxHash", proTxHash.ToString()));
ret.push_back(Pair("height", (int)nHeight));
ret.push_back(Pair("time", nTime));
ret.push_back(Pair("timeStr", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nTime)));
UniValue sessionsJson(UniValue::VOBJ);
for (const auto& p : sessions) {
if (!Params().GetConsensus().llmqs.count((Consensus::LLMQType)p.first)) {
continue;
}
const auto& params = Params().GetConsensus().llmqs.at((Consensus::LLMQType)p.first);
sessionsJson.push_back(Pair(params.name, p.second.ToJson(detailLevel)));
}
ret.push_back(Pair("session", sessionsJson));
return ret;
}
bool CDKGDebugManager::AlreadyHave(const CInv& inv)
{
LOCK(cs);
return statuses.count(inv.hash) != 0;
}
bool CDKGDebugManager::GetDebugStatus(const uint256& hash, llmq::CDKGDebugStatus& ret)
{
LOCK(cs);
auto it = statuses.find(hash);
if (it == statuses.end()) {
return false;
}
ret = it->second;
return true;
}
bool CDKGDebugManager::GetDebugStatusForMasternode(const uint256& proTxHash, llmq::CDKGDebugStatus& ret)
{
LOCK(cs);
auto it = statusesForMasternodes.find(proTxHash);
if (it == statusesForMasternodes.end()) {
return false;
}
ret = statuses.at(it->second);
return true;
}
void CDKGDebugManager::GetLocalDebugStatus(llmq::CDKGDebugStatus& ret)
{
LOCK(cs);
ret = localStatus;
ret.proTxHash = activeMasternodeInfo.proTxHash;
}
void CDKGDebugManager::ResetLocalSessionStatus(Consensus::LLMQType llmqType, const uint256& quorumHash, int quorumHeight)
{
LOCK(cs);
auto& params = Params().GetConsensus().llmqs.at(llmqType);
localStatus.nTime = GetAdjustedTime();
auto& session = localStatus.sessions[llmqType];
session.llmqType = llmqType;
session.quorumHash = quorumHash;
session.quorumHeight = (uint32_t)quorumHeight;
session.phase = 0;
session.statusBitset = 0;
session.members.clear();
session.members.resize((size_t)params.size);
}
void CDKGDebugManager::UpdateLocalStatus(std::function<bool(CDKGDebugStatus& status)>&& func)
{
LOCK(cs);
if (func(localStatus)) {
localStatus.nTime = GetAdjustedTime();
}
}
void CDKGDebugManager::UpdateLocalSessionStatus(Consensus::LLMQType llmqType, std::function<bool(CDKGDebugSessionStatus& status)>&& func)
{
LOCK(cs);
if (func(localStatus.sessions.at(llmqType))) {
localStatus.nTime = GetAdjustedTime();
}
}
void CDKGDebugManager::UpdateLocalMemberStatus(Consensus::LLMQType llmqType, size_t memberIdx, std::function<bool(CDKGDebugMemberStatus& status)>&& func)
{
LOCK(cs);
if (func(localStatus.sessions.at(llmqType).members.at(memberIdx))) {
localStatus.nTime = GetAdjustedTime();
}
}
void CDKGDebugManager::SendLocalStatus()
{
if (!fMasternodeMode) {
return;
}
if (activeMasternodeInfo.proTxHash.IsNull()) {
return;
}
CDKGDebugStatus status;
{
LOCK(cs);
status = localStatus;
}
int64_t nTime = status.nTime;
status.proTxHash = activeMasternodeInfo.proTxHash;
status.nTime = 0;
status.sig = CBLSSignature();
uint256 newHash = ::SerializeHash(status);
if (newHash == lastStatusHash) {
return;
}
lastStatusHash = newHash;
status.nTime = nTime;
status.sig = activeMasternodeInfo.blsKeyOperator->Sign(status.GetSignHash());
ProcessDebugStatusMessage(-1, status);
}
}

178
src/llmq/quorums_debug.h Normal file
View File

@ -0,0 +1,178 @@
// Copyright (c) 2018 The Dash Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef DASH_QUORUMS_DEBUG_H
#define DASH_QUORUMS_DEBUG_H
#include "consensus/params.h"
#include "serialize.h"
#include "bls/bls.h"
#include "sync.h"
#include "univalue.h"
#include "net.h"
class CDataStream;
class CInv;
class CScheduler;
namespace llmq
{
class CDKGDebugMemberStatus
{
public:
union {
struct
{
// is it locally considered as bad (and thus removed from the validMembers set)
bool bad : 1;
// did we complain about this member
bool weComplain : 1;
// received message for DKG phases
bool receivedContribution : 1;
bool receivedComplaint : 1;
bool receivedJustification : 1;
bool receivedPrematureCommitment : 1;
};
uint16_t statusBitset;
};
std::set<size_t> complaintsFromMembers;
public:
CDKGDebugMemberStatus() : statusBitset(0) {}
public:
ADD_SERIALIZE_METHODS
template<typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(statusBitset);
READWRITE(complaintsFromMembers);
}
};
class CDKGDebugSessionStatus
{
public:
uint8_t llmqType{Consensus::LLMQ_NONE};
uint256 quorumHash;
uint32_t quorumHeight{0};
uint8_t phase{0};
union {
struct
{
// sent messages for DKG phases
bool sentContributions : 1;
bool sentComplaint : 1;
bool sentJustification : 1;
bool sentPrematureCommitment : 1;
bool aborted : 1;
};
uint16_t statusBitset;
};
std::vector<CDKGDebugMemberStatus> members;
public:
CDKGDebugSessionStatus() : statusBitset(0) {}
public:
ADD_SERIALIZE_METHODS
template<typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(llmqType);
READWRITE(quorumHash);
READWRITE(quorumHeight);
READWRITE(phase);
READWRITE(statusBitset);
READWRITE(members);
}
UniValue ToJson(int detailLevel) const;
};
class CDKGDebugStatus
{
public:
uint256 proTxHash;
int64_t nTime{0};
uint32_t nHeight{0};
std::map<uint8_t, CDKGDebugSessionStatus> sessions;
CBLSSignature sig;
public:
ADD_SERIALIZE_METHODS
template<typename Stream, typename Operation>
inline void SerializationOpWithoutSig(Stream& s, Operation ser_action)
{
READWRITE(proTxHash);
READWRITE(nTime);
READWRITE(nHeight);
READWRITE(sessions);
}
template<typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
SerializationOpWithoutSig(s, ser_action);
READWRITE(sig);
}
uint256 GetSignHash() const
{
CHashWriter hw(SER_GETHASH, 0);
NCONST_PTR(this)->SerializationOpWithoutSig(hw, CSerActionSerialize());
hw << CBLSSignature();
return hw.GetHash();
}
UniValue ToJson(int detailLevel) const;
};
class CDKGDebugManager
{
private:
CCriticalSection cs;
std::map<uint256, CDKGDebugStatus> statuses;
std::map<uint256, uint256> statusesForMasternodes;
CDKGDebugStatus localStatus;
uint256 lastStatusHash;
public:
CDKGDebugManager(CScheduler* scheduler);
void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman);
void ProcessDebugStatusMessage(NodeId nodeId, CDKGDebugStatus& status);
bool AlreadyHave(const CInv& inv);
bool GetDebugStatus(const uint256& hash, CDKGDebugStatus& ret);
bool GetDebugStatusForMasternode(const uint256& proTxHash, CDKGDebugStatus& ret);
void GetLocalDebugStatus(CDKGDebugStatus& ret);
void ResetLocalSessionStatus(Consensus::LLMQType llmqType, const uint256& quorumHash, int quorumHeight);
void UpdateLocalStatus(std::function<bool(CDKGDebugStatus& status)>&& func);
void UpdateLocalSessionStatus(Consensus::LLMQType llmqType, std::function<bool(CDKGDebugSessionStatus& status)>&& func);
void UpdateLocalMemberStatus(Consensus::LLMQType llmqType, size_t memberIdx, std::function<bool(CDKGDebugMemberStatus& status)>&& func);
void SendLocalStatus();
};
extern CDKGDebugManager* quorumDKGDebugManager;
}
#endif //DASH_QUORUMS_DEBUG_H

View File

@ -5,6 +5,7 @@
#include "quorums_dkgsession.h" #include "quorums_dkgsession.h"
#include "quorums_commitment.h" #include "quorums_commitment.h"
#include "quorums_debug.h"
#include "quorums_dkgsessionmgr.h" #include "quorums_dkgsessionmgr.h"
#include "quorums_utils.h" #include "quorums_utils.h"
@ -177,6 +178,11 @@ void CDKGSession::SendContributions()
logger.Flush(); logger.Flush();
quorumDKGDebugManager->UpdateLocalSessionStatus(params.type, [&](CDKGDebugSessionStatus& status) {
status.sentContributions = true;
return true;
});
uint256 hash = ::SerializeHash(qc); uint256 hash = ::SerializeHash(qc);
bool ban = false; bool ban = false;
if (PreVerifyMessage(hash, qc, ban)) { if (PreVerifyMessage(hash, qc, ban)) {
@ -265,6 +271,11 @@ void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGContribution& qc
invSet.emplace(inv); invSet.emplace(inv);
RelayInvToParticipants(inv); RelayInvToParticipants(inv);
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
status.receivedContribution = true;
return true;
});
if (member->contributions.size() > 1) { if (member->contributions.size() > 1) {
// don't do any further processing if we got more than 1 contribution. we already relayed it, // don't do any further processing if we got more than 1 contribution. we already relayed it,
// so others know about his bad behavior // so others know about his bad behavior
@ -306,6 +317,10 @@ void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGContribution& qc
if (complain) { if (complain) {
member->weComplain = true; member->weComplain = true;
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
status.weComplain = true;
return true;
});
return; return;
} }
@ -364,6 +379,10 @@ void CDKGSession::VerifyPendingContributions()
auto& m = members[memberIndexes[i]]; auto& m = members[memberIndexes[i]];
logger.Printf("invalid contribution from %s. will complain later\n", m->dmn->proTxHash.ToString()); logger.Printf("invalid contribution from %s. will complain later\n", m->dmn->proTxHash.ToString());
m->weComplain = true; m->weComplain = true;
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, m->idx, [&](CDKGDebugMemberStatus& status) {
status.weComplain = true;
return true;
});
} else { } else {
size_t memberIdx = memberIndexes[i]; size_t memberIdx = memberIndexes[i];
dkgManager.WriteVerifiedSkContribution(params.type, quorumHash, members[memberIdx]->dmn->proTxHash, skContributions[i]); dkgManager.WriteVerifiedSkContribution(params.type, quorumHash, members[memberIdx]->dmn->proTxHash, skContributions[i]);
@ -443,6 +462,11 @@ void CDKGSession::SendComplaint()
logger.Flush(); logger.Flush();
quorumDKGDebugManager->UpdateLocalSessionStatus(params.type, [&](CDKGDebugSessionStatus& status) {
status.sentComplaint = true;
return true;
});
uint256 hash = ::SerializeHash(qc); uint256 hash = ::SerializeHash(qc);
bool ban = false; bool ban = false;
if (PreVerifyMessage(hash, qc, ban)) { if (PreVerifyMessage(hash, qc, ban)) {
@ -522,6 +546,11 @@ void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGComplaint& qc, b
invSet.emplace(inv); invSet.emplace(inv);
RelayInvToParticipants(inv); RelayInvToParticipants(inv);
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
status.receivedComplaint = true;
return true;
});
if (member->complaints.size() > 1) { if (member->complaints.size() > 1) {
// don't do any further processing if we got more than 1 complaint. we already relayed it, // don't do any further processing if we got more than 1 complaint. we already relayed it,
// so others know about his bad behavior // so others know about his bad behavior
@ -544,6 +573,9 @@ void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGComplaint& qc, b
if (qc.complainForMembers[i]) { if (qc.complainForMembers[i]) {
m->complaintsFromOthers.emplace(qc.proTxHash); m->complaintsFromOthers.emplace(qc.proTxHash);
m->someoneComplain = true; m->someoneComplain = true;
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, m->idx, [&](CDKGDebugMemberStatus& status) {
return status.complaintsFromMembers.emplace(member->idx).second;
});
if (AreWeMember() && i == myIdx) { if (AreWeMember() && i == myIdx) {
logger.Printf("%s complained about us\n", member->dmn->proTxHash.ToString()); logger.Printf("%s complained about us\n", member->dmn->proTxHash.ToString());
} }
@ -636,6 +668,11 @@ void CDKGSession::SendJustification(const std::set<uint256>& forMembers)
logger.Flush(); logger.Flush();
quorumDKGDebugManager->UpdateLocalSessionStatus(params.type, [&](CDKGDebugSessionStatus& status) {
status.sentJustification = true;
return true;
});
uint256 hash = ::SerializeHash(qj); uint256 hash = ::SerializeHash(qj);
bool ban = false; bool ban = false;
if (PreVerifyMessage(hash, qj, ban)) { if (PreVerifyMessage(hash, qj, ban)) {
@ -732,6 +769,11 @@ void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGJustification& q
invSet.emplace(inv); invSet.emplace(inv);
RelayInvToParticipants(inv); RelayInvToParticipants(inv);
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
status.receivedJustification = true;
return true;
});
if (member->justifications.size() > 1) { if (member->justifications.size() > 1) {
// don't do any further processing if we got more than 1 justification. we already relayed it, // don't do any further processing if we got more than 1 justification. we already relayed it,
// so others know about his bad behavior // so others know about his bad behavior
@ -956,6 +998,11 @@ void CDKGSession::SendCommitment()
logger.Flush(); logger.Flush();
quorumDKGDebugManager->UpdateLocalSessionStatus(params.type, [&](CDKGDebugSessionStatus& status) {
status.sentPrematureCommitment = true;
return true;
});
uint256 hash = ::SerializeHash(qc); uint256 hash = ::SerializeHash(qc);
bool ban = false; bool ban = false;
if (PreVerifyMessage(hash, qc, ban)) { if (PreVerifyMessage(hash, qc, ban)) {
@ -1099,6 +1146,11 @@ void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGPrematureCommitm
invSet.emplace(inv); invSet.emplace(inv);
RelayInvToParticipants(inv); RelayInvToParticipants(inv);
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
status.receivedPrematureCommitment = true;
return true;
});
int receivedCount = 0; int receivedCount = 0;
for (auto& m : members) { for (auto& m : members) {
if (!m->prematureCommitments.empty()) { if (!m->prematureCommitments.empty()) {
@ -1223,6 +1275,10 @@ void CDKGSession::MarkBadMember(size_t idx)
if (member->bad) { if (member->bad) {
return; return;
} }
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, idx, [&](CDKGDebugMemberStatus& status) {
status.bad = true;
return true;
});
member->bad = true; member->bad = true;
} }

View File

@ -123,6 +123,7 @@ void CDKGSessionHandler::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBl
QuorumPhase newPhase = phase; QuorumPhase newPhase = phase;
if (quorumStageInt == 0) { if (quorumStageInt == 0) {
newPhase = QuorumPhase_Initialized; newPhase = QuorumPhase_Initialized;
quorumDKGDebugManager->ResetLocalSessionStatus(params.type, quorumHash, quorumHeight);
} else if (quorumStageInt == params.dkgPhaseBlocks * 1) { } else if (quorumStageInt == params.dkgPhaseBlocks * 1) {
newPhase = QuorumPhase_Contribute; newPhase = QuorumPhase_Contribute;
} else if (quorumStageInt == params.dkgPhaseBlocks * 2) { } else if (quorumStageInt == params.dkgPhaseBlocks * 2) {
@ -137,6 +138,17 @@ void CDKGSessionHandler::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBl
newPhase = QuorumPhase_Idle; newPhase = QuorumPhase_Idle;
} }
phase = newPhase; phase = newPhase;
quorumDKGDebugManager->UpdateLocalStatus([&](CDKGDebugStatus& status) {
bool changed = status.nHeight != pindexNew->nHeight;
status.nHeight = (uint32_t)pindexNew->nHeight;
return changed;
});
quorumDKGDebugManager->UpdateLocalSessionStatus(params.type, [&](CDKGDebugSessionStatus& status) {
bool changed = status.phase != (uint8_t)phase;
status.phase = (uint8_t)phase;
return changed;
});
} }
void CDKGSessionHandler::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman) void CDKGSessionHandler::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
@ -530,6 +542,10 @@ void CDKGSessionHandler::PhaseHandlerThread()
try { try {
HandleDKGRound(); HandleDKGRound();
} catch (AbortPhaseException& e) { } catch (AbortPhaseException& e) {
quorumDKGDebugManager->UpdateLocalSessionStatus(params.type, [&](CDKGDebugSessionStatus& status) {
status.aborted = true;
return true;
});
LogPrintf("CDKGSessionHandler::%s -- aborted current DKG session\n", __func__); LogPrintf("CDKGSessionHandler::%s -- aborted current DKG session\n", __func__);
} }
} }

View File

@ -4,6 +4,7 @@
#include "quorums_dkgsessionmgr.h" #include "quorums_dkgsessionmgr.h"
#include "quorums_blockprocessor.h" #include "quorums_blockprocessor.h"
#include "quorums_debug.h"
#include "quorums_init.h" #include "quorums_init.h"
#include "quorums_utils.h" #include "quorums_utils.h"

View File

@ -6,6 +6,7 @@
#include "quorums_blockprocessor.h" #include "quorums_blockprocessor.h"
#include "quorums_commitment.h" #include "quorums_commitment.h"
#include "quorums_debug.h"
#include "quorums_dkgsessionmgr.h" #include "quorums_dkgsessionmgr.h"
#include "scheduler.h" #include "scheduler.h"
@ -17,6 +18,7 @@ static CBLSWorker blsWorker;
void InitLLMQSystem(CEvoDB& evoDb, CScheduler* scheduler) void InitLLMQSystem(CEvoDB& evoDb, CScheduler* scheduler)
{ {
quorumDKGDebugManager = new CDKGDebugManager(scheduler);
quorumBlockProcessor = new CQuorumBlockProcessor(evoDb); quorumBlockProcessor = new CQuorumBlockProcessor(evoDb);
quorumDKGSessionManager = new CDKGSessionManager(evoDb, blsWorker); quorumDKGSessionManager = new CDKGSessionManager(evoDb, blsWorker);
} }
@ -27,6 +29,8 @@ void DestroyLLMQSystem()
quorumDKGSessionManager = NULL; quorumDKGSessionManager = NULL;
delete quorumBlockProcessor; delete quorumBlockProcessor;
quorumBlockProcessor = nullptr; quorumBlockProcessor = nullptr;
delete quorumDKGDebugManager;
quorumDKGDebugManager = nullptr;
} }
} }

View File

@ -46,6 +46,7 @@
#include "evo/simplifiedmns.h" #include "evo/simplifiedmns.h"
#include "llmq/quorums_blockprocessor.h" #include "llmq/quorums_blockprocessor.h"
#include "llmq/quorums_commitment.h" #include "llmq/quorums_commitment.h"
#include "llmq/quorums_debug.h"
#include "llmq/quorums_dkgsessionmgr.h" #include "llmq/quorums_dkgsessionmgr.h"
#include "llmq/quorums_init.h" #include "llmq/quorums_init.h"
@ -956,6 +957,8 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
case MSG_QUORUM_JUSTIFICATION: case MSG_QUORUM_JUSTIFICATION:
case MSG_QUORUM_PREMATURE_COMMITMENT: case MSG_QUORUM_PREMATURE_COMMITMENT:
return llmq::quorumDKGSessionManager->AlreadyHave(inv); return llmq::quorumDKGSessionManager->AlreadyHave(inv);
case MSG_QUORUM_DEBUG_STATUS:
return llmq::quorumDKGDebugManager->AlreadyHave(inv);
} }
// Don't know what it is, just say we already got one // Don't know what it is, just say we already got one
@ -1253,6 +1256,13 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
push = true; push = true;
} }
} }
if (!push && (inv.type == MSG_QUORUM_DEBUG_STATUS)) {
llmq::CDKGDebugStatus o;
if (llmq::quorumDKGDebugManager->GetDebugStatus(inv.hash, o)) {
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::QDEBUGSTATUS, o));
push = true;
}
}
if (!push) if (!push)
vNotFound.push_back(inv); vNotFound.push_back(inv);
@ -2911,6 +2921,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
governance.ProcessMessage(pfrom, strCommand, vRecv, connman); governance.ProcessMessage(pfrom, strCommand, vRecv, connman);
llmq::quorumBlockProcessor->ProcessMessage(pfrom, strCommand, vRecv, connman); llmq::quorumBlockProcessor->ProcessMessage(pfrom, strCommand, vRecv, connman);
llmq::quorumDKGSessionManager->ProcessMessage(pfrom, strCommand, vRecv, connman); llmq::quorumDKGSessionManager->ProcessMessage(pfrom, strCommand, vRecv, connman);
llmq::quorumDKGDebugManager->ProcessMessage(pfrom, strCommand, vRecv, connman);
} }
else else
{ {

View File

@ -64,6 +64,7 @@ const char *QCOMPLAINT="qcomplaint";
const char *QJUSTIFICATION="qjustify"; const char *QJUSTIFICATION="qjustify";
const char *QPCOMMITMENT="qpcommit"; const char *QPCOMMITMENT="qpcommit";
const char *QWATCH="qwatch"; const char *QWATCH="qwatch";
const char *QDEBUGSTATUS="qdebugstatus";
}; };
static const char* ppszTypeName[] = static const char* ppszTypeName[] =
@ -97,6 +98,7 @@ static const char* ppszTypeName[] =
NetMsgType::QCOMPLAINT, NetMsgType::QCOMPLAINT,
NetMsgType::QJUSTIFICATION, NetMsgType::QJUSTIFICATION,
NetMsgType::QPCOMMITMENT, NetMsgType::QPCOMMITMENT,
NetMsgType::QDEBUGSTATUS,
}; };
/** All known message types. Keep this in the same order as the list of /** All known message types. Keep this in the same order as the list of
@ -155,6 +157,7 @@ const static std::string allNetMessageTypes[] = {
NetMsgType::QJUSTIFICATION, NetMsgType::QJUSTIFICATION,
NetMsgType::QPCOMMITMENT, NetMsgType::QPCOMMITMENT,
NetMsgType::QWATCH, NetMsgType::QWATCH,
NetMsgType::QDEBUGSTATUS,
}; };
const static std::vector<std::string> allNetMessageTypesVec(allNetMessageTypes, allNetMessageTypes+ARRAYLEN(allNetMessageTypes)); const static std::vector<std::string> allNetMessageTypesVec(allNetMessageTypes, allNetMessageTypes+ARRAYLEN(allNetMessageTypes));

View File

@ -270,6 +270,7 @@ extern const char *QCOMPLAINT;
extern const char *QJUSTIFICATION; extern const char *QJUSTIFICATION;
extern const char *QPCOMMITMENT; extern const char *QPCOMMITMENT;
extern const char *QWATCH; extern const char *QWATCH;
extern const char *QDEBUGSTATUS;
}; };
/* Get a vector of all valid message types (see above) */ /* Get a vector of all valid message types (see above) */
@ -369,6 +370,7 @@ enum GetDataMsg {
MSG_QUORUM_COMPLAINT = 24, MSG_QUORUM_COMPLAINT = 24,
MSG_QUORUM_JUSTIFICATION = 25, MSG_QUORUM_JUSTIFICATION = 25,
MSG_QUORUM_PREMATURE_COMMITMENT = 26, MSG_QUORUM_PREMATURE_COMMITMENT = 26,
MSG_QUORUM_DEBUG_STATUS = 27,
}; };
/** inv message data */ /** inv message data */

View File

@ -25,6 +25,8 @@ void RegisterMasternodeRPCCommands(CRPCTable &tableRPC);
void RegisterGovernanceRPCCommands(CRPCTable &tableRPC); void RegisterGovernanceRPCCommands(CRPCTable &tableRPC);
/** Register Evo RPC commands */ /** Register Evo RPC commands */
void RegisterEvoRPCCommands(CRPCTable &tableRPC); void RegisterEvoRPCCommands(CRPCTable &tableRPC);
/** Register Quorums RPC commands */
void RegisterQuorumsRPCCommands(CRPCTable &tableRPC);
static inline void RegisterAllCoreRPCCommands(CRPCTable &t) static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
{ {
@ -36,6 +38,7 @@ static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
RegisterMasternodeRPCCommands(t); RegisterMasternodeRPCCommands(t);
RegisterGovernanceRPCCommands(t); RegisterGovernanceRPCCommands(t);
RegisterEvoRPCCommands(t); RegisterEvoRPCCommands(t);
RegisterQuorumsRPCCommands(t);
} }
#endif #endif

81
src/rpc/rpcquorums.cpp Normal file
View File

@ -0,0 +1,81 @@
// Copyright (c) 2017 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "server.h"
#include "validation.h"
#include "llmq/quorums_debug.h"
#include "llmq/quorums_dkgsession.h"
void quorum_dkgstatus_help()
{
throw std::runtime_error(
"quorum dkgstatus (detailed)\n"
"\nArguments:\n"
"1. \"proTxHash\" (string, optional, default=0) ProTxHash of masternode to show status for.\n"
" If set to an empty string or 0, the local status is shown.\n"
"2. \"detailLevel\" (number, optional, default=0) Detail level of output.\n"
" 0=Only show counts. 1=Show member indexes. 2=Show member's ProTxHashes.\n"
);
}
UniValue quorum_dkgstatus(const JSONRPCRequest& request)
{
if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2 && request.params.size() != 3)) {
quorum_dkgstatus_help();
}
uint256 proTxHash;
if (request.params.size() > 1 && request.params[1].get_str() != "" && request.params[1].get_str() != "0") {
proTxHash = ParseHashV(request.params[1], "proTxHash");
}
int detailLevel = 0;
if (request.params.size() > 2) {
detailLevel = ParseInt32V(request.params[2], "detailLevel");
if (detailLevel < 0 || detailLevel > 2) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid detailLevel");
}
}
llmq::CDKGDebugStatus status;
if (proTxHash.IsNull()) {
llmq::quorumDKGDebugManager->GetLocalDebugStatus(status);
} else {
if (!llmq::quorumDKGDebugManager->GetDebugStatusForMasternode(proTxHash, status)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("no status for %s found", proTxHash.ToString()));
}
}
return status.ToJson(detailLevel);
}
UniValue quorum(const JSONRPCRequest& request)
{
if (request.params.empty()) {
throw std::runtime_error(
"quorum \"command\" ...\n"
);
}
std::string command = request.params[0].get_str();
if (command == "dkgstatus") {
return quorum_dkgstatus(request);
} else {
throw std::runtime_error("invalid command: " + command);
}
}
static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
{ "evo", "quorum", &quorum, false, {} },
};
void RegisterQuorumsRPCCommands(CRPCTable &tableRPC)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
}