Skip to content

Commit 58ab8b3

Browse files
UdjinM6claude
authored andcommitted
fix: register NetGovernance unconditionally and tie SuperblockManager lifetime to govman
Two issues on top of the governance refactor: 1. With -disablegovernance, NetGovernance was no longer registered, so AlreadyHave/ProcessGetData stopped suppressing governance inv items. Always register the handler; AlreadyHave short-circuits to true when govman isn't loaded so peers can't grow m_requested_hash_time without a cleanup task. 2. SuperblockManager's m_loaded was sticky and the chain_helper-outlives- govman contract was undocumented and violated by the test teardown. SuperblockManager::Clear() now resets m_loaded; CGovernanceManager's destructor calls m_superblocks.Clear(); ~TestingSetup resets govman before DashChainstateSetupClose to match PrepareShutdown ordering. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 28f339e commit 58ab8b3

6 files changed

Lines changed: 24 additions & 2 deletions

File tree

src/governance/governance.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ CGovernanceManager::CGovernanceManager(CMasternodeMetaMan& mn_metaman, const Cha
7979

8080
CGovernanceManager::~CGovernanceManager()
8181
{
82+
// Reset the paired SuperblockManager so its loaded-flag and trigger map don't
83+
// outlive us. chain_helper (its owner) must outlive govman -- see PrepareShutdown
84+
// in init.cpp and the test teardown ordering.
85+
m_superblocks.Clear();
8286
if (!is_loaded) return;
8387
m_db->Store(*this);
8488
}

src/governance/net_governance.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ bool NetGovernance::AlreadyHave(const CInv& inv)
205205
if (inv.type != MSG_GOVERNANCE_OBJECT && inv.type != MSG_GOVERNANCE_OBJECT_VOTE) {
206206
return false;
207207
}
208+
// When governance isn't loaded (e.g. -disablegovernance), claim we already have
209+
// the item so we don't fetch or track it. ConfirmInventoryRequest would otherwise
210+
// grow m_requested_hash_time unbounded since CheckAndRemove never runs in that mode.
211+
if (!m_gov_manager.IsValid()) return true;
208212
return !m_gov_manager.ConfirmInventoryRequest(inv);
209213
}
210214

src/governance/superblock.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,7 @@ void SuperblockManager::Clear()
521521
{
522522
LOCK(cs_sb);
523523
m_triggers.clear();
524+
m_loaded = false;
524525
}
525526

526527
std::vector<CSuperblock_sptr> SuperblockManager::GetActiveTriggers() const

src/governance/superblock.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ namespace governance {
123123
* AddTrigger() and notifies us via RemoveTrigger() when it erases the
124124
* underlying object from its store. Each entry holds a strong reference
125125
* to the underlying CGovernanceObject so we never look it up by hash.
126+
*
127+
* Lifetime: typically owned by CChainstateHelper, which outlives the
128+
* paired CGovernanceManager. The govman drives m_loaded via SetLoaded()
129+
* from LoadCache() and Clear()s us in its destructor, so IsValid() and
130+
* the trigger map track the live govman's state.
126131
*/
127132
class SuperblockManager
128133
{

src/init.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2270,8 +2270,12 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
22702270
}
22712271
return InitError(strprintf(_("Failed to clear governance cache at %s"), file_path));
22722272
}
2273-
node.peerman->AddExtraHandler(std::make_unique<NetGovernance>(node.peerman.get(), *node.govman, *node.mn_sync, *node.netfulfilledman, *node.connman));
22742273
}
2274+
// Always register NetGovernance so it can suppress governance inv items in AlreadyHave()
2275+
// even when -disablegovernance is set. The handler's ProcessMessage/Schedule paths
2276+
// early-return on !IsValid(), and AlreadyHave() short-circuits to true so we don't grow
2277+
// m_requested_hash_time without a cleanup task.
2278+
node.peerman->AddExtraHandler(std::make_unique<NetGovernance>(node.peerman.get(), *node.govman, *node.mn_sync, *node.netfulfilledman, *node.connman));
22752279
node.peerman->AddExtraHandler(std::make_unique<SyncManager>(node.peerman.get(), *node.govman, *node.mn_sync, *node.connman, *node.netfulfilledman));
22762280

22772281
// ********************************************************* Step 8: start indexers

src/test/util/setup_common.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,6 @@ ChainTestingSetup::~ChainTestingSetup()
303303
StopScriptCheckWorkerThreads();
304304
GetMainSignals().FlushBackgroundCallbacks();
305305
GetMainSignals().UnregisterBackgroundSignalScheduler();
306-
m_node.govman.reset();
307306
m_node.mn_sync.reset();
308307
m_node.chainman.reset();
309308
m_node.mempool.reset();
@@ -432,6 +431,11 @@ TestingSetup::~TestingSetup()
432431
m_node.connman->Stop();
433432
}
434433

434+
// govman holds a reference to chain_helper->superblocks, so it must be reset
435+
// before DashChainstateSetupClose() destroys chain_helper (matches PrepareShutdown
436+
// ordering in init.cpp).
437+
m_node.govman.reset();
438+
435439
// DashChainstateSetup() is called by LoadChainstate() internally but
436440
// winding them down is our responsibility
437441
DashChainstateSetupClose(m_node);

0 commit comments

Comments
 (0)