aboutsummaryrefslogtreecommitdiff
path: root/src/net_processing.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net_processing.cpp')
-rw-r--r--src/net_processing.cpp236
1 files changed, 116 insertions, 120 deletions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 6597019797..be6777d14b 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -10,7 +10,6 @@
#include <blockencodings.h>
#include <blockfilter.h>
#include <chainparams.h>
-#include <common/args.h>
#include <consensus/amount.h>
#include <consensus/validation.h>
#include <deploymentstatus.h>
@@ -487,7 +486,7 @@ class PeerManagerImpl final : public PeerManager
public:
PeerManagerImpl(CConnman& connman, AddrMan& addrman,
BanMan* banman, ChainstateManager& chainman,
- CTxMemPool& pool, bool ignore_incoming_txs);
+ CTxMemPool& pool, Options opts);
/** Overridden from CValidationInterface. */
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) override
@@ -515,7 +514,7 @@ public:
std::optional<std::string> FetchBlock(NodeId peer_id, const CBlockIndex& block_index) override
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
- bool IgnoresIncomingTxs() override { return m_ignore_incoming_txs; }
+ bool IgnoresIncomingTxs() override { return m_opts.ignore_incoming_txs; }
void SendPings() override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
void RelayTransaction(const uint256& txid, const uint256& wtxid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
void SetBestHeight(int height) override { m_best_height = height; };
@@ -568,7 +567,7 @@ private:
*
* @return Returns true if the peer was punished (probably disconnected)
*/
- bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = "")
+ bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state)
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
/** Maybe disconnect a peer and discourage future connections from its address.
@@ -718,8 +717,7 @@ private:
/** Next time to check for stale tip */
std::chrono::seconds m_stale_tip_check_time GUARDED_BY(cs_main){0s};
- /** Whether this node is running in -blocksonly mode */
- const bool m_ignore_incoming_txs;
+ const Options m_opts;
bool RejectIncomingTxs(const CNode& peer) const;
@@ -918,6 +916,10 @@ private:
/** Process a new block. Perform any post-processing housekeeping */
void ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing, bool min_pow_checked);
+ /** Process compact block txns */
+ void ProcessCompactBlockTxns(CNode& pfrom, Peer& peer, const BlockTransactions& block_transactions)
+ EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex, !m_most_recent_block_mutex);
+
/**
* When a peer sends us a valid block, instruct it to announce blocks to us
* using CMPCTBLOCK if possible by adding its nodeid to the end of
@@ -1208,7 +1210,7 @@ void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid)
// When in -blocksonly mode, never request high-bandwidth mode from peers. Our
// mempool will not contain the transactions necessary to reconstruct the
// compact block.
- if (m_ignore_incoming_txs) return;
+ if (m_opts.ignore_incoming_txs) return;
CNodeState* nodestate = State(nodeid);
if (!nodestate || !nodestate->m_provides_cmpctblocks) {
@@ -1646,13 +1648,12 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c
void PeerManagerImpl::AddToCompactExtraTransactions(const CTransactionRef& tx)
{
- size_t max_extra_txn = gArgs.GetIntArg("-blockreconstructionextratxn", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN);
- if (max_extra_txn <= 0)
+ if (m_opts.max_extra_txs <= 0)
return;
if (!vExtraTxnForCompact.size())
- vExtraTxnForCompact.resize(max_extra_txn);
+ vExtraTxnForCompact.resize(m_opts.max_extra_txs);
vExtraTxnForCompact[vExtraTxnForCompactIt] = std::make_pair(tx->GetWitnessHash(), tx);
- vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % max_extra_txn;
+ vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
}
void PeerManagerImpl::Misbehaving(Peer& peer, int howmuch, const std::string& message)
@@ -1731,7 +1732,7 @@ bool PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidati
return false;
}
-bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message)
+bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state)
{
PeerRef peer{GetPeerRef(nodeid)};
switch (state.GetResult()) {
@@ -1739,7 +1740,7 @@ bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationStat
break;
// The node is providing invalid data:
case TxValidationResult::TX_CONSENSUS:
- if (peer) Misbehaving(*peer, 100, message);
+ if (peer) Misbehaving(*peer, 100, "");
return true;
// Conflicting (but not necessarily invalid) data or different policy:
case TxValidationResult::TX_RECENT_CONSENSUS_CHANGE:
@@ -1754,9 +1755,6 @@ bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationStat
case TxValidationResult::TX_NO_MEMPOOL:
break;
}
- if (message != "") {
- LogPrint(BCLog::NET, "peer=%d: %s\n", nodeid, message);
- }
return false;
}
@@ -1808,25 +1806,25 @@ std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBl
std::unique_ptr<PeerManager> PeerManager::make(CConnman& connman, AddrMan& addrman,
BanMan* banman, ChainstateManager& chainman,
- CTxMemPool& pool, bool ignore_incoming_txs)
+ CTxMemPool& pool, Options opts)
{
- return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman, pool, ignore_incoming_txs);
+ return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman, pool, opts);
}
PeerManagerImpl::PeerManagerImpl(CConnman& connman, AddrMan& addrman,
BanMan* banman, ChainstateManager& chainman,
- CTxMemPool& pool, bool ignore_incoming_txs)
+ CTxMemPool& pool, Options opts)
: m_chainparams(chainman.GetParams()),
m_connman(connman),
m_addrman(addrman),
m_banman(banman),
m_chainman(chainman),
m_mempool(pool),
- m_ignore_incoming_txs(ignore_incoming_txs)
+ m_opts{opts}
{
// While Erlay support is incomplete, it must be enabled explicitly via -txreconciliation.
// This argument can go away after Erlay support is complete.
- if (gArgs.GetBoolArg("-txreconciliation", DEFAULT_TXRECONCILIATION_ENABLE)) {
+ if (opts.reconcile_txs) {
m_txreconciliation = std::make_unique<TxReconciliationTracker>(TXRECONCILIATION_VERSION);
}
}
@@ -2728,7 +2726,7 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, c
last_header.nHeight);
}
if (vGetData.size() > 0) {
- if (!m_ignore_incoming_txs &&
+ if (!m_opts.ignore_incoming_txs &&
nodestate->m_provides_cmpctblocks &&
vGetData.size() == 1 &&
mapBlocksInFlight.size() == 1 &&
@@ -3204,6 +3202,93 @@ void PeerManagerImpl::ProcessBlock(CNode& node, const std::shared_ptr<const CBlo
}
}
+void PeerManagerImpl::ProcessCompactBlockTxns(CNode& pfrom, Peer& peer, const BlockTransactions& block_transactions)
+{
+ std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
+ bool fBlockRead{false};
+ const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
+ {
+ LOCK(cs_main);
+
+ auto range_flight = mapBlocksInFlight.equal_range(block_transactions.blockhash);
+ size_t already_in_flight = std::distance(range_flight.first, range_flight.second);
+ bool requested_block_from_this_peer{false};
+
+ // Multimap ensures ordering of outstanding requests. It's either empty or first in line.
+ bool first_in_flight = already_in_flight == 0 || (range_flight.first->second.first == pfrom.GetId());
+
+ while (range_flight.first != range_flight.second) {
+ auto [node_id, block_it] = range_flight.first->second;
+ if (node_id == pfrom.GetId() && block_it->partialBlock) {
+ requested_block_from_this_peer = true;
+ break;
+ }
+ range_flight.first++;
+ }
+
+ if (!requested_block_from_this_peer) {
+ LogPrint(BCLog::NET, "Peer %d sent us block transactions for block we weren't expecting\n", pfrom.GetId());
+ return;
+ }
+
+ PartiallyDownloadedBlock& partialBlock = *range_flight.first->second.second->partialBlock;
+ ReadStatus status = partialBlock.FillBlock(*pblock, block_transactions.txn);
+ if (status == READ_STATUS_INVALID) {
+ RemoveBlockRequest(block_transactions.blockhash, pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect
+ Misbehaving(peer, 100, "invalid compact block/non-matching block transactions");
+ return;
+ } else if (status == READ_STATUS_FAILED) {
+ if (first_in_flight) {
+ // Might have collided, fall back to getdata now :(
+ std::vector<CInv> invs;
+ invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(peer), block_transactions.blockhash));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
+ } else {
+ RemoveBlockRequest(block_transactions.blockhash, pfrom.GetId());
+ LogPrint(BCLog::NET, "Peer %d sent us a compact block but it failed to reconstruct, waiting on first download to complete\n", pfrom.GetId());
+ return;
+ }
+ } else {
+ // Block is either okay, or possibly we received
+ // READ_STATUS_CHECKBLOCK_FAILED.
+ // Note that CheckBlock can only fail for one of a few reasons:
+ // 1. bad-proof-of-work (impossible here, because we've already
+ // accepted the header)
+ // 2. merkleroot doesn't match the transactions given (already
+ // caught in FillBlock with READ_STATUS_FAILED, so
+ // impossible here)
+ // 3. the block is otherwise invalid (eg invalid coinbase,
+ // block is too big, too many legacy sigops, etc).
+ // So if CheckBlock failed, #3 is the only possibility.
+ // Under BIP 152, we don't discourage the peer unless proof of work is
+ // invalid (we don't require all the stateless checks to have
+ // been run). This is handled below, so just treat this as
+ // though the block was successfully read, and rely on the
+ // handling in ProcessNewBlock to ensure the block index is
+ // updated, etc.
+ RemoveBlockRequest(block_transactions.blockhash, pfrom.GetId()); // it is now an empty pointer
+ fBlockRead = true;
+ // mapBlockSource is used for potentially punishing peers and
+ // updating which peers send us compact blocks, so the race
+ // between here and cs_main in ProcessNewBlock is fine.
+ // BIP 152 permits peers to relay compact blocks after validating
+ // the header only; we should not punish peers if the block turns
+ // out to be invalid.
+ mapBlockSource.emplace(block_transactions.blockhash, std::make_pair(pfrom.GetId(), false));
+ }
+ } // Don't hold cs_main when we call into ProcessNewBlock
+ if (fBlockRead) {
+ // Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
+ // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
+ // This bypasses some anti-DoS logic in AcceptBlock (eg to prevent
+ // disk-space attacks), but this should be safe due to the
+ // protections in the compact block handler -- see related comment
+ // in compact block optimistic reconstruction handling.
+ ProcessBlock(pfrom, pblock, /*force_processing=*/true, /*min_pow_checked=*/true);
+ }
+ return;
+}
+
void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
const std::chrono::microseconds time_received,
const std::atomic<bool>& interruptMsgProc)
@@ -3346,7 +3431,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// - we are not in -blocksonly mode.
const auto* tx_relay = peer->GetTxRelay();
if (tx_relay && WITH_LOCK(tx_relay->m_bloom_filter_mutex, return tx_relay->m_relay_txs) &&
- !pfrom.IsAddrFetchConn() && !m_ignore_incoming_txs) {
+ !pfrom.IsAddrFetchConn() && !m_opts.ignore_incoming_txs) {
const uint64_t recon_salt = m_txreconciliation->PreRegisterPeer(pfrom.GetId());
m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::SENDTXRCNCL,
TXRECONCILIATION_VERSION, recon_salt));
@@ -4151,8 +4236,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
// DoS prevention: do not allow m_orphanage to grow unbounded (see CVE-2012-3789)
- unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, gArgs.GetIntArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS));
- m_orphanage.LimitOrphans(nMaxOrphanTx);
+ m_orphanage.LimitOrphans(m_opts.max_orphan_txs);
} else {
LogPrint(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s\n",tx.GetHash().ToString());
// We will continue to reject this tx since it has rejected
@@ -4276,12 +4360,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
blockhash.ToString(), pfrom.GetId());
}
- // When we succeed in decoding a block's txids from a cmpctblock
- // message we typically jump to the BLOCKTXN handling code, with a
- // dummy (empty) BLOCKTXN message, to re-use the logic there in
- // completing processing of the putative block (without cs_main).
bool fProcessBLOCKTXN = false;
- CDataStream blockTxnMsg(SER_NETWORK, PROTOCOL_VERSION);
// If we end up treating this as a plain headers message, call that as well
// without cs_main.
@@ -4382,10 +4461,6 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
req.indexes.push_back(i);
}
if (req.indexes.empty()) {
- // Dirty hack to jump to BLOCKTXN code (TODO: move message handling into their own functions)
- BlockTransactions txn;
- txn.blockhash = blockhash;
- blockTxnMsg << txn;
fProcessBLOCKTXN = true;
} else if (first_in_flight) {
// We will try to round-trip any compact blocks we get on failure,
@@ -4440,7 +4515,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
} // cs_main
if (fProcessBLOCKTXN) {
- return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, time_received, interruptMsgProc);
+ BlockTransactions txn;
+ txn.blockhash = blockhash;
+ return ProcessCompactBlockTxns(pfrom, *peer, txn);
}
if (fRevertToHeaderProcessing) {
@@ -4492,88 +4569,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
BlockTransactions resp;
vRecv >> resp;
- std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
- bool fBlockRead = false;
- {
- LOCK(cs_main);
-
- auto range_flight = mapBlocksInFlight.equal_range(resp.blockhash);
- size_t already_in_flight = std::distance(range_flight.first, range_flight.second);
- bool requested_block_from_this_peer{false};
-
- // Multimap ensures ordering of outstanding requests. It's either empty or first in line.
- bool first_in_flight = already_in_flight == 0 || (range_flight.first->second.first == pfrom.GetId());
-
- while (range_flight.first != range_flight.second) {
- auto [node_id, block_it] = range_flight.first->second;
- if (node_id == pfrom.GetId() && block_it->partialBlock) {
- requested_block_from_this_peer = true;
- break;
- }
- range_flight.first++;
- }
-
- if (!requested_block_from_this_peer) {
- LogPrint(BCLog::NET, "Peer %d sent us block transactions for block we weren't expecting\n", pfrom.GetId());
- return;
- }
-
- PartiallyDownloadedBlock& partialBlock = *range_flight.first->second.second->partialBlock;
- ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn);
- if (status == READ_STATUS_INVALID) {
- RemoveBlockRequest(resp.blockhash, pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect
- Misbehaving(*peer, 100, "invalid compact block/non-matching block transactions");
- return;
- } else if (status == READ_STATUS_FAILED) {
- if (first_in_flight) {
- // Might have collided, fall back to getdata now :(
- std::vector<CInv> invs;
- invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(*peer), resp.blockhash));
- m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
- } else {
- RemoveBlockRequest(resp.blockhash, pfrom.GetId());
- LogPrint(BCLog::NET, "Peer %d sent us a compact block but it failed to reconstruct, waiting on first download to complete\n", pfrom.GetId());
- return;
- }
- } else {
- // Block is either okay, or possibly we received
- // READ_STATUS_CHECKBLOCK_FAILED.
- // Note that CheckBlock can only fail for one of a few reasons:
- // 1. bad-proof-of-work (impossible here, because we've already
- // accepted the header)
- // 2. merkleroot doesn't match the transactions given (already
- // caught in FillBlock with READ_STATUS_FAILED, so
- // impossible here)
- // 3. the block is otherwise invalid (eg invalid coinbase,
- // block is too big, too many legacy sigops, etc).
- // So if CheckBlock failed, #3 is the only possibility.
- // Under BIP 152, we don't discourage the peer unless proof of work is
- // invalid (we don't require all the stateless checks to have
- // been run). This is handled below, so just treat this as
- // though the block was successfully read, and rely on the
- // handling in ProcessNewBlock to ensure the block index is
- // updated, etc.
- RemoveBlockRequest(resp.blockhash, pfrom.GetId()); // it is now an empty pointer
- fBlockRead = true;
- // mapBlockSource is used for potentially punishing peers and
- // updating which peers send us compact blocks, so the race
- // between here and cs_main in ProcessNewBlock is fine.
- // BIP 152 permits peers to relay compact blocks after validating
- // the header only; we should not punish peers if the block turns
- // out to be invalid.
- mapBlockSource.emplace(resp.blockhash, std::make_pair(pfrom.GetId(), false));
- }
- } // Don't hold cs_main when we call into ProcessNewBlock
- if (fBlockRead) {
- // Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
- // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
- // This bypasses some anti-DoS logic in AcceptBlock (eg to prevent
- // disk-space attacks), but this should be safe due to the
- // protections in the compact block handler -- see related comment
- // in compact block optimistic reconstruction handling.
- ProcessBlock(pfrom, pblock, /*force_processing=*/true, /*min_pow_checked=*/true);
- }
- return;
+ return ProcessCompactBlockTxns(pfrom, *peer, resp);
}
if (msg_type == NetMsgType::HEADERS)
@@ -5008,7 +5004,7 @@ bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt
msg.m_recv.data()
);
- if (gArgs.GetBoolArg("-capturemessages", false)) {
+ if (m_opts.capture_messages) {
CaptureMessage(pfrom->addr, msg.m_type, MakeUCharSpan(msg.m_recv), /*is_incoming=*/true);
}
@@ -5358,7 +5354,7 @@ void PeerManagerImpl::MaybeSendSendHeaders(CNode& node, Peer& peer)
void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, Peer& peer, std::chrono::microseconds current_time)
{
- if (m_ignore_incoming_txs) return;
+ if (m_opts.ignore_incoming_txs) return;
if (pto.GetCommonVersion() < FEEFILTER_VERSION) return;
// peers with the forcerelay permission should not filter txs to us
if (pto.HasPermission(NetPermissionFlags::ForceRelay)) return;
@@ -5426,7 +5422,7 @@ bool PeerManagerImpl::RejectIncomingTxs(const CNode& peer) const
if (peer.IsBlockOnlyConn()) return true;
if (peer.IsFeelerConn()) return true;
// In -blocksonly mode, peers need the 'relay' permission to send txs to us
- if (m_ignore_incoming_txs && !peer.HasPermission(NetPermissionFlags::Relay)) return true;
+ if (m_opts.ignore_incoming_txs && !peer.HasPermission(NetPermissionFlags::Relay)) return true;
return false;
}