Remove code for QDEBUGSTATUS propagation (#2891)

* Remove code for QDEBUGSTATUS propagation

This turned out to be too expensive and could easily take the network
down by bringing all nodes to 100% CPU usage. Better to fully remove this
functionality.

* Apply suggestions from code review

Co-Authored-By: codablock <ablock84@gmail.com>

* Update src/rpc/rpcquorums.cpp

Co-Authored-By: codablock <ablock84@gmail.com>
This commit is contained in:
Alexander Block 2019-05-02 01:20:06 +02:00 committed by UdjinM6
parent 783cb9ca69
commit 53827a3764
9 changed files with 14 additions and 369 deletions

View File

@ -4,14 +4,7 @@
#include "quorums_debug.h"
#include "activemasternode.h"
#include "bls/bls_batchverifier.h"
#include "chainparams.h"
#include "net.h"
#include "net_processing.h"
#include "scheduler.h"
#include "spork.h"
#include "validation.h"
#include "evo/deterministicmns.h"
#include "quorums_utils.h"
@ -108,182 +101,14 @@ UniValue CDKGDebugSessionStatus::ToJson(int detailLevel) const
return ret;
}
CDKGDebugManager::CDKGDebugManager(CScheduler* _scheduler) :
scheduler(_scheduler)
CDKGDebugManager::CDKGDebugManager()
{
}
void CDKGDebugManager::StartScheduler()
{
if (scheduler) {
scheduler->scheduleEvery([&]() {
SendLocalStatus();
}, 10 * 1000);
}
}
void CDKGDebugManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
{
if (!sporkManager.IsSporkActive(SPORK_18_QUORUM_DEBUG_ENABLED)) {
return;
}
if (strCommand == NetMsgType::QDEBUGSTATUS) {
CDKGDebugStatus status;
vRecv >> status;
uint256 hash = ::SerializeHash(status);
{
LOCK(cs_main);
connman.RemoveAskFor(hash);
}
bool ban = false;
if (!PreVerifyDebugStatusMessage(hash, status, ban)) {
if (ban) {
LOCK(cs_main);
Misbehaving(pfrom->id, 10);
return;
}
}
LOCK(cs);
pendingIncomingStatuses.emplace(hash, std::make_pair(std::move(status), pfrom->id));
ScheduleProcessPending();
}
}
bool CDKGDebugManager::PreVerifyDebugStatusMessage(const uint256& hash, llmq::CDKGDebugStatus& status, bool& retBan)
{
retBan = false;
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(status.proTxHash);
if (!dmn) {
retBan = true;
return false;
}
{
LOCK(cs);
if (!seenStatuses.emplace(hash, GetTimeMillis()).second) {
return false;
}
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 false;
}
}
}
// check if all present LLMQ types are valid
for (const auto& p : status.sessions) {
if (!Params().GetConsensus().llmqs.count((Consensus::LLMQType)p.first)) {
retBan = true;
return false;
}
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) {
retBan = true;
return false;
}
}
return true;
}
void CDKGDebugManager::ScheduleProcessPending()
{
AssertLockHeld(cs);
if (hasScheduledProcessPending) {
return;
}
scheduler->schedule([&] {
ProcessPending();
}, boost::chrono::system_clock::now() + boost::chrono::milliseconds(100));
}
void CDKGDebugManager::ProcessPending()
{
decltype(pendingIncomingStatuses) pend;
{
LOCK(cs);
hasScheduledProcessPending = false;
pend = std::move(pendingIncomingStatuses);
}
if (!sporkManager.IsSporkActive(SPORK_18_QUORUM_DEBUG_ENABLED)) {
return;
}
CBLSBatchVerifier<NodeId, uint256> batchVerifier(true, true, 8);
for (const auto& p : pend) {
const auto& hash = p.first;
const auto& status = p.second.first;
auto nodeId = p.second.second;
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(status.proTxHash);
if (!dmn) {
continue;
}
batchVerifier.PushMessage(nodeId, hash, status.GetSignHash(), status.sig, dmn->pdmnState->pubKeyOperator);
}
batchVerifier.Verify();
if (!batchVerifier.badSources.empty()) {
LOCK(cs_main);
for (auto& nodeId : batchVerifier.badSources) {
Misbehaving(nodeId, 100);
}
}
for (const auto& p : pend) {
const auto& hash = p.first;
const auto& status = p.second.first;
auto nodeId = p.second.second;
if (batchVerifier.badMessages.count(p.first)) {
continue;
}
ProcessDebugStatusMessage(hash, status);
}
}
// status must have a validated signature
void CDKGDebugManager::ProcessDebugStatusMessage(const uint256& hash, const llmq::CDKGDebugStatus& status)
{
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(status.proTxHash);
if (!dmn) {
return;
}
LOCK(cs);
auto it = statusesForMasternodes.find(status.proTxHash);
if (it != statusesForMasternodes.end()) {
statuses.erase(it->second);
statusesForMasternodes.erase(it);
}
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("time", nTime));
ret.push_back(Pair("timeStr", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nTime)));
@ -301,44 +126,10 @@ UniValue CDKGDebugStatus::ToJson(int detailLevel) const
return ret;
}
bool CDKGDebugManager::AlreadyHave(const CInv& inv)
{
LOCK(cs);
if (!sporkManager.IsSporkActive(SPORK_18_QUORUM_DEBUG_ENABLED)) {
return true;
}
return statuses.count(inv.hash) != 0 || seenStatuses.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)
@ -410,39 +201,4 @@ void CDKGDebugManager::UpdateLocalMemberStatus(Consensus::LLMQType llmqType, siz
}
}
void CDKGDebugManager::SendLocalStatus()
{
if (!fMasternodeMode) {
return;
}
if (activeMasternodeInfo.proTxHash.IsNull()) {
return;
}
if (!sporkManager.IsSporkActive(SPORK_18_QUORUM_DEBUG_ENABLED)) {
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(newHash, status);
}
}

View File

@ -6,11 +6,10 @@
#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"
#include <set>
class CDataStream;
class CInv;
@ -43,16 +42,6 @@ public:
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
@ -82,93 +71,29 @@ public:
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};
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(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:
CScheduler* scheduler;
CCriticalSection cs;
std::map<uint256, int64_t> seenStatuses;
std::multimap<uint256, std::pair<CDKGDebugStatus, NodeId>> pendingIncomingStatuses;
bool hasScheduledProcessPending{false};
std::map<uint256, CDKGDebugStatus> statuses;
std::map<uint256, uint256> statusesForMasternodes;
CDKGDebugStatus localStatus;
uint256 lastStatusHash;
public:
CDKGDebugManager(CScheduler* _scheduler);
CDKGDebugManager();
void StartScheduler();
void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman);
bool PreVerifyDebugStatusMessage(const uint256& hash, CDKGDebugStatus& status, bool& retBan);
void ScheduleProcessPending();
void ProcessPending();
void ProcessDebugStatusMessage(const uint256& hash, const 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);
@ -177,8 +102,6 @@ public:
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;

View File

@ -29,7 +29,7 @@ void InitLLMQSystem(CEvoDB& evoDb, CScheduler* scheduler, bool unitTests, bool f
llmqDb = new CDBWrapper(unitTests ? "" : (GetDataDir() / "llmq"), 1 << 20, unitTests, fWipe);
blsWorker = new CBLSWorker();
quorumDKGDebugManager = new CDKGDebugManager(scheduler);
quorumDKGDebugManager = new CDKGDebugManager();
quorumBlockProcessor = new CQuorumBlockProcessor(evoDb);
quorumDKGSessionManager = new CDKGSessionManager(*llmqDb, *blsWorker);
quorumManager = new CQuorumManager(evoDb, *blsWorker, *quorumDKGSessionManager);
@ -70,9 +70,6 @@ void StartLLMQSystem()
if (blsWorker) {
blsWorker->Start();
}
if (quorumDKGDebugManager) {
quorumDKGDebugManager->StartScheduler();
}
if (quorumDKGSessionManager) {
quorumDKGSessionManager->StartMessageHandlerPool();
}

View File

@ -48,7 +48,6 @@
#include "llmq/quorums_blockprocessor.h"
#include "llmq/quorums_commitment.h"
#include "llmq/quorums_chainlocks.h"
#include "llmq/quorums_debug.h"
#include "llmq/quorums_dkgsessionmgr.h"
#include "llmq/quorums_init.h"
#include "llmq/quorums_instantsend.h"
@ -1016,8 +1015,6 @@ 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);
case MSG_QUORUM_RECOVERED_SIG:
return llmq::quorumSigningManager->AlreadyHave(inv);
case MSG_CLSIG:
@ -1340,13 +1337,6 @@ 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 && (inv.type == MSG_QUORUM_RECOVERED_SIG)) {
llmq::CRecoveredSig o;
if (llmq::quorumSigningManager->GetRecoveredSigForGetData(inv.hash, o)) {
@ -3072,7 +3062,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
CMNAuth::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);
llmq::quorumSigSharesManager->ProcessMessage(pfrom, strCommand, vRecv, connman);
llmq::quorumSigningManager->ProcessMessage(pfrom, strCommand, vRecv, connman);
llmq::chainLocksHandler->ProcessMessage(pfrom, strCommand, vRecv, connman);

View File

@ -66,7 +66,6 @@ const char *QCOMPLAINT="qcomplaint";
const char *QJUSTIFICATION="qjustify";
const char *QPCOMMITMENT="qpcommit";
const char *QWATCH="qwatch";
const char *QDEBUGSTATUS="qdebugstatus";
const char *QSIGSESANN="qsigsesann";
const char *QSIGSHARESINV="qsigsinv";
const char *QGETSIGSHARES="qgetsigs";
@ -108,7 +107,7 @@ static const char* ppszTypeName[] =
NetMsgType::QCOMPLAINT,
NetMsgType::QJUSTIFICATION,
NetMsgType::QPCOMMITMENT,
NetMsgType::QDEBUGSTATUS,
"qdebugstatus", // was only shortly used on testnet
NetMsgType::QSIGREC,
NetMsgType::CLSIG,
NetMsgType::ISLOCK,
@ -172,7 +171,6 @@ const static std::string allNetMessageTypes[] = {
NetMsgType::QJUSTIFICATION,
NetMsgType::QPCOMMITMENT,
NetMsgType::QWATCH,
NetMsgType::QDEBUGSTATUS,
NetMsgType::QSIGSESANN,
NetMsgType::QSIGSHARESINV,
NetMsgType::QGETSIGSHARES,

View File

@ -272,7 +272,6 @@ extern const char *QCOMPLAINT;
extern const char *QJUSTIFICATION;
extern const char *QPCOMMITMENT;
extern const char *QWATCH;
extern const char *QDEBUGSTATUS;
extern const char *QSIGSESANN;
extern const char *QSIGSHARESINV;
extern const char *QGETSIGSHARES;
@ -380,7 +379,7 @@ enum GetDataMsg {
MSG_QUORUM_COMPLAINT = 24,
MSG_QUORUM_JUSTIFICATION = 25,
MSG_QUORUM_PREMATURE_COMMITMENT = 26,
MSG_QUORUM_DEBUG_STATUS = 27,
/* MSG_QUORUM_DEBUG_STATUS = 27, */ // was shortly used on testnet/devnet/regtest
MSG_QUORUM_RECOVERED_SIG = 28,
MSG_CLSIG = 29,
MSG_ISLOCK = 30,

View File

@ -135,44 +135,31 @@ UniValue quorum_info(const JSONRPCRequest& request)
void quorum_dkgstatus_help()
{
throw std::runtime_error(
"quorum dkgstatus (\"proTxHash\" detail_level)\n"
"quorum dkgstatus ( detail_level )\n"
"Return the status of the current DKG process.\n"
"Works only when SPORK_17_QUORUM_DKG_ENABLED and SPORK_18_QUORUM_DEBUG_ENABLED sporks are ON.\n"
"Works only when SPORK_17_QUORUM_DKG_ENABLED spork is ON.\n"
"\nArguments:\n"
"1. \"proTxHash\" (string, optional, default=\"\") ProTxHash of masternode to show status for.\n"
" If set to an empty string, the local status is shown.\n"
"2. detail_level (number, optional, default=0) Detail level of output.\n"
"1. detail_level (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() > 3)) {
if (request.fHelp || (request.params.size() < 1 || request.params.size() > 2)) {
quorum_dkgstatus_help();
}
uint256 proTxHash;
if (request.params.size() > 1 && request.params[1].get_str() != "") {
proTxHash = ParseHashV(request.params[1], "proTxHash");
}
int detailLevel = 0;
if (request.params.size() > 2) {
detailLevel = ParseInt32V(request.params[2], "detail_level");
if (request.params.size() > 1) {
detailLevel = ParseInt32V(request.params[1], "detail_level");
if (detailLevel < 0 || detailLevel > 2) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid detail_level");
}
}
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()));
}
}
llmq::quorumDKGDebugManager->GetLocalDebugStatus(status);
auto ret = status.ToJson(detailLevel);

View File

@ -27,7 +27,6 @@ std::map<int, int64_t> mapSporkDefaults = {
{SPORK_15_DETERMINISTIC_MNS_ENABLED, 4070908800ULL}, // OFF
{SPORK_16_INSTANTSEND_AUTOLOCKS, 4070908800ULL}, // OFF
{SPORK_17_QUORUM_DKG_ENABLED, 4070908800ULL}, // OFF
{SPORK_18_QUORUM_DEBUG_ENABLED, 4070908800ULL}, // OFF
{SPORK_19_CHAINLOCKS_ENABLED, 4070908800ULL}, // OFF
{SPORK_20_INSTANTSEND_LLMQ_BASED, 4070908800ULL}, // OFF
};
@ -290,7 +289,6 @@ int CSporkManager::GetSporkIDByName(const std::string& strName)
if (strName == "SPORK_15_DETERMINISTIC_MNS_ENABLED") return SPORK_15_DETERMINISTIC_MNS_ENABLED;
if (strName == "SPORK_16_INSTANTSEND_AUTOLOCKS") return SPORK_16_INSTANTSEND_AUTOLOCKS;
if (strName == "SPORK_17_QUORUM_DKG_ENABLED") return SPORK_17_QUORUM_DKG_ENABLED;
if (strName == "SPORK_18_QUORUM_DEBUG_ENABLED") return SPORK_18_QUORUM_DEBUG_ENABLED;
if (strName == "SPORK_19_CHAINLOCKS_ENABLED") return SPORK_19_CHAINLOCKS_ENABLED;
if (strName == "SPORK_20_INSTANTSEND_LLMQ_BASED") return SPORK_20_INSTANTSEND_LLMQ_BASED;
@ -310,7 +308,6 @@ std::string CSporkManager::GetSporkNameByID(int nSporkID)
case SPORK_15_DETERMINISTIC_MNS_ENABLED: return "SPORK_15_DETERMINISTIC_MNS_ENABLED";
case SPORK_16_INSTANTSEND_AUTOLOCKS: return "SPORK_16_INSTANTSEND_AUTOLOCKS";
case SPORK_17_QUORUM_DKG_ENABLED: return "SPORK_17_QUORUM_DKG_ENABLED";
case SPORK_18_QUORUM_DEBUG_ENABLED: return "SPORK_18_QUORUM_DEBUG_ENABLED";
case SPORK_19_CHAINLOCKS_ENABLED: return "SPORK_19_CHAINLOCKS_ENABLED";
case SPORK_20_INSTANTSEND_LLMQ_BASED: return "SPORK_20_INSTANTSEND_LLMQ_BASED";
default:

View File

@ -29,7 +29,6 @@ static const int SPORK_12_RECONSIDER_BLOCKS = 10011;
static const int SPORK_15_DETERMINISTIC_MNS_ENABLED = 10014;
static const int SPORK_16_INSTANTSEND_AUTOLOCKS = 10015;
static const int SPORK_17_QUORUM_DKG_ENABLED = 10016;
static const int SPORK_18_QUORUM_DEBUG_ENABLED = 10017;
static const int SPORK_19_CHAINLOCKS_ENABLED = 10018;
static const int SPORK_20_INSTANTSEND_LLMQ_BASED = 10019;