Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/files.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Subdirectory | File(s) | Description
`indexes/blockfilter/basic/db/` | LevelDB database | Blockfilter index LevelDB database for the basic filtertype; *optional*, used if `-blockfilterindex=basic`
`indexes/blockfilter/basic/` | `fltrNNNNN.dat`<sup>[\[2\]](#note2)</sup> | Blockfilter index filters for the basic filtertype; *optional*, used if `-blockfilterindex=basic`
`indexes/coinstats/db/` | LevelDB database | Coinstats index; *optional*, used if `-coinstatsindex=1`
`indexes/govcollateralindex/` | LevelDB database | Governance proposal collateral index
`wallets/` | | [Contains wallets](#multi-wallet-environment); can be specified by `-walletdir` option; if `wallets/` subdirectory does not exist, wallets reside in the [data directory](#data-directory-location)
`./` | `anchors.dat` | Anchor IP address database, created on shutdown and deleted at startup. Anchors are last known outgoing block-relay-only peers that are tried to re-connect to on startup
`evodb/` | |special txes and quorums database
Expand Down
40 changes: 40 additions & 0 deletions doc/release-notes-7860.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Governance
----------

- Pruned nodes can now run governance. Proposal collateral is now looked up
in a new governance collateral index instead of `-txindex`. The index
stores only the transactions that could be a proposal's collateral, works
with `-prune`, and always runs; there is no option for it. Pruned nodes, and
nodes started with `-txindex=0`, now sync proposals and votes, check
superblock payments in full, and can create and submit proposals.

- Every node builds the index once, on the first start after upgrading. It
reads every block for that, and the node's governance sync waits until it
has finished.

- A node that pruned blocks before it had this index can't build it, because
the index has to start from the genesis block. It now starts with governance
turned off and a warning instead of failing; restarting it once with
`-reindex` downloads the blockchain again and enables governance, and the
node stays pruned. This replaces the warning such nodes showed before, that
governance is disabled because the node is pruned.

- Dash-Qt used to save `disablegovernance=1` in `settings.json` when pruning
was turned on in the options. That setting stays until it is removed, so
governance stays off on those nodes.

- `gobject prepare` and `gobject submit` now fail straight away on a node that
can't check or relay proposals. Before, `gobject prepare` burned the
proposal fee and only `gobject submit` failed afterwards, with the
misleading error `Invalid proposal collateral`. Collateral errors now also
say what is wrong with the collateral instead of only
`Invalid proposal collateral`.

- Pruned nodes now check superblock payments against the governance
triggers they know, like full nodes do, instead of only checking that a
superblock stays within the budget.

- `getindexinfo` reports the new index as `govcollateralindex`.

- Starting with `-prune` and `-disablegovernance=0` is no longer an error.
Governance validation no longer needs `-txindex`.
4 changes: 4 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ BITCOIN_CORE_H = \
external_signer.h \
flat-database.h \
flatfile.h \
governance/collateral.h \
governance/common.h \
governance/governance.h \
governance/net_governance.h \
Expand All @@ -271,6 +272,7 @@ BITCOIN_CORE_H = \
index/blockfilterindex.h \
index/coinstatsindex.h \
index/disktxpos.h \
index/govcollateralindex.h \
index/spentindex.h \
index/spentindex_types.h \
index/timestampindex.h \
Expand Down Expand Up @@ -574,6 +576,7 @@ libbitcoin_node_a_SOURCES = \
evo/specialtx_filter.cpp \
evo/specialtxman.cpp \
flatfile.cpp \
governance/collateral.cpp \
governance/governance.cpp \
governance/net_governance.cpp \
governance/object.cpp \
Expand All @@ -590,6 +593,7 @@ libbitcoin_node_a_SOURCES = \
index/base.cpp \
index/blockfilterindex.cpp \
index/coinstatsindex.cpp \
index/govcollateralindex.cpp \
index/spentindex.cpp \
index/timestampindex.cpp \
index/txindex.cpp \
Expand Down
1 change: 1 addition & 0 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ BITCOIN_TESTS =\
test/flatfile_tests.cpp \
test/fs_tests.cpp \
test/getarg_tests.cpp \
test/governance_collateral_tests.cpp \
test/governance_inv_tests.cpp \
test/governance_superblock_tests.cpp \
test/governance_validators_tests.cpp \
Expand Down
35 changes: 35 additions & 0 deletions src/governance/collateral.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) 2026 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 <governance/collateral.h>

#include <primitives/transaction.h>
#include <script/script.h>
#include <span.h>

#include <algorithm>

namespace governance {
bool CollateralInfo::BurnsAtLeast(const uint256& hash, CAmount amount) const
{
return std::any_of(burns.begin(), burns.end(),
[&](const auto& burn) { return burn.first == hash && burn.second >= amount; });
}

CollateralInfo GetCollateralInfo(const CTransaction& tx, const uint256& block_hash)
{
CollateralInfo info{block_hash, /*outputs_standard=*/true, /*burns=*/{}};
for (const auto& output : tx.vout) {
const CScript& script{output.scriptPubKey};
if (!script.IsPayToPublicKeyHash() && !script.IsUnspendable()) {
info.outputs_standard = false;
}
// Exactly the script `CScript() << OP_RETURN << ToByteVector(hash)` produces
if (script.size() == 2 + uint256::size() && script[0] == OP_RETURN && script[1] == uint256::size()) {
info.burns.emplace_back(uint256{Span{script}.subspan(2)}, output.nValue);
}
}
return info;
}
} // namespace governance
50 changes: 50 additions & 0 deletions src/governance/collateral.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) 2026 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_GOVERNANCE_COLLATERAL_H
#define BITCOIN_GOVERNANCE_COLLATERAL_H

#include <consensus/amount.h>
#include <serialize.h>
#include <uint256.h>

#include <optional>
#include <utility>
#include <vector>

class CTransaction;

static constexpr CAmount GOVERNANCE_PROPOSAL_FEE_TX = (1 * COIN);

namespace governance {
/** The parts of a mined transaction that decide whether it is valid proposal collateral. */
struct CollateralInfo {
uint256 block_hash;
//! Whether every output pays to P2PKH or is unspendable.
bool outputs_standard{false};
//! Value burned to each `OP_RETURN <32-byte hash>` output, together with that hash.
std::vector<std::pair<uint256, CAmount>> burns;

SERIALIZE_METHODS(CollateralInfo, obj) { READWRITE(obj.block_hash, obj.outputs_standard, obj.burns); }

bool BurnsAtLeast(const uint256& hash, CAmount amount) const;
};

CollateralInfo GetCollateralInfo(const CTransaction& tx, const uint256& block_hash);

/** Where proposal collateral is looked up. Implemented by GovCollateralIndex. */
class CollateralSource
{
public:
virtual ~CollateralSource() = default;

//! Whether every block up to the active tip has been read. Until then, a transaction that isn't
//! found may still be valid collateral.
virtual bool IsCollateralSynced() const = 0;

virtual std::optional<CollateralInfo> FindCollateral(const uint256& txid) const = 0;
};
} // namespace governance

#endif // BITCOIN_GOVERNANCE_COLLATERAL_H
16 changes: 11 additions & 5 deletions src/governance/governance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,24 @@ GovernanceStore::GovernanceStore() :

CGovernanceManager::CGovernanceManager(CMasternodeMetaMan& mn_metaman, const ChainstateManager& chainman,
governance::SuperblockManager& superblocks, CDeterministicMNManager& dmnman,
CMasternodeSync& mn_sync) :
CMasternodeSync& mn_sync, const governance::CollateralSource* collateral) :
m_db{std::make_unique<db_type>("governance.dat", "magicGovernanceCache")},
m_mn_metaman{mn_metaman},
m_chainman{chainman},
m_superblocks{superblocks},
m_dmnman{dmnman},
m_mn_sync{mn_sync},
m_collateral{collateral},
cmapVoteToObject{MAX_CACHE_SIZE},
mapPostponedObjects{}
{
}

bool CGovernanceManager::IsCollateralSourceBehind() const
{
return m_collateral && !m_collateral->IsCollateralSynced();
}

CGovernanceManager::~CGovernanceManager()
{
// Reset the paired SuperblockManager so its loaded-flag and trigger map don't
Expand Down Expand Up @@ -248,7 +254,7 @@ bool CGovernanceManager::ProcessObject(const std::string& peer_str, const uint25

const auto tip_mn_list = m_dmnman.GetListAtChainTip();
bool fMissingConfirmations = false;
bool fIsValid = govobj.IsValidLocally(tip_mn_list, m_chainman, strError, fMissingConfirmations, true);
bool fIsValid = govobj.IsValidLocally(tip_mn_list, m_chainman, m_collateral, strError, fMissingConfirmations, true);

bool unused_rcb;
if (fRateCheckBypassed && fIsValid && !MasternodeRateCheck(govobj, true, true, unused_rcb)) {
Expand Down Expand Up @@ -322,7 +328,7 @@ void CGovernanceManager::AddGovernanceObjectInternal(CGovernanceObject& insert_o

// MAKE SURE THIS OBJECT IS OK

if (!insert_obj.IsValidLocally(tip_mn_list, m_chainman, strError, true)) {
if (!insert_obj.IsValidLocally(tip_mn_list, m_chainman, m_collateral, strError, true)) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- invalid governance object - %s - (nCachedBlockHeight %d) \n", strError, nCachedBlockHeight);
return;
}
Expand Down Expand Up @@ -874,8 +880,8 @@ void CGovernanceManager::CheckPostponedObjects()

std::string strError;
bool fMissingConfirmations;
if (govobj.IsCollateralValid(m_chainman, strError, fMissingConfirmations)) {
if (govobj.IsValidLocally(m_dmnman.GetListAtChainTip(), m_chainman, strError, false)) {
if (govobj.IsCollateralValid(m_collateral, m_chainman, strError, fMissingConfirmations)) {
if (govobj.IsValidLocally(m_dmnman.GetListAtChainTip(), m_chainman, /*collateral=*/nullptr, strError, false)) {
AddGovernanceObjectInternal(govobj, "<postponed>");
} else {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::CheckPostponedObjects -- %s invalid\n", nHash.ToString());
Expand Down
8 changes: 7 additions & 1 deletion src/governance/governance.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct RPCResult;
class UniValue;

namespace governance {
class CollateralSource;
class SuperblockManager;

struct OrphanVote {
Expand Down Expand Up @@ -254,6 +255,8 @@ class CGovernanceManager : public GovernanceStore
governance::SuperblockManager& m_superblocks;
CDeterministicMNManager& m_dmnman;
CMasternodeSync& m_mn_sync;
//! Null on a node that can't look up proposal collateral
const governance::CollateralSource* const m_collateral;

int64_t nTimeLastDiff{0};
// keep track of current block height
Expand All @@ -272,11 +275,14 @@ class CGovernanceManager : public GovernanceStore
CGovernanceManager& operator=(const CGovernanceManager&) = delete;
explicit CGovernanceManager(CMasternodeMetaMan& mn_metaman, const ChainstateManager& chainman,
governance::SuperblockManager& superblocks, CDeterministicMNManager& dmnman,
CMasternodeSync& mn_sync);
CMasternodeSync& mn_sync, const governance::CollateralSource* collateral);
~CGovernanceManager();

// Basic initialization and querying
bool IsValid() const { return is_loaded; }
const governance::CollateralSource* GetCollateralSource() const { return m_collateral; }
//! Whether proposal collateral can't be checked yet because the collateral source is still catching up
bool IsCollateralSourceBehind() const;
bool LoadCache(bool load_cache)
EXCLUSIVE_LOCKS_REQUIRED(!cs_store);
[[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional);
Expand Down
17 changes: 14 additions & 3 deletions src/governance/net_governance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ void NetGovernance::Schedule(CScheduler& scheduler)
void NetGovernance::ProcessMessage(CNode& peer, const std::string& msg_type, CDataStream& vRecv)
{
if (!m_gov_manager.IsValid()) return;
// Until proposal collateral can be looked up, valid proposals would look invalid and their senders get punished
if (m_gov_manager.IsCollateralSourceBehind()) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep serving governance sync requests while catching up

When a node whose index is ready sends MNGOVERNANCESYNC to a peer that is still doing its initial index scan, this blanket return drops the sync request as well as object payloads. SyncManager::ProcessTick marks that peer's governance-sync request fulfilled before sending it and never retries it, so if the available peers are still scanning, the requester times out and advances to FINISHED without their cached objects or votes. The collateral-readiness gate should still allow sync requests to be served, or the requester needs a readiness response that causes a retry.

AGENTS.md reference: AGENTS.md:L243-L243

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not changing this here. Moving the catch-up gate below the MNGOVERNANCESYNC branch wouldn't change anything: the next check in that branch, if (!m_node_sync.IsSynced()) return;, also drops the request, and develop already has it. A node in the middle of mnsync doesn't serve governance sync today. What this PR changes is that an upgraded node stays in that state for the length of its first index build.

A requester whose request was dropped still syncs from its other peers. Serving sync requests during catch-up would mean finishing mnsync before the index has synced. That is the alternative listed under "Still open" item 1 in the PR description (only hold back proposals while the index catches up). It also needs masternodes to stop voting on triggers while proposals are missing, so I'd rather decide it separately from this fix.


🤖 Posted autonomously by Claude on behalf of pasta.

if (!m_node_sync.IsBlockchainSynced()) return;

// ANOTHER USER IS ASKING US TO HELP THEM SYNC GOVERNANCE OBJECT DATA
Expand Down Expand Up @@ -275,12 +277,21 @@ bool NetGovernance::AlreadyHave(const CInv& inv)
if (inv.type != MSG_GOVERNANCE_OBJECT && inv.type != MSG_GOVERNANCE_OBJECT_VOTE) {
return false;
}
// When governance isn't loaded (e.g. -disablegovernance), claim we already have
// the item so we don't fetch or track it in the net-layer request tracker.
if (!m_gov_manager.IsValid()) return true;
// When governance isn't loaded (e.g. -disablegovernance) or can't check collateral yet, claim we
// already have the item so we don't fetch or track it in the net-layer request tracker.
if (!m_gov_manager.IsValid() || m_gov_manager.IsCollateralSourceBehind()) return true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve inventory skipped during collateral-index catch-up

On an upgraded, already blockchain-synced node whose new index is doing its initial scan, this reports every governance object/vote INV as already held, so it is neither fetched nor queued for later. The sending peer has already recorded the hash in its per-connection known-inventory filter, and the later full MNGOVERNANCESYNC response in this file also goes through PeerRelayInv, whose net_processing.cpp::PushInv suppresses hashes in that filter. Thus an object or vote announced during the scan can remain absent after mnsync completes for connections that stay up (until reconnect/filter eviction), leaving stale governance and potentially superblock state; retain these announcements or make the post-index sync bypass/reset that suppression.

AGENTS.md reference: AGENTS.md:L243-L243

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 79df37e. Announcements received during the index scan are now held per peer, not dropped, and are requested from the announcing peer once the index has synced. The details are in the reply to the matching thepastaclaw thread on the same line.


🤖 Posted autonomously by Claude on behalf of pasta.

return !m_gov_manager.ConfirmInventoryRequest(inv);
Comment on lines +280 to 283

@thepastaclaw thepastaclaw Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Resolved at 6f28f944; see the replies below.

🔴 Blocking: Retain governance inventory ignored during index catch-up

On an upgraded, blockchain-synced node, this returns true for governance announcements throughout the new index's initial scan, so the request tracker never records or fetches them. The announcing peer nevertheless records each transmitted hash in its per-connection known-inventory filter (net_processing.cpp, lines 6797–6804). After catch-up, full governance sync and per-object vote sync both send their responses through PeerRelayInv() here, which reaches PushInv() and suppresses those already-announced hashes. Objects or votes announced during the scan can therefore remain absent after mnsync finishes on connections that stay open, leaving incomplete funding or trigger state until another recovery event, such as reconnection or filter eviction. Retain bounded deferred announcements for retrieval after readiness, or make explicit synchronization responses bypass the announcement-suppression filter. The regression test should keep the sender connection across the readiness transition and exercise the actual sync response: manually injecting the INV again, as the current unit test does, bypasses the sender-side suppression.

source: gemini-3.8-flash-high (phase1-reviewer: general); gpt-6.1-sol (phase2-reviewer: general)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 79df37e, folded into "feat(governance): run governance on pruned nodes". You're right that the fix has to be on our side: most of the peers answering our sync requests run old versions, and their PushInv keeps skipping hashes they already announced.

  • NetHandler has a new hook, DeferAnnouncement(inv). While it returns true for an inv, the INV loop in PeerManagerImpl::ProcessMessage still records the hash as known for that peer. It doesn't send the inv to AlreadyHave or the request tracker; it stores it in Peer::m_deferred_announcements instead, up to MAX_PEER_DEFERRED_ANNOUNCEMENTS (10,000) per peer. The list is freed when the peer disconnects.
  • SendMessages checks whether the handler still defers. Once it doesn't, it passes the held invs to AddObjectAnnouncement, skipping any that AlreadyHave reports, so they're fetched from the peers that announced them. While anything is still held, that check is a single call per SendMessages.
  • NetGovernance::DeferAnnouncement returns true for governance objects and votes while governance is enabled and the collateral index is behind. It doesn't depend on IsBlockchainSynced, so an mnsync reset during the scan doesn't release the announcements early only to drop them.

The test now keeps the sender connected while the index finishes, and doesn't inject the INV a second time. It announces the object once while the index is behind, checks that SendMessages sends no GETDATA, marks the index synced, and checks that SendMessages now sends a GETDATA for the object to the same peer. The object is then rejected and the peer is scored 20. With NetGovernance::DeferAnnouncement stubbed to return false, which is the old drop behavior, the GETDATA check fails.


🤖 Posted autonomously by Claude on behalf of pasta.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still applies (re-reviewed at 79df37e6): Your hook and revised test recover the retained announcement without a second INV, but the 10,000-entry cap still silently drops the remainder of a supported governance batch while keeping the connection open. Those discarded hashes remain suppressed by the sender's known-inventory filter, so the bounded queue needs an overflow-recovery path as well.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 6f28f94: when a peer's announcements overflow the held list, the peer is now disconnected and recovered through governance sync over a new connection. Details are in the reply on the new blocking thread at src/net_processing.cpp.


🤖 Posted autonomously by Claude on behalf of pasta.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved (re-reviewed at 6f28f944): Your retained queue now requests announcements from the original connection after readiness, and the overflow branch disconnects peers whose held list was truncated. Those changes address this thread's original drop-at-receipt path; the remaining replay-admission problem is tracked separately under 09140c2eb49e.

}

bool NetGovernance::DeferAnnouncement(const CInv& inv)
{
if (inv.type != MSG_GOVERNANCE_OBJECT && inv.type != MSG_GOVERNANCE_OBJECT_VOTE) {
return false;
}
// Hold exactly the announcements ProcessMessage() would drop the objects of
return m_gov_manager.IsValid() && (m_gov_manager.IsCollateralSourceBehind() || !m_node_sync.IsBlockchainSynced());
}
Comment on lines +286 to +293

@thepastaclaw thepastaclaw Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Resolved at 6f28f944; see the replies below.

🟡 Suggestion: Defer governance announcements until blockchain sync completes

If the collateral index becomes ready while CMasternodeSync is still in its blockchain stage, this hook stops deferring and SendMessages drains the buffered inventory. However, ConfirmInventoryRequest returns false while IsBlockchainSynced() is false, causing AlreadyHave to report every entry as held; std::erase_if then removes those entries without scheduling requests. This can occur during startup or when mnsync is reset during the index scan. The sender's known-inventory filter subsequently suppresses those announcements on the same connection. Continue deferring until both the collateral source and blockchain-sync state permit requesting governance inventory, and exercise that readiness transition in the existing regression.

Suggested change
bool NetGovernance::DeferAnnouncement(const CInv& inv)
{
if (inv.type != MSG_GOVERNANCE_OBJECT && inv.type != MSG_GOVERNANCE_OBJECT_VOTE) {
return false;
}
return m_gov_manager.IsValid() && m_gov_manager.IsCollateralSourceBehind();
}
bool NetGovernance::DeferAnnouncement(const CInv& inv)
{
if (inv.type != MSG_GOVERNANCE_OBJECT && inv.type != MSG_GOVERNANCE_OBJECT_VOTE) {
return false;
}
return m_gov_manager.IsValid() && (m_gov_manager.IsCollateralSourceBehind() || !m_node_sync.IsBlockchainSynced());
}

source: gemini-3.8-flash-high (phase1-reviewer: general)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already applied in addd429, which was pushed while this review of 79df37e was running. DeferAnnouncement now matches your suggestion, and the catch-up test covers the index finishing while mnsync is still in its blockchain stage.


🤖 Posted autonomously by Claude on behalf of pasta.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved (re-reviewed at 6f28f944): Your current DeferAnnouncement condition now retains governance inventory while either the collateral source is behind or blockchain sync is incomplete. The updated regression also marks the index synced, resets mnsync, and checks that retrieval waits until the blockchain stage completes.


bool NetGovernance::ProcessGetData(CNode& pfrom, const CInv& inv, const CNetMsgMaker& msgMaker)
{
if (inv.type == MSG_GOVERNANCE_OBJECT) {
Expand Down
1 change: 1 addition & 0 deletions src/governance/net_governance.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class NetGovernance final : public NetHandler
void ProcessMessage(CNode& peer, const std::string& msg_type, CDataStream& vRecv) override;

bool AlreadyHave(const CInv& inv) override;
bool DeferAnnouncement(const CInv& inv) override;
bool ProcessGetData(CNode& pfrom, const CInv& inv, const CNetMsgMaker& msgMaker) override;

private:
Expand Down
Loading
Loading