mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 20:12:57 +01:00
Implement debugging messages and RPC for LLMQ DKGs
This commit is contained in:
parent
098b094959
commit
324406bfed
@ -143,6 +143,7 @@ BITCOIN_CORE_H = \
|
||||
limitedmap.h \
|
||||
llmq/quorums_blockprocessor.h \
|
||||
llmq/quorums_commitment.h \
|
||||
llmq/quorums_debug.h \
|
||||
llmq/quorums_dkgsessionhandler.h \
|
||||
llmq/quorums_dkgsessionmgr.h \
|
||||
llmq/quorums_dkgsession.h \
|
||||
@ -254,6 +255,7 @@ libdash_server_a_SOURCES = \
|
||||
governance-votedb.cpp \
|
||||
llmq/quorums_blockprocessor.cpp \
|
||||
llmq/quorums_commitment.cpp \
|
||||
llmq/quorums_debug.cpp \
|
||||
llmq/quorums_dkgsessionhandler.cpp \
|
||||
llmq/quorums_dkgsessionmgr.cpp \
|
||||
llmq/quorums_dkgsession.cpp \
|
||||
@ -284,6 +286,7 @@ libdash_server_a_SOURCES = \
|
||||
rpc/net.cpp \
|
||||
rpc/rawtransaction.cpp \
|
||||
rpc/rpcevo.cpp \
|
||||
rpc/rpcquorums.cpp \
|
||||
rpc/server.cpp \
|
||||
script/sigcache.cpp \
|
||||
script/ismine.cpp \
|
||||
|
347
src/llmq/quorums_debug.cpp
Normal file
347
src/llmq/quorums_debug.cpp
Normal 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
178
src/llmq/quorums_debug.h
Normal 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
|
@ -5,6 +5,7 @@
|
||||
#include "quorums_dkgsession.h"
|
||||
|
||||
#include "quorums_commitment.h"
|
||||
#include "quorums_debug.h"
|
||||
#include "quorums_dkgsessionmgr.h"
|
||||
#include "quorums_utils.h"
|
||||
|
||||
@ -177,6 +178,11 @@ void CDKGSession::SendContributions()
|
||||
|
||||
logger.Flush();
|
||||
|
||||
quorumDKGDebugManager->UpdateLocalSessionStatus(params.type, [&](CDKGDebugSessionStatus& status) {
|
||||
status.sentContributions = true;
|
||||
return true;
|
||||
});
|
||||
|
||||
uint256 hash = ::SerializeHash(qc);
|
||||
bool ban = false;
|
||||
if (PreVerifyMessage(hash, qc, ban)) {
|
||||
@ -265,6 +271,11 @@ void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGContribution& qc
|
||||
invSet.emplace(inv);
|
||||
RelayInvToParticipants(inv);
|
||||
|
||||
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
|
||||
status.receivedContribution = true;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (member->contributions.size() > 1) {
|
||||
// don't do any further processing if we got more than 1 contribution. we already relayed it,
|
||||
// so others know about his bad behavior
|
||||
@ -306,6 +317,10 @@ void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGContribution& qc
|
||||
|
||||
if (complain) {
|
||||
member->weComplain = true;
|
||||
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
|
||||
status.weComplain = true;
|
||||
return true;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@ -364,6 +379,10 @@ void CDKGSession::VerifyPendingContributions()
|
||||
auto& m = members[memberIndexes[i]];
|
||||
logger.Printf("invalid contribution from %s. will complain later\n", m->dmn->proTxHash.ToString());
|
||||
m->weComplain = true;
|
||||
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, m->idx, [&](CDKGDebugMemberStatus& status) {
|
||||
status.weComplain = true;
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
size_t memberIdx = memberIndexes[i];
|
||||
dkgManager.WriteVerifiedSkContribution(params.type, quorumHash, members[memberIdx]->dmn->proTxHash, skContributions[i]);
|
||||
@ -443,6 +462,11 @@ void CDKGSession::SendComplaint()
|
||||
|
||||
logger.Flush();
|
||||
|
||||
quorumDKGDebugManager->UpdateLocalSessionStatus(params.type, [&](CDKGDebugSessionStatus& status) {
|
||||
status.sentComplaint = true;
|
||||
return true;
|
||||
});
|
||||
|
||||
uint256 hash = ::SerializeHash(qc);
|
||||
bool ban = false;
|
||||
if (PreVerifyMessage(hash, qc, ban)) {
|
||||
@ -522,6 +546,11 @@ void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGComplaint& qc, b
|
||||
invSet.emplace(inv);
|
||||
RelayInvToParticipants(inv);
|
||||
|
||||
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
|
||||
status.receivedComplaint = true;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (member->complaints.size() > 1) {
|
||||
// don't do any further processing if we got more than 1 complaint. we already relayed it,
|
||||
// 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]) {
|
||||
m->complaintsFromOthers.emplace(qc.proTxHash);
|
||||
m->someoneComplain = true;
|
||||
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, m->idx, [&](CDKGDebugMemberStatus& status) {
|
||||
return status.complaintsFromMembers.emplace(member->idx).second;
|
||||
});
|
||||
if (AreWeMember() && i == myIdx) {
|
||||
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();
|
||||
|
||||
quorumDKGDebugManager->UpdateLocalSessionStatus(params.type, [&](CDKGDebugSessionStatus& status) {
|
||||
status.sentJustification = true;
|
||||
return true;
|
||||
});
|
||||
|
||||
uint256 hash = ::SerializeHash(qj);
|
||||
bool ban = false;
|
||||
if (PreVerifyMessage(hash, qj, ban)) {
|
||||
@ -732,6 +769,11 @@ void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGJustification& q
|
||||
invSet.emplace(inv);
|
||||
RelayInvToParticipants(inv);
|
||||
|
||||
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
|
||||
status.receivedJustification = true;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (member->justifications.size() > 1) {
|
||||
// don't do any further processing if we got more than 1 justification. we already relayed it,
|
||||
// so others know about his bad behavior
|
||||
@ -956,6 +998,11 @@ void CDKGSession::SendCommitment()
|
||||
|
||||
logger.Flush();
|
||||
|
||||
quorumDKGDebugManager->UpdateLocalSessionStatus(params.type, [&](CDKGDebugSessionStatus& status) {
|
||||
status.sentPrematureCommitment = true;
|
||||
return true;
|
||||
});
|
||||
|
||||
uint256 hash = ::SerializeHash(qc);
|
||||
bool ban = false;
|
||||
if (PreVerifyMessage(hash, qc, ban)) {
|
||||
@ -1099,6 +1146,11 @@ void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGPrematureCommitm
|
||||
invSet.emplace(inv);
|
||||
RelayInvToParticipants(inv);
|
||||
|
||||
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
|
||||
status.receivedPrematureCommitment = true;
|
||||
return true;
|
||||
});
|
||||
|
||||
int receivedCount = 0;
|
||||
for (auto& m : members) {
|
||||
if (!m->prematureCommitments.empty()) {
|
||||
@ -1223,6 +1275,10 @@ void CDKGSession::MarkBadMember(size_t idx)
|
||||
if (member->bad) {
|
||||
return;
|
||||
}
|
||||
quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, idx, [&](CDKGDebugMemberStatus& status) {
|
||||
status.bad = true;
|
||||
return true;
|
||||
});
|
||||
member->bad = true;
|
||||
}
|
||||
|
||||
@ -1256,4 +1312,4 @@ void CDKGSession::RelayInvToParticipants(const CInv& inv)
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -123,6 +123,7 @@ void CDKGSessionHandler::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBl
|
||||
QuorumPhase newPhase = phase;
|
||||
if (quorumStageInt == 0) {
|
||||
newPhase = QuorumPhase_Initialized;
|
||||
quorumDKGDebugManager->ResetLocalSessionStatus(params.type, quorumHash, quorumHeight);
|
||||
} else if (quorumStageInt == params.dkgPhaseBlocks * 1) {
|
||||
newPhase = QuorumPhase_Contribute;
|
||||
} else if (quorumStageInt == params.dkgPhaseBlocks * 2) {
|
||||
@ -137,6 +138,17 @@ void CDKGSessionHandler::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBl
|
||||
newPhase = QuorumPhase_Idle;
|
||||
}
|
||||
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)
|
||||
@ -530,6 +542,10 @@ void CDKGSessionHandler::PhaseHandlerThread()
|
||||
try {
|
||||
HandleDKGRound();
|
||||
} catch (AbortPhaseException& e) {
|
||||
quorumDKGDebugManager->UpdateLocalSessionStatus(params.type, [&](CDKGDebugSessionStatus& status) {
|
||||
status.aborted = true;
|
||||
return true;
|
||||
});
|
||||
LogPrintf("CDKGSessionHandler::%s -- aborted current DKG session\n", __func__);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "quorums_dkgsessionmgr.h"
|
||||
#include "quorums_blockprocessor.h"
|
||||
#include "quorums_debug.h"
|
||||
#include "quorums_init.h"
|
||||
#include "quorums_utils.h"
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "quorums_blockprocessor.h"
|
||||
#include "quorums_commitment.h"
|
||||
#include "quorums_debug.h"
|
||||
#include "quorums_dkgsessionmgr.h"
|
||||
|
||||
#include "scheduler.h"
|
||||
@ -17,6 +18,7 @@ static CBLSWorker blsWorker;
|
||||
|
||||
void InitLLMQSystem(CEvoDB& evoDb, CScheduler* scheduler)
|
||||
{
|
||||
quorumDKGDebugManager = new CDKGDebugManager(scheduler);
|
||||
quorumBlockProcessor = new CQuorumBlockProcessor(evoDb);
|
||||
quorumDKGSessionManager = new CDKGSessionManager(evoDb, blsWorker);
|
||||
}
|
||||
@ -27,6 +29,8 @@ void DestroyLLMQSystem()
|
||||
quorumDKGSessionManager = NULL;
|
||||
delete quorumBlockProcessor;
|
||||
quorumBlockProcessor = nullptr;
|
||||
delete quorumDKGDebugManager;
|
||||
quorumDKGDebugManager = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "evo/simplifiedmns.h"
|
||||
#include "llmq/quorums_blockprocessor.h"
|
||||
#include "llmq/quorums_commitment.h"
|
||||
#include "llmq/quorums_debug.h"
|
||||
#include "llmq/quorums_dkgsessionmgr.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_PREMATURE_COMMITMENT:
|
||||
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
|
||||
@ -1253,6 +1256,13 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
|
||||
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)
|
||||
vNotFound.push_back(inv);
|
||||
@ -2911,6 +2921,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||
governance.ProcessMessage(pfrom, strCommand, vRecv, connman);
|
||||
llmq::quorumBlockProcessor->ProcessMessage(pfrom, strCommand, vRecv, connman);
|
||||
llmq::quorumDKGSessionManager->ProcessMessage(pfrom, strCommand, vRecv, connman);
|
||||
llmq::quorumDKGDebugManager->ProcessMessage(pfrom, strCommand, vRecv, connman);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -64,6 +64,7 @@ const char *QCOMPLAINT="qcomplaint";
|
||||
const char *QJUSTIFICATION="qjustify";
|
||||
const char *QPCOMMITMENT="qpcommit";
|
||||
const char *QWATCH="qwatch";
|
||||
const char *QDEBUGSTATUS="qdebugstatus";
|
||||
};
|
||||
|
||||
static const char* ppszTypeName[] =
|
||||
@ -97,6 +98,7 @@ static const char* ppszTypeName[] =
|
||||
NetMsgType::QCOMPLAINT,
|
||||
NetMsgType::QJUSTIFICATION,
|
||||
NetMsgType::QPCOMMITMENT,
|
||||
NetMsgType::QDEBUGSTATUS,
|
||||
};
|
||||
|
||||
/** 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::QPCOMMITMENT,
|
||||
NetMsgType::QWATCH,
|
||||
NetMsgType::QDEBUGSTATUS,
|
||||
};
|
||||
const static std::vector<std::string> allNetMessageTypesVec(allNetMessageTypes, allNetMessageTypes+ARRAYLEN(allNetMessageTypes));
|
||||
|
||||
|
@ -270,6 +270,7 @@ extern const char *QCOMPLAINT;
|
||||
extern const char *QJUSTIFICATION;
|
||||
extern const char *QPCOMMITMENT;
|
||||
extern const char *QWATCH;
|
||||
extern const char *QDEBUGSTATUS;
|
||||
};
|
||||
|
||||
/* Get a vector of all valid message types (see above) */
|
||||
@ -369,6 +370,7 @@ enum GetDataMsg {
|
||||
MSG_QUORUM_COMPLAINT = 24,
|
||||
MSG_QUORUM_JUSTIFICATION = 25,
|
||||
MSG_QUORUM_PREMATURE_COMMITMENT = 26,
|
||||
MSG_QUORUM_DEBUG_STATUS = 27,
|
||||
};
|
||||
|
||||
/** inv message data */
|
||||
|
@ -25,6 +25,8 @@ void RegisterMasternodeRPCCommands(CRPCTable &tableRPC);
|
||||
void RegisterGovernanceRPCCommands(CRPCTable &tableRPC);
|
||||
/** Register Evo RPC commands */
|
||||
void RegisterEvoRPCCommands(CRPCTable &tableRPC);
|
||||
/** Register Quorums RPC commands */
|
||||
void RegisterQuorumsRPCCommands(CRPCTable &tableRPC);
|
||||
|
||||
static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
|
||||
{
|
||||
@ -36,6 +38,7 @@ static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
|
||||
RegisterMasternodeRPCCommands(t);
|
||||
RegisterGovernanceRPCCommands(t);
|
||||
RegisterEvoRPCCommands(t);
|
||||
RegisterQuorumsRPCCommands(t);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
81
src/rpc/rpcquorums.cpp
Normal file
81
src/rpc/rpcquorums.cpp
Normal 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]);
|
||||
}
|
Loading…
Reference in New Issue
Block a user