From bf54a5dbb5aef52f2d2224eecfe3f571336b5d0a Mon Sep 17 00:00:00 2001 From: pasta Date: Wed, 28 Aug 2024 11:06:24 -0500 Subject: [PATCH 1/7] feat: add transactions.mempool.lockedTransactions and chainlocks.blockHeight stats --- src/init.cpp | 2 ++ src/llmq/chainlocks.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index 1abb710513..2d044532ef 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -833,6 +833,7 @@ static void PeriodicStats(NodeContext& node) const ArgsManager& args = *Assert(node.args); ChainstateManager& chainman = *Assert(node.chainman); const CTxMemPool& mempool = *Assert(node.mempool); + const llmq::CInstantSendManager& isman = *Assert(node.llmq_ctx->isman); CCoinsStats stats{CoinStatsHashType::NONE}; chainman.ActiveChainstate().ForceFlushStateToDisk(); if (WITH_LOCK(cs_main, return GetUTXOStats(&chainman.ActiveChainstate().CoinsDB(), chainman.m_blockman, stats, node.rpc_interruption_point, chainman.ActiveChain().Tip()))) { @@ -880,6 +881,7 @@ static void PeriodicStats(NodeContext& node) ::g_stats_client->gauge("transactions.mempool.memoryUsageBytes", (int64_t) mempool.DynamicMemoryUsage(), 1.0f); ::g_stats_client->gauge("transactions.mempool.minFeePerKb", mempool.GetMinFee(args.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK(), 1.0f); } + ::g_stats_client.gauge("transactions.mempool.lockedTransactions", isman.GetInstantSendLockCount(), 1.0f); } static bool AppInitServers(NodeContext& node) diff --git a/src/llmq/chainlocks.cpp b/src/llmq/chainlocks.cpp index 1ef7d22b91..33fb70953b 100644 --- a/src/llmq/chainlocks.cpp +++ b/src/llmq/chainlocks.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -499,6 +500,7 @@ void CChainLocksHandler::EnforceBestChainLock() GetMainSignals().NotifyChainLock(currentBestChainLockBlockIndex, clsig); uiInterface.NotifyChainLock(clsig->getBlockHash().ToString(), clsig->getHeight()); + statsClient.gauge("chainlocks.blockHeight", clsig->getHeight(), 1.0f); } MessageProcessingResult CChainLocksHandler::HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig) From 749d371d235dde9c05dcde883295f13ffe6dc069 Mon Sep 17 00:00:00 2001 From: pasta Date: Wed, 28 Aug 2024 19:02:29 -0500 Subject: [PATCH 2/7] fix: add 1 to tip.Height so output matches RPCs such as getblockcount --- src/validation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index 1074bb065f..97eb0a7ce6 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2301,7 +2301,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, ::g_stats_client->timing("ConnectBlock_ms", (nTime8 - nTimeStart) / 1000, 1.0f); ::g_stats_client->gauge("blocks.tip.SizeBytes", ::GetSerializeSize(block, PROTOCOL_VERSION), 1.0f); - ::g_stats_client->gauge("blocks.tip.Height", m_chain.Height(), 1.0f); + ::g_stats_client->gauge("blocks.tip.Height", m_chain.Height() + 1, 1.0f); // without the +1, the "tip.Height" doesn't match rpc calls like `getblockcount` ::g_stats_client->gauge("blocks.tip.Version", block.nVersion, 1.0f); ::g_stats_client->gauge("blocks.tip.NumTransactions", block.vtx.size(), 1.0f); ::g_stats_client->gauge("blocks.tip.SigOps", nSigOps, 1.0f); From b836f25e1a4d8b64d9b72f7c7796720f7431c8dd Mon Sep 17 00:00:00 2001 From: pasta Date: Wed, 28 Aug 2024 19:03:08 -0500 Subject: [PATCH 3/7] feat: implement masternode counts in stats --- src/evo/deterministicmns.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index 96fbe4c02c..b38e0d3f0b 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -645,6 +646,15 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, gsl::not_nullGetBlockHash()) { LogPrintf("CDeterministicMNManager::%s -- DIP3 enforcement block has wrong hash: hash=%s, expected=%s, nHeight=%d\n", __func__, From 508bade8c3c1224a501676926f5dab09e0eeef1e Mon Sep 17 00:00:00 2001 From: pasta Date: Wed, 28 Aug 2024 19:22:38 -0500 Subject: [PATCH 4/7] feat: add islock timing statistics --- src/llmq/instantsend.cpp | 21 +++++++++++++++++++++ src/llmq/instantsend.h | 3 +++ 2 files changed, 24 insertions(+) diff --git a/src/llmq/instantsend.cpp b/src/llmq/instantsend.cpp index d027ff94c3..84248a9831 100644 --- a/src/llmq/instantsend.cpp +++ b/src/llmq/instantsend.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -774,6 +775,17 @@ PeerMsgRet CInstantSendManager::ProcessMessageInstantSendLock(const CNode& pfrom LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: received islock, peer=%d\n", __func__, islock->txid.ToString(), hash.ToString(), pfrom.GetId()); + auto time_diff = [&] () -> int64_t { + LOCK(cs_timingsTxSeen); + if (auto it = timingsTxSeen.find(islock->txid); it != timingsTxSeen.end()) { + // This is the normal case where we received the TX before the islock + return GetTimeMillis() - it->second; + } + // But if we received the islock and don't know when we got the tx, then say 0, to indicate we received the islock first. + return 0; + }(); + statsClient.timing("islock_ms", time_diff); + LOCK(cs_pendingLocks); pendingInstantSendLocks.emplace(hash, std::make_pair(pfrom.GetId(), islock)); return {}; @@ -1164,6 +1176,15 @@ void CInstantSendManager::AddNonLockedTx(const CTransactionRef& tx, const CBlock ++it; } } + + { + LOCK(cs_timingsTxSeen); + // Only insert the time the first time we see the tx, as we sometimes try to resign + if (auto it = timingsTxSeen.find(tx->GetHash()); it == timingsTxSeen.end()) { + timingsTxSeen[tx->GetHash()] = GetTimeMillis(); + } + } + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, pindexMined=%s\n", __func__, tx->GetHash().ToString(), pindexMined ? pindexMined->GetBlockHash().ToString() : ""); } diff --git a/src/llmq/instantsend.h b/src/llmq/instantsend.h index 2b83878e9a..87f96d6042 100644 --- a/src/llmq/instantsend.h +++ b/src/llmq/instantsend.h @@ -253,6 +253,9 @@ private: mutable Mutex cs_pendingRetry; std::unordered_set pendingRetryTxs GUARDED_BY(cs_pendingRetry); + mutable Mutex cs_timingsTxSeen; + std::unordered_map timingsTxSeen GUARDED_BY(cs_timingsTxSeen); + public: explicit CInstantSendManager(CChainLocksHandler& _clhandler, CChainState& chainstate, CQuorumManager& _qman, CSigningManager& _sigman, CSigSharesManager& _shareman, CSporkManager& sporkman, From 3e5242283c2ccc172102724dffd0ed11a7ca0cee Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Thu, 5 Sep 2024 23:48:40 +0300 Subject: [PATCH 5/7] fix: update `blocks.tip.*` stats in `ConnectTip`/`DisconnectTip` instead of `ConnectBlock` --- src/validation.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/validation.cpp b/src/validation.cpp index 97eb0a7ce6..cdba67dfae 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2623,6 +2623,8 @@ bool CChainState::DisconnectTip(BlockValidationState& state, DisconnectedBlockTr AssertLockHeld(cs_main); if (m_mempool) AssertLockHeld(m_mempool->cs); + int64_t nTime1 = GetTimeMicros(); + CBlockIndex *pindexDelete = m_chain.Tip(); assert(pindexDelete); // Read block from disk. @@ -2681,6 +2683,19 @@ bool CChainState::DisconnectTip(BlockValidationState& state, DisconnectedBlockTr // Let wallets know transactions went from 1-confirmed to // 0-confirmed or conflicted: GetMainSignals().BlockDisconnected(pblock, pindexDelete); + + int64_t nTime2 = GetTimeMicros(); + + unsigned int nSigOps = 0; + for (const auto& tx : block.vtx) { + nSigOps += GetLegacySigOpCount(*tx); + } + statsClient.timing("DisconnectTip_ms", (nTime2 - nTime1) / 1000, 1.0f); + statsClient.gauge("blocks.tip.SizeBytes", ::GetSerializeSize(block, PROTOCOL_VERSION), 1.0f); + statsClient.gauge("blocks.tip.Height", m_chain.Height(), 1.0f); + statsClient.gauge("blocks.tip.Version", block.nVersion, 1.0f); + statsClient.gauge("blocks.tip.NumTransactions", block.vtx.size(), 1.0f); + statsClient.gauge("blocks.tip.SigOps", nSigOps, 1.0f); return true; } @@ -2799,7 +2814,16 @@ bool CChainState::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew LogPrint(BCLog::BENCHMARK, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime5) * MILLI, nTimePostConnect * MICRO, nTimePostConnect * MILLI / nBlocksTotal); LogPrint(BCLog::BENCHMARK, "- Connect block: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime1) * MILLI, nTimeTotal * MICRO, nTimeTotal * MILLI / nBlocksTotal); + unsigned int nSigOps = 0; + for (const auto& tx : blockConnecting.vtx) { + nSigOps += GetLegacySigOpCount(*tx); + } ::g_stats_client->timing("ConnectTip_ms", (nTime6 - nTime1) / 1000, 1.0f); + ::g_stats_client->gauge("blocks.tip.SizeBytes", ::GetSerializeSize(blockConnecting, PROTOCOL_VERSION), 1.0f); + ::g_stats_client->gauge("blocks.tip.Height", m_chain.Height(), 1.0f); + ::g_stats_client->gauge("blocks.tip.Version", blockConnecting.nVersion, 1.0f); + ::g_stats_client->gauge("blocks.tip.NumTransactions", blockConnecting.vtx.size(), 1.0f); + ::g_stats_client->gauge("blocks.tip.SigOps", nSigOps, 1.0f); connectTrace.BlockConnected(pindexNew, std::move(pthisBlock)); return true; From 3574550382ec0a682a259eb1b70060c8201cd0dd Mon Sep 17 00:00:00 2001 From: pasta Date: Sat, 7 Dec 2024 14:45:26 -0600 Subject: [PATCH 6/7] fixup: compilation errors --- src/evo/deterministicmns.cpp | 18 +++++++++--------- src/init.cpp | 2 +- src/llmq/chainlocks.cpp | 4 ++-- src/llmq/instantsend.cpp | 4 ++-- src/validation.cpp | 12 ++++++------ 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index b38e0d3f0b..f48c59c977 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include @@ -646,14 +646,14 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, gsl::not_nullgauge("masternodes.count", newList.GetAllMNsCount()); + ::g_stats_client->gauge("masternodes.weighted_count", newList.GetValidWeightedMNsCount()); + ::g_stats_client->gauge("masternodes.enabled", newList.GetValidMNsCount()); + ::g_stats_client->gauge("masternodes.weighted_enabled", newList.GetValidWeightedMNsCount()); + ::g_stats_client->gauge("masternodes.evo.count", newList.GetAllEvoCount()); + ::g_stats_client->gauge("masternodes.evo.enabled", newList.GetValidEvoCount()); + ::g_stats_client->gauge("masternodes.mn.count", newList.GetAllMNsCount() - newList.GetAllEvoCount()); + ::g_stats_client->gauge("masternodes.mn.enabled", newList.GetValidMNsCount() - newList.GetValidEvoCount()); if (nHeight == consensusParams.DIP0003EnforcementHeight) { if (!consensusParams.DIP0003EnforcementHash.IsNull() && consensusParams.DIP0003EnforcementHash != pindex->GetBlockHash()) { diff --git a/src/init.cpp b/src/init.cpp index 2d044532ef..28adfa735d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -881,7 +881,7 @@ static void PeriodicStats(NodeContext& node) ::g_stats_client->gauge("transactions.mempool.memoryUsageBytes", (int64_t) mempool.DynamicMemoryUsage(), 1.0f); ::g_stats_client->gauge("transactions.mempool.minFeePerKb", mempool.GetMinFee(args.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK(), 1.0f); } - ::g_stats_client.gauge("transactions.mempool.lockedTransactions", isman.GetInstantSendLockCount(), 1.0f); + ::g_stats_client->gauge("transactions.mempool.lockedTransactions", isman.GetInstantSendLockCount(), 1.0f); } static bool AppInitServers(NodeContext& node) diff --git a/src/llmq/chainlocks.cpp b/src/llmq/chainlocks.cpp index 33fb70953b..d0845751a6 100644 --- a/src/llmq/chainlocks.cpp +++ b/src/llmq/chainlocks.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -500,7 +500,7 @@ void CChainLocksHandler::EnforceBestChainLock() GetMainSignals().NotifyChainLock(currentBestChainLockBlockIndex, clsig); uiInterface.NotifyChainLock(clsig->getBlockHash().ToString(), clsig->getHeight()); - statsClient.gauge("chainlocks.blockHeight", clsig->getHeight(), 1.0f); + ::g_stats_client->gauge("chainlocks.blockHeight", clsig->getHeight(), 1.0f); } MessageProcessingResult CChainLocksHandler::HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig) diff --git a/src/llmq/instantsend.cpp b/src/llmq/instantsend.cpp index 84248a9831..cab3e5818c 100644 --- a/src/llmq/instantsend.cpp +++ b/src/llmq/instantsend.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include @@ -784,7 +784,7 @@ PeerMsgRet CInstantSendManager::ProcessMessageInstantSendLock(const CNode& pfrom // But if we received the islock and don't know when we got the tx, then say 0, to indicate we received the islock first. return 0; }(); - statsClient.timing("islock_ms", time_diff); + ::g_stats_client->timing("islock_ms", time_diff); LOCK(cs_pendingLocks); pendingInstantSendLocks.emplace(hash, std::make_pair(pfrom.GetId(), islock)); diff --git a/src/validation.cpp b/src/validation.cpp index cdba67dfae..80bf055a99 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2690,12 +2690,12 @@ bool CChainState::DisconnectTip(BlockValidationState& state, DisconnectedBlockTr for (const auto& tx : block.vtx) { nSigOps += GetLegacySigOpCount(*tx); } - statsClient.timing("DisconnectTip_ms", (nTime2 - nTime1) / 1000, 1.0f); - statsClient.gauge("blocks.tip.SizeBytes", ::GetSerializeSize(block, PROTOCOL_VERSION), 1.0f); - statsClient.gauge("blocks.tip.Height", m_chain.Height(), 1.0f); - statsClient.gauge("blocks.tip.Version", block.nVersion, 1.0f); - statsClient.gauge("blocks.tip.NumTransactions", block.vtx.size(), 1.0f); - statsClient.gauge("blocks.tip.SigOps", nSigOps, 1.0f); + ::g_stats_client->timing("DisconnectTip_ms", (nTime2 - nTime1) / 1000, 1.0f); + ::g_stats_client->gauge("blocks.tip.SizeBytes", ::GetSerializeSize(block, PROTOCOL_VERSION), 1.0f); + ::g_stats_client->gauge("blocks.tip.Height", m_chain.Height(), 1.0f); + ::g_stats_client->gauge("blocks.tip.Version", block.nVersion, 1.0f); + ::g_stats_client->gauge("blocks.tip.NumTransactions", block.vtx.size(), 1.0f); + ::g_stats_client->gauge("blocks.tip.SigOps", nSigOps, 1.0f); return true; } From 7bbbc15db0fe81d8983421b7991fdaf2c33c51e8 Mon Sep 17 00:00:00 2001 From: pasta Date: Tue, 17 Dec 2024 11:39:31 -0600 Subject: [PATCH 7/7] fixup: avoid expensive evaluations in stats code --- src/evo/deterministicmns.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index f48c59c977..b2a36543a2 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -646,14 +646,16 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, gsl::not_nullgauge("masternodes.count", newList.GetAllMNsCount()); - ::g_stats_client->gauge("masternodes.weighted_count", newList.GetValidWeightedMNsCount()); - ::g_stats_client->gauge("masternodes.enabled", newList.GetValidMNsCount()); - ::g_stats_client->gauge("masternodes.weighted_enabled", newList.GetValidWeightedMNsCount()); - ::g_stats_client->gauge("masternodes.evo.count", newList.GetAllEvoCount()); - ::g_stats_client->gauge("masternodes.evo.enabled", newList.GetValidEvoCount()); - ::g_stats_client->gauge("masternodes.mn.count", newList.GetAllMNsCount() - newList.GetAllEvoCount()); - ::g_stats_client->gauge("masternodes.mn.enabled", newList.GetValidMNsCount() - newList.GetValidEvoCount()); + if (::g_stats_client->active()) { + ::g_stats_client->gauge("masternodes.count", newList.GetAllMNsCount()); + ::g_stats_client->gauge("masternodes.weighted_count", newList.GetValidWeightedMNsCount()); + ::g_stats_client->gauge("masternodes.enabled", newList.GetValidMNsCount()); + ::g_stats_client->gauge("masternodes.weighted_enabled", newList.GetValidWeightedMNsCount()); + ::g_stats_client->gauge("masternodes.evo.count", newList.GetAllEvoCount()); + ::g_stats_client->gauge("masternodes.evo.enabled", newList.GetValidEvoCount()); + ::g_stats_client->gauge("masternodes.mn.count", newList.GetAllMNsCount() - newList.GetAllEvoCount()); + ::g_stats_client->gauge("masternodes.mn.enabled", newList.GetValidMNsCount() - newList.GetValidEvoCount()); + } if (nHeight == consensusParams.DIP0003EnforcementHeight) { if (!consensusParams.DIP0003EnforcementHash.IsNull() && consensusParams.DIP0003EnforcementHash != pindex->GetBlockHash()) {