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.cpp446
1 files changed, 245 insertions, 201 deletions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 4e631fd00e..34d349e8e9 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -68,13 +68,13 @@ static constexpr int32_t MAX_PEER_TX_IN_FLIGHT = 100;
/** Maximum number of announced transactions from a peer */
static constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS = 2 * MAX_INV_SZ;
/** How many microseconds to delay requesting transactions from inbound peers */
-static constexpr int64_t INBOUND_PEER_TX_DELAY = 2 * 1000000; // 2 seconds
+static constexpr std::chrono::microseconds INBOUND_PEER_TX_DELAY{std::chrono::seconds{2}};
/** How long to wait (in microseconds) before downloading a transaction from an additional peer */
-static constexpr int64_t GETDATA_TX_INTERVAL = 60 * 1000000; // 1 minute
+static constexpr std::chrono::microseconds GETDATA_TX_INTERVAL{std::chrono::seconds{60}};
/** Maximum delay (in microseconds) for transaction requests to avoid biasing some peers over others. */
-static constexpr int64_t MAX_GETDATA_RANDOM_DELAY = 2 * 1000000; // 2 seconds
+static constexpr std::chrono::microseconds MAX_GETDATA_RANDOM_DELAY{std::chrono::seconds{2}};
/** How long to wait (in microseconds) before expiring an in-flight getdata request to a peer */
-static constexpr int64_t TX_EXPIRY_INTERVAL = 10 * GETDATA_TX_INTERVAL;
+static constexpr std::chrono::microseconds TX_EXPIRY_INTERVAL{GETDATA_TX_INTERVAL * 10};
static_assert(INBOUND_PEER_TX_DELAY >= MAX_GETDATA_RANDOM_DELAY,
"To preserve security, MAX_GETDATA_RANDOM_DELAY should not exceed INBOUND_PEER_DELAY");
/** Limit to avoid sending big packets. Not used in processing incoming GETDATA for compatibility */
@@ -262,7 +262,7 @@ struct CNodeState {
bool fSupportsDesiredCmpctVersion;
/** State used to enforce CHAIN_SYNC_TIMEOUT
- * Only in effect for outbound, non-manual connections, with
+ * Only in effect for outbound, non-manual, full-relay connections, with
* m_protect == false
* Algorithm: if a peer's best known block has less work than our tip,
* set a timeout CHAIN_SYNC_TIMEOUT seconds in the future:
@@ -340,16 +340,16 @@ struct CNodeState {
/* Track when to attempt download of announced transactions (process
* time in micros -> txid)
*/
- std::multimap<int64_t, uint256> m_tx_process_time;
+ std::multimap<std::chrono::microseconds, uint256> m_tx_process_time;
//! Store all the transactions a peer has recently announced
std::set<uint256> m_tx_announced;
//! Store transactions which were requested by us, with timestamp
- std::map<uint256, int64_t> m_tx_in_flight;
+ std::map<uint256, std::chrono::microseconds> m_tx_in_flight;
//! Periodically check for stuck getdata requests
- int64_t m_check_expiry_timer{0};
+ std::chrono::microseconds m_check_expiry_timer{0};
};
TxDownloadState m_tx_download;
@@ -391,7 +391,7 @@ struct CNodeState {
};
// Keeps track of the time (in microseconds) when transactions were requested last time
-limitedmap<uint256, int64_t> g_already_asked_for GUARDED_BY(cs_main)(MAX_INV_SZ);
+limitedmap<uint256, std::chrono::microseconds> g_already_asked_for GUARDED_BY(cs_main)(MAX_INV_SZ);
/** Map maintaining per-node state. */
static std::map<NodeId, CNodeState> mapNodeState GUARDED_BY(cs_main);
@@ -408,13 +408,16 @@ static void UpdatePreferredDownload(CNode* node, CNodeState* state) EXCLUSIVE_LO
nPreferredDownload -= state->fPreferredDownload;
// Whether this node should be marked as a preferred download node.
- state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && !node->fOneShot && !node->fClient;
+ state->fPreferredDownload = (!node->fInbound || node->HasPermission(PF_NOBAN)) && !node->fOneShot && !node->fClient;
nPreferredDownload += state->fPreferredDownload;
}
static void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime)
{
+ // Note that pnode->GetLocalServices() is a reflection of the local
+ // services we were offering when the CNode object was created for this
+ // peer.
ServiceFlags nLocalNodeServices = pnode->GetLocalServices();
uint64_t nonce = pnode->GetLocalNonce();
int nNodeStartingHeight = pnode->GetMyStartingHeight();
@@ -425,7 +428,7 @@ static void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime)
CAddress addrMe = CAddress(CService(), nLocalNodeServices);
connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe,
- nonce, strSubVersion, nNodeStartingHeight, ::g_relay_txes));
+ nonce, strSubVersion, nNodeStartingHeight, ::g_relay_txes && pnode->m_tx_relay != nullptr));
if (fLogIPs) {
LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid);
@@ -688,16 +691,16 @@ void EraseTxRequest(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
g_already_asked_for.erase(txid);
}
-int64_t GetTxRequestTime(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+std::chrono::microseconds GetTxRequestTime(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
auto it = g_already_asked_for.find(txid);
if (it != g_already_asked_for.end()) {
return it->second;
}
- return 0;
+ return {};
}
-void UpdateTxRequestTime(const uint256& txid, int64_t request_time) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+void UpdateTxRequestTime(const uint256& txid, std::chrono::microseconds request_time) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
auto it = g_already_asked_for.find(txid);
if (it == g_already_asked_for.end()) {
@@ -707,17 +710,17 @@ void UpdateTxRequestTime(const uint256& txid, int64_t request_time) EXCLUSIVE_LO
}
}
-int64_t CalculateTxGetDataTime(const uint256& txid, int64_t current_time, bool use_inbound_delay) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+std::chrono::microseconds CalculateTxGetDataTime(const uint256& txid, std::chrono::microseconds current_time, bool use_inbound_delay) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
- int64_t process_time;
- int64_t last_request_time = GetTxRequestTime(txid);
+ std::chrono::microseconds process_time;
+ const auto last_request_time = GetTxRequestTime(txid);
// First time requesting this tx
- if (last_request_time == 0) {
+ if (last_request_time.count() == 0) {
process_time = current_time;
} else {
// Randomize the delay to avoid biasing some peers over others (such as due to
// fixed ordering of peer processing in ThreadMessageHandler)
- process_time = last_request_time + GETDATA_TX_INTERVAL + GetRand(MAX_GETDATA_RANDOM_DELAY);
+ process_time = last_request_time + GETDATA_TX_INTERVAL + GetRandMicros(MAX_GETDATA_RANDOM_DELAY);
}
// We delay processing announcements from inbound peers
@@ -726,7 +729,7 @@ int64_t CalculateTxGetDataTime(const uint256& txid, int64_t current_time, bool u
return process_time;
}
-void RequestTx(CNodeState* state, const uint256& txid, int64_t nNow) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+void RequestTx(CNodeState* state, const uint256& txid, std::chrono::microseconds current_time) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
CNodeState::TxDownloadState& peer_download_state = state->m_tx_download;
if (peer_download_state.m_tx_announced.size() >= MAX_PEER_TX_ANNOUNCEMENTS ||
@@ -740,7 +743,7 @@ void RequestTx(CNodeState* state, const uint256& txid, int64_t nNow) EXCLUSIVE_L
// Calculate the time to try requesting this transaction. Use
// fPreferredDownload as a proxy for outbound peers.
- int64_t process_time = CalculateTxGetDataTime(txid, nNow, !state->fPreferredDownload);
+ const auto process_time = CalculateTxGetDataTime(txid, current_time, !state->fPreferredDownload);
peer_download_state.m_tx_process_time.emplace(process_time, txid);
}
@@ -757,7 +760,7 @@ void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds)
}
// Returns true for outbound peers, excluding manual connections, feelers, and
-// one-shots
+// one-shots.
static bool IsOutboundDisconnectionCandidate(const CNode *node)
{
return !(node->fInbound || node->m_manual_connection || node->fFeeler || node->fOneShot);
@@ -1291,11 +1294,12 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
LOCK(g_cs_orphans);
if (mapOrphanTransactions.count(inv.hash)) return true;
}
+ const CCoinsViewCache& coins_cache = ::ChainstateActive().CoinsTip();
return recentRejects->contains(inv.hash) ||
mempool.exists(inv.hash) ||
- pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 0)) || // Best effort: only try output 0 and 1
- pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 1));
+ coins_cache.HaveCoinInCache(COutPoint(inv.hash, 0)) || // Best effort: only try output 0 and 1
+ coins_cache.HaveCoinInCache(COutPoint(inv.hash, 1));
}
case MSG_BLOCK:
case MSG_WITNESS_BLOCK:
@@ -1329,7 +1333,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman* connma
assert(nRelayNodes <= best.size());
auto sortfunc = [&best, &hasher, nRelayNodes](CNode* pnode) {
- if (pnode->nVersion >= CADDR_TIME_VERSION) {
+ if (pnode->nVersion >= CADDR_TIME_VERSION && pnode->IsAddrRelayPeer()) {
uint64_t hashKey = CSipHasher(hasher).Write(pnode->GetId()).Finalize();
for (unsigned int i = 0; i < nRelayNodes; i++) {
if (hashKey > best[i].first) {
@@ -1398,7 +1402,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
// disconnect node in case we have reached the outbound limit for serving historical blocks
// never disconnect whitelisted nodes
- if (send && connman->OutboundTargetReached(true) && ( ((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted)
+ if (send && connman->OutboundTargetReached(true) && ( ((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->HasPermission(PF_NOBAN))
{
LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId());
@@ -1407,7 +1411,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
send = false;
}
// Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
- if (send && !pfrom->fWhitelisted && (
+ if (send && !pfrom->HasPermission(PF_NOBAN) && (
(((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (::ChainActive().Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
)) {
LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom->GetId());
@@ -1448,11 +1452,11 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
{
bool sendMerkleBlock = false;
CMerkleBlock merkleBlock;
- {
- LOCK(pfrom->cs_filter);
- if (pfrom->pfilter) {
+ if (pfrom->m_tx_relay != nullptr) {
+ LOCK(pfrom->m_tx_relay->cs_filter);
+ if (pfrom->m_tx_relay->pfilter) {
sendMerkleBlock = true;
- merkleBlock = CMerkleBlock(*pblock, *pfrom->pfilter);
+ merkleBlock = CMerkleBlock(*pblock, *pfrom->m_tx_relay->pfilter);
}
}
if (sendMerkleBlock) {
@@ -1512,7 +1516,12 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm
std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();
std::vector<CInv> vNotFound;
const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
- {
+
+ // Note that if we receive a getdata for a MSG_TX or MSG_WITNESS_TX from a
+ // block-relay-only outbound peer, we will stop processing further getdata
+ // messages from this peer (likely resulting in our peer eventually
+ // disconnecting us).
+ if (pfrom->m_tx_relay != nullptr) {
LOCK(cs_main);
while (it != pfrom->vRecvGetData.end() && (it->type == MSG_TX || it->type == MSG_WITNESS_TX)) {
@@ -1532,11 +1541,11 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm
if (mi != mapRelay.end()) {
connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second));
push = true;
- } else if (pfrom->timeLastMempoolReq) {
+ } else if (pfrom->m_tx_relay->timeLastMempoolReq) {
auto txinfo = mempool.info(inv.hash);
// To protect privacy, do not answer getdata using the mempool when
// that TX couldn't have been INVed in reply to a MEMPOOL request.
- if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) {
+ if (txinfo.tx && txinfo.nTime <= pfrom->m_tx_relay->timeLastMempoolReq) {
connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx));
push = true;
}
@@ -1772,9 +1781,11 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
}
}
- if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && nodestate->pindexBestKnownBlock != nullptr) {
- // If this is an outbound peer, check to see if we should protect
+ if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && nodestate->pindexBestKnownBlock != nullptr && pfrom->m_tx_relay != nullptr) {
+ // If this is an outbound full-relay peer, check to see if we should protect
// it from the bad/lagging chain logic.
+ // Note that block-relay-only peers are already implicitly protected, so we
+ // only consider setting m_protect for the full-relay peers.
if (g_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= ::ChainActive().Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) {
LogPrint(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom->GetId());
nodestate->m_chain_sync.m_protect = true;
@@ -1844,7 +1855,7 @@ void static ProcessOrphanTx(CConnman* connman, std::set<uint256>& orphan_work_se
EraseOrphanTx(orphanHash);
done = true;
}
- mempool.check(pcoinsTip.get());
+ mempool.check(&::ChainstateActive().CoinsTip());
}
}
@@ -1995,9 +2006,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// set nodes not capable of serving the complete blockchain history as "limited nodes"
pfrom->m_limited_node = (!(nServices & NODE_NETWORK) && (nServices & NODE_NETWORK_LIMITED));
- {
- LOCK(pfrom->cs_filter);
- pfrom->fRelayTxes = fRelay; // set to true after we get the first filter* message
+ if (pfrom->m_tx_relay != nullptr) {
+ LOCK(pfrom->m_tx_relay->cs_filter);
+ pfrom->m_tx_relay->fRelayTxes = fRelay; // set to true after we get the first filter* message
}
// Change version
@@ -2016,7 +2027,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
UpdatePreferredDownload(pfrom, State(pfrom->GetId()));
}
- if (!pfrom->fInbound)
+ if (!pfrom->fInbound && pfrom->IsAddrRelayPeer())
{
// Advertise our address
if (fListen && !::ChainstateActive().IsInitialBlockDownload())
@@ -2088,9 +2099,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// Mark this node as currently connected, so we update its timestamp later.
LOCK(cs_main);
State(pfrom->GetId())->fCurrentlyConnected = true;
- LogPrintf("New outbound peer connected: version: %d, blocks=%d, peer=%d%s\n",
- pfrom->nVersion.load(), pfrom->nStartingHeight, pfrom->GetId(),
- (fLogIPs ? strprintf(", peeraddr=%s", pfrom->addr.ToString()) : ""));
+ LogPrintf("New outbound peer connected: version: %d, blocks=%d, peer=%d%s (%s)\n",
+ pfrom->nVersion.load(), pfrom->nStartingHeight,
+ pfrom->GetId(), (fLogIPs ? strprintf(", peeraddr=%s", pfrom->addr.ToString()) : ""),
+ pfrom->m_tx_relay == nullptr ? "block-relay" : "full-relay");
}
if (pfrom->nVersion >= SENDHEADERS_VERSION) {
@@ -2131,6 +2143,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// Don't want addr from older versions unless seeding
if (pfrom->nVersion < CADDR_TIME_VERSION && connman->GetAddressCount() > 1000)
return true;
+ if (!pfrom->IsAddrRelayPeer()) {
+ return true;
+ }
if (vAddr.size() > 1000)
{
LOCK(cs_main);
@@ -2214,16 +2229,18 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return false;
}
- bool fBlocksOnly = !g_relay_txes;
+ // We won't accept tx inv's if we're in blocks-only mode, or this is a
+ // block-relay-only peer
+ bool fBlocksOnly = !g_relay_txes || (pfrom->m_tx_relay == nullptr);
// Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true
- if (pfrom->fWhitelisted && gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))
+ if (pfrom->HasPermission(PF_RELAY))
fBlocksOnly = false;
LOCK(cs_main);
uint32_t nFetchFlags = GetFetchFlags(pfrom);
- int64_t nNow = GetTimeMicros();
+ const auto current_time = GetTime<std::chrono::microseconds>();
for (CInv &inv : vInv)
{
@@ -2253,9 +2270,11 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
{
pfrom->AddInventoryKnown(inv);
if (fBlocksOnly) {
- LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->GetId());
+ LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom->GetId());
+ pfrom->fDisconnect = true;
+ return true;
} else if (!fAlreadyHave && !fImporting && !fReindex && !::ChainstateActive().IsInitialBlockDownload()) {
- RequestTx(State(pfrom->GetId()), inv.hash, nNow);
+ RequestTx(State(pfrom->GetId()), inv.hash, current_time);
}
}
}
@@ -2412,7 +2431,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
LOCK(cs_main);
- if (::ChainstateActive().IsInitialBlockDownload() && !pfrom->fWhitelisted) {
+ if (::ChainstateActive().IsInitialBlockDownload() && !pfrom->HasPermission(PF_NOBAN)) {
LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->GetId());
return true;
}
@@ -2470,9 +2489,11 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (strCommand == NetMsgType::TX) {
// Stop processing the transaction early if
// We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off
- if (!g_relay_txes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)))
+ // or if this peer is supposed to be a block-relay-only peer
+ if ((!g_relay_txes && !pfrom->HasPermission(PF_RELAY)) || (pfrom->m_tx_relay == nullptr))
{
LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom->GetId());
+ pfrom->fDisconnect = true;
return true;
}
@@ -2497,7 +2518,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (!AlreadyHave(inv) &&
AcceptToMemoryPool(mempool, state, ptx, &fMissingInputs, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
- mempool.check(pcoinsTip.get());
+ mempool.check(&::ChainstateActive().CoinsTip());
RelayTransaction(tx.GetHash(), *connman);
for (unsigned int i = 0; i < tx.vout.size(); i++) {
auto it_by_prev = mapOrphanTransactionsByPrev.find(COutPoint(inv.hash, i));
@@ -2529,16 +2550,16 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
if (!fRejectedParents) {
uint32_t nFetchFlags = GetFetchFlags(pfrom);
- int64_t nNow = GetTimeMicros();
+ const auto current_time = GetTime<std::chrono::microseconds>();
for (const CTxIn& txin : tx.vin) {
CInv _inv(MSG_TX | nFetchFlags, txin.prevout.hash);
pfrom->AddInventoryKnown(_inv);
- if (!AlreadyHave(_inv)) RequestTx(State(pfrom->GetId()), _inv.hash, nNow);
+ if (!AlreadyHave(_inv)) RequestTx(State(pfrom->GetId()), _inv.hash, current_time);
}
AddOrphanTx(ptx, pfrom->GetId());
- // DoS prevention: do not allow mapOrphanTransactions to grow unbounded
+ // DoS prevention: do not allow mapOrphanTransactions to grow unbounded (see CVE-2012-3789)
unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, gArgs.GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS));
unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx);
if (nEvicted > 0) {
@@ -2565,7 +2586,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
AddToCompactExtraTransactions(ptx);
}
- if (pfrom->fWhitelisted && gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
+ if (pfrom->HasPermission(PF_FORCERELAY)) {
// Always relay transactions received from whitelisted peers, even
// if they were already in the mempool or rejected from it due
// to policy, allowing the node to function as a gateway for
@@ -2989,6 +3010,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LogPrint(BCLog::NET, "Ignoring \"getaddr\" from outbound connection. peer=%d\n", pfrom->GetId());
return true;
}
+ if (!pfrom->IsAddrRelayPeer()) {
+ LogPrint(BCLog::NET, "Ignoring \"getaddr\" from block-relay-only connection. peer=%d\n", pfrom->GetId());
+ return true;
+ }
// Only send one GetAddr response per connection to reduce resource waste
// and discourage addr stamping of INV announcements.
@@ -3010,22 +3035,30 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
if (strCommand == NetMsgType::MEMPOOL) {
- if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->fWhitelisted)
+ if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->HasPermission(PF_MEMPOOL))
{
- LogPrint(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId());
- pfrom->fDisconnect = true;
+ if (!pfrom->HasPermission(PF_NOBAN))
+ {
+ LogPrint(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId());
+ pfrom->fDisconnect = true;
+ }
return true;
}
- if (connman->OutboundTargetReached(false) && !pfrom->fWhitelisted)
+ if (connman->OutboundTargetReached(false) && !pfrom->HasPermission(PF_MEMPOOL))
{
- LogPrint(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId());
- pfrom->fDisconnect = true;
+ if (!pfrom->HasPermission(PF_NOBAN))
+ {
+ LogPrint(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId());
+ pfrom->fDisconnect = true;
+ }
return true;
}
- LOCK(pfrom->cs_inventory);
- pfrom->fSendMempool = true;
+ if (pfrom->m_tx_relay != nullptr) {
+ LOCK(pfrom->m_tx_relay->cs_tx_inventory);
+ pfrom->m_tx_relay->fSendMempool = true;
+ }
return true;
}
@@ -3116,12 +3149,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 100);
}
- else
+ else if (pfrom->m_tx_relay != nullptr)
{
- LOCK(pfrom->cs_filter);
- pfrom->pfilter.reset(new CBloomFilter(filter));
- pfrom->pfilter->UpdateEmptyFull();
- pfrom->fRelayTxes = true;
+ LOCK(pfrom->m_tx_relay->cs_filter);
+ pfrom->m_tx_relay->pfilter.reset(new CBloomFilter(filter));
+ pfrom->m_tx_relay->pfilter->UpdateEmptyFull();
+ pfrom->m_tx_relay->fRelayTxes = true;
}
return true;
}
@@ -3135,10 +3168,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
bool bad = false;
if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) {
bad = true;
- } else {
- LOCK(pfrom->cs_filter);
- if (pfrom->pfilter) {
- pfrom->pfilter->insert(vData);
+ } else if (pfrom->m_tx_relay != nullptr) {
+ LOCK(pfrom->m_tx_relay->cs_filter);
+ if (pfrom->m_tx_relay->pfilter) {
+ pfrom->m_tx_relay->pfilter->insert(vData);
} else {
bad = true;
}
@@ -3151,11 +3184,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
if (strCommand == NetMsgType::FILTERCLEAR) {
- LOCK(pfrom->cs_filter);
+ if (pfrom->m_tx_relay == nullptr) {
+ return true;
+ }
+ LOCK(pfrom->m_tx_relay->cs_filter);
if (pfrom->GetLocalServices() & NODE_BLOOM) {
- pfrom->pfilter.reset(new CBloomFilter());
+ pfrom->m_tx_relay->pfilter.reset(new CBloomFilter());
}
- pfrom->fRelayTxes = true;
+ pfrom->m_tx_relay->fRelayTxes = true;
return true;
}
@@ -3163,9 +3199,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
CAmount newFeeFilter = 0;
vRecv >> newFeeFilter;
if (MoneyRange(newFeeFilter)) {
- {
- LOCK(pfrom->cs_feeFilter);
- pfrom->minFeeFilter = newFeeFilter;
+ if (pfrom->m_tx_relay != nullptr) {
+ LOCK(pfrom->m_tx_relay->cs_feeFilter);
+ pfrom->m_tx_relay->minFeeFilter = newFeeFilter;
}
LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->GetId());
}
@@ -3216,7 +3252,7 @@ bool PeerLogicValidation::SendRejectsAndCheckIfBanned(CNode* pnode, bool enable_
if (state.fShouldBan) {
state.fShouldBan = false;
- if (pnode->fWhitelisted)
+ if (pnode->HasPermission(PF_NOBAN))
LogPrintf("Warning: not punishing whitelisted peer %s!\n", pnode->addr.ToString());
else if (pnode->m_manual_connection)
LogPrintf("Warning: not punishing manually-connected peer %s!\n", pnode->addr.ToString());
@@ -3442,6 +3478,8 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds)
if (state == nullptr) return; // shouldn't be possible, but just in case
// Don't evict our protected peers
if (state->m_chain_sync.m_protect) return;
+ // Don't evict our block-relay-only peers.
+ if (pnode->m_tx_relay == nullptr) return;
if (state->m_last_block_announcement < oldest_block_announcement || (state->m_last_block_announcement == oldest_block_announcement && pnode->GetId() > worst_peer)) {
worst_peer = pnode->GetId();
oldest_block_announcement = state->m_last_block_announcement;
@@ -3569,7 +3607,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// Address refresh broadcast
int64_t nNow = GetTimeMicros();
- if (!::ChainstateActive().IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
+ if (pto->IsAddrRelayPeer() && !::ChainstateActive().IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
AdvertiseLocal(pto);
pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
}
@@ -3577,7 +3615,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
//
// Message: addr
//
- if (pto->nNextAddrSend < nNow) {
+ if (pto->IsAddrRelayPeer() && pto->nNextAddrSend < nNow) {
pto->nNextAddrSend = PoissonNextSend(nNow, AVG_ADDRESS_BROADCAST_INTERVAL);
std::vector<CAddress> vAddr;
vAddr.reserve(pto->vAddrToSend.size());
@@ -3785,120 +3823,123 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
}
pto->vInventoryBlockToSend.clear();
- // Check whether periodic sends should happen
- bool fSendTrickle = pto->fWhitelisted;
- if (pto->nNextInvSend < nNow) {
- fSendTrickle = true;
- if (pto->fInbound) {
- pto->nNextInvSend = connman->PoissonNextSendInbound(nNow, INVENTORY_BROADCAST_INTERVAL);
- } else {
- // Use half the delay for outbound peers, as there is less privacy concern for them.
- pto->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> 1);
+ if (pto->m_tx_relay != nullptr) {
+ LOCK(pto->m_tx_relay->cs_tx_inventory);
+ // Check whether periodic sends should happen
+ bool fSendTrickle = pto->HasPermission(PF_NOBAN);
+ if (pto->m_tx_relay->nNextInvSend < nNow) {
+ fSendTrickle = true;
+ if (pto->fInbound) {
+ pto->m_tx_relay->nNextInvSend = connman->PoissonNextSendInbound(nNow, INVENTORY_BROADCAST_INTERVAL);
+ } else {
+ // Use half the delay for outbound peers, as there is less privacy concern for them.
+ pto->m_tx_relay->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> 1);
+ }
}
- }
-
- // Time to send but the peer has requested we not relay transactions.
- if (fSendTrickle) {
- LOCK(pto->cs_filter);
- if (!pto->fRelayTxes) pto->setInventoryTxToSend.clear();
- }
- // Respond to BIP35 mempool requests
- if (fSendTrickle && pto->fSendMempool) {
- auto vtxinfo = mempool.infoAll();
- pto->fSendMempool = false;
- CAmount filterrate = 0;
- {
- LOCK(pto->cs_feeFilter);
- filterrate = pto->minFeeFilter;
+ // Time to send but the peer has requested we not relay transactions.
+ if (fSendTrickle) {
+ LOCK(pto->m_tx_relay->cs_filter);
+ if (!pto->m_tx_relay->fRelayTxes) pto->m_tx_relay->setInventoryTxToSend.clear();
}
- LOCK(pto->cs_filter);
-
- for (const auto& txinfo : vtxinfo) {
- const uint256& hash = txinfo.tx->GetHash();
- CInv inv(MSG_TX, hash);
- pto->setInventoryTxToSend.erase(hash);
- if (filterrate) {
- if (txinfo.feeRate.GetFeePerK() < filterrate)
- continue;
- }
- if (pto->pfilter) {
- if (!pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
+ // Respond to BIP35 mempool requests
+ if (fSendTrickle && pto->m_tx_relay->fSendMempool) {
+ auto vtxinfo = mempool.infoAll();
+ pto->m_tx_relay->fSendMempool = false;
+ CAmount filterrate = 0;
+ {
+ LOCK(pto->m_tx_relay->cs_feeFilter);
+ filterrate = pto->m_tx_relay->minFeeFilter;
}
- pto->filterInventoryKnown.insert(hash);
- vInv.push_back(inv);
- if (vInv.size() == MAX_INV_SZ) {
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
- vInv.clear();
+
+ LOCK(pto->m_tx_relay->cs_filter);
+
+ for (const auto& txinfo : vtxinfo) {
+ const uint256& hash = txinfo.tx->GetHash();
+ CInv inv(MSG_TX, hash);
+ pto->m_tx_relay->setInventoryTxToSend.erase(hash);
+ if (filterrate) {
+ if (txinfo.feeRate.GetFeePerK() < filterrate)
+ continue;
+ }
+ if (pto->m_tx_relay->pfilter) {
+ if (!pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
+ }
+ pto->m_tx_relay->filterInventoryKnown.insert(hash);
+ vInv.push_back(inv);
+ if (vInv.size() == MAX_INV_SZ) {
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ vInv.clear();
+ }
}
+ pto->m_tx_relay->timeLastMempoolReq = GetTime();
}
- pto->timeLastMempoolReq = GetTime();
- }
- // Determine transactions to relay
- if (fSendTrickle) {
- // Produce a vector with all candidates for sending
- std::vector<std::set<uint256>::iterator> vInvTx;
- vInvTx.reserve(pto->setInventoryTxToSend.size());
- for (std::set<uint256>::iterator it = pto->setInventoryTxToSend.begin(); it != pto->setInventoryTxToSend.end(); it++) {
- vInvTx.push_back(it);
- }
- CAmount filterrate = 0;
- {
- LOCK(pto->cs_feeFilter);
- filterrate = pto->minFeeFilter;
- }
- // Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
- // A heap is used so that not all items need sorting if only a few are being sent.
- CompareInvMempoolOrder compareInvMempoolOrder(&mempool);
- std::make_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
- // No reason to drain out at many times the network's capacity,
- // especially since we have many peers and some will draw much shorter delays.
- unsigned int nRelayedTransactions = 0;
- LOCK(pto->cs_filter);
- while (!vInvTx.empty() && nRelayedTransactions < INVENTORY_BROADCAST_MAX) {
- // Fetch the top element from the heap
- std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
- std::set<uint256>::iterator it = vInvTx.back();
- vInvTx.pop_back();
- uint256 hash = *it;
- // Remove it from the to-be-sent set
- pto->setInventoryTxToSend.erase(it);
- // Check if not in the filter already
- if (pto->filterInventoryKnown.contains(hash)) {
- continue;
+ // Determine transactions to relay
+ if (fSendTrickle) {
+ // Produce a vector with all candidates for sending
+ std::vector<std::set<uint256>::iterator> vInvTx;
+ vInvTx.reserve(pto->m_tx_relay->setInventoryTxToSend.size());
+ for (std::set<uint256>::iterator it = pto->m_tx_relay->setInventoryTxToSend.begin(); it != pto->m_tx_relay->setInventoryTxToSend.end(); it++) {
+ vInvTx.push_back(it);
}
- // Not in the mempool anymore? don't bother sending it.
- auto txinfo = mempool.info(hash);
- if (!txinfo.tx) {
- continue;
- }
- if (filterrate && txinfo.feeRate.GetFeePerK() < filterrate) {
- continue;
- }
- if (pto->pfilter && !pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
- // Send
- vInv.push_back(CInv(MSG_TX, hash));
- nRelayedTransactions++;
+ CAmount filterrate = 0;
{
- // Expire old relay messages
- while (!vRelayExpiration.empty() && vRelayExpiration.front().first < nNow)
- {
- mapRelay.erase(vRelayExpiration.front().second);
- vRelayExpiration.pop_front();
+ LOCK(pto->m_tx_relay->cs_feeFilter);
+ filterrate = pto->m_tx_relay->minFeeFilter;
+ }
+ // Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
+ // A heap is used so that not all items need sorting if only a few are being sent.
+ CompareInvMempoolOrder compareInvMempoolOrder(&mempool);
+ std::make_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
+ // No reason to drain out at many times the network's capacity,
+ // especially since we have many peers and some will draw much shorter delays.
+ unsigned int nRelayedTransactions = 0;
+ LOCK(pto->m_tx_relay->cs_filter);
+ while (!vInvTx.empty() && nRelayedTransactions < INVENTORY_BROADCAST_MAX) {
+ // Fetch the top element from the heap
+ std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
+ std::set<uint256>::iterator it = vInvTx.back();
+ vInvTx.pop_back();
+ uint256 hash = *it;
+ // Remove it from the to-be-sent set
+ pto->m_tx_relay->setInventoryTxToSend.erase(it);
+ // Check if not in the filter already
+ if (pto->m_tx_relay->filterInventoryKnown.contains(hash)) {
+ continue;
+ }
+ // Not in the mempool anymore? don't bother sending it.
+ auto txinfo = mempool.info(hash);
+ if (!txinfo.tx) {
+ continue;
}
+ if (filterrate && txinfo.feeRate.GetFeePerK() < filterrate) {
+ continue;
+ }
+ if (pto->m_tx_relay->pfilter && !pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
+ // Send
+ vInv.push_back(CInv(MSG_TX, hash));
+ nRelayedTransactions++;
+ {
+ // Expire old relay messages
+ while (!vRelayExpiration.empty() && vRelayExpiration.front().first < nNow)
+ {
+ mapRelay.erase(vRelayExpiration.front().second);
+ vRelayExpiration.pop_front();
+ }
- auto ret = mapRelay.insert(std::make_pair(hash, std::move(txinfo.tx)));
- if (ret.second) {
- vRelayExpiration.push_back(std::make_pair(nNow + 15 * 60 * 1000000, ret.first));
+ auto ret = mapRelay.insert(std::make_pair(hash, std::move(txinfo.tx)));
+ if (ret.second) {
+ vRelayExpiration.push_back(std::make_pair(nNow + 15 * 60 * 1000000, ret.first));
+ }
}
+ if (vInv.size() == MAX_INV_SZ) {
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ vInv.clear();
+ }
+ pto->m_tx_relay->filterInventoryKnown.insert(hash);
}
- if (vInv.size() == MAX_INV_SZ) {
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
- vInv.clear();
- }
- pto->filterInventoryKnown.insert(hash);
}
}
}
@@ -3906,6 +3947,9 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
// Detect whether we're stalling
+ const auto current_time = GetTime<std::chrono::microseconds>();
+ // nNow is the current system time (GetTimeMicros is not mockable) and
+ // should be replaced by the mockable current_time eventually
nNow = GetTimeMicros();
if (state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) {
// Stalling only triggers when the block download window cannot move. During normal steady state,
@@ -3939,7 +3983,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// Note: If all our peers are inbound, then we won't
// disconnect our sync peer for stalling; we have bigger
// problems if we can't get any outbound peers.
- if (!pto->fWhitelisted) {
+ if (!pto->HasPermission(PF_NOBAN)) {
LogPrintf("Timeout downloading headers from peer=%d, disconnecting\n", pto->GetId());
pto->fDisconnect = true;
return true;
@@ -3998,9 +4042,9 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// were unresponsive in the past.
// Eventually we should consider disconnecting peers, but this is
// conservative.
- if (state.m_tx_download.m_check_expiry_timer <= nNow) {
+ if (state.m_tx_download.m_check_expiry_timer <= current_time) {
for (auto it=state.m_tx_download.m_tx_in_flight.begin(); it != state.m_tx_download.m_tx_in_flight.end();) {
- if (it->second <= nNow - TX_EXPIRY_INTERVAL) {
+ if (it->second <= current_time - TX_EXPIRY_INTERVAL) {
LogPrint(BCLog::NET, "timeout of inflight tx %s from peer=%d\n", it->first.ToString(), pto->GetId());
state.m_tx_download.m_tx_announced.erase(it->first);
state.m_tx_download.m_tx_in_flight.erase(it++);
@@ -4010,11 +4054,11 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
}
// On average, we do this check every TX_EXPIRY_INTERVAL. Randomize
// so that we're not doing this for all peers at the same time.
- state.m_tx_download.m_check_expiry_timer = nNow + TX_EXPIRY_INTERVAL/2 + GetRand(TX_EXPIRY_INTERVAL);
+ state.m_tx_download.m_check_expiry_timer = current_time + TX_EXPIRY_INTERVAL / 2 + GetRandMicros(TX_EXPIRY_INTERVAL);
}
auto& tx_process_time = state.m_tx_download.m_tx_process_time;
- while (!tx_process_time.empty() && tx_process_time.begin()->first <= nNow && state.m_tx_download.m_tx_in_flight.size() < MAX_PEER_TX_IN_FLIGHT) {
+ while (!tx_process_time.empty() && tx_process_time.begin()->first <= current_time && state.m_tx_download.m_tx_in_flight.size() < MAX_PEER_TX_IN_FLIGHT) {
const uint256 txid = tx_process_time.begin()->second;
// Erase this entry from tx_process_time (it may be added back for
// processing at a later time, see below)
@@ -4023,22 +4067,22 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
if (!AlreadyHave(inv)) {
// If this transaction was last requested more than 1 minute ago,
// then request.
- int64_t last_request_time = GetTxRequestTime(inv.hash);
- if (last_request_time <= nNow - GETDATA_TX_INTERVAL) {
+ const auto last_request_time = GetTxRequestTime(inv.hash);
+ if (last_request_time <= current_time - GETDATA_TX_INTERVAL) {
LogPrint(BCLog::NET, "Requesting %s peer=%d\n", inv.ToString(), pto->GetId());
vGetData.push_back(inv);
if (vGetData.size() >= MAX_GETDATA_SZ) {
connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
vGetData.clear();
}
- UpdateTxRequestTime(inv.hash, nNow);
- state.m_tx_download.m_tx_in_flight.emplace(inv.hash, nNow);
+ UpdateTxRequestTime(inv.hash, current_time);
+ state.m_tx_download.m_tx_in_flight.emplace(inv.hash, current_time);
} else {
// This transaction is in flight from someone else; queue
// up processing to happen after the download times out
// (with a slight delay for inbound peers, to prefer
// requests to outbound peers).
- int64_t next_process_time = CalculateTxGetDataTime(txid, nNow, !state.fPreferredDownload);
+ const auto next_process_time = CalculateTxGetDataTime(txid, current_time, !state.fPreferredDownload);
tx_process_time.emplace(next_process_time, txid);
}
} else {
@@ -4056,27 +4100,27 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// Message: feefilter
//
// We don't want white listed peers to filter txs to us if we have -whitelistforcerelay
- if (pto->nVersion >= FEEFILTER_VERSION && gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
- !(pto->fWhitelisted && gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY))) {
+ if (pto->m_tx_relay != nullptr && pto->nVersion >= FEEFILTER_VERSION && gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
+ !pto->HasPermission(PF_FORCERELAY)) {
CAmount currentFilter = mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
int64_t timeNow = GetTimeMicros();
- if (timeNow > pto->nextSendTimeFeeFilter) {
+ if (timeNow > pto->m_tx_relay->nextSendTimeFeeFilter) {
static CFeeRate default_feerate(DEFAULT_MIN_RELAY_TX_FEE);
static FeeFilterRounder filterRounder(default_feerate);
CAmount filterToSend = filterRounder.round(currentFilter);
// We always have a fee filter of at least minRelayTxFee
filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK());
- if (filterToSend != pto->lastSentFeeFilter) {
+ if (filterToSend != pto->m_tx_relay->lastSentFeeFilter) {
connman->PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend));
- pto->lastSentFeeFilter = filterToSend;
+ pto->m_tx_relay->lastSentFeeFilter = filterToSend;
}
- pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL);
+ pto->m_tx_relay->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL);
}
// If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY
// until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.
- else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->nextSendTimeFeeFilter &&
- (currentFilter < 3 * pto->lastSentFeeFilter / 4 || currentFilter > 4 * pto->lastSentFeeFilter / 3)) {
- pto->nextSendTimeFeeFilter = timeNow + GetRandInt(MAX_FEEFILTER_CHANGE_DELAY) * 1000000;
+ else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->m_tx_relay->nextSendTimeFeeFilter &&
+ (currentFilter < 3 * pto->m_tx_relay->lastSentFeeFilter / 4 || currentFilter > 4 * pto->m_tx_relay->lastSentFeeFilter / 3)) {
+ pto->m_tx_relay->nextSendTimeFeeFilter = timeNow + GetRandInt(MAX_FEEFILTER_CHANGE_DELAY) * 1000000;
}
}
}