Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
struct COrphanTx { | struct COrphanTx { | ||||
// When modifying, adapt the copy of this definition in tests/DoS_tests. | // When modifying, adapt the copy of this definition in tests/DoS_tests. | ||||
CTransactionRef tx; | CTransactionRef tx; | ||||
NodeId fromPeer; | NodeId fromPeer; | ||||
int64_t nTimeExpire; | int64_t nTimeExpire; | ||||
}; | }; | ||||
std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main); | std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main); | ||||
std::map<COutPoint, | std::map<COutPoint, | ||||
std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> | std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> | ||||
mapOrphanTransactionsByPrev GUARDED_BY(cs_main); | mapOrphanTransactionsByPrev GUARDED_BY(cs_main); | ||||
void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | ||||
static size_t vExtraTxnForCompactIt = 0; | static size_t vExtraTxnForCompactIt = 0; | ||||
static std::vector<std::pair<uint256, CTransactionRef>> | static std::vector<std::pair<uint256, CTransactionRef>> | ||||
vExtraTxnForCompact GUARDED_BY(cs_main); | vExtraTxnForCompact GUARDED_BY(cs_main); | ||||
// SHA256("main address relay")[0:8] | // SHA256("main address relay")[0:8] | ||||
static const uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; | static const uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; | ||||
// Internal stuff | // Internal stuff | ||||
namespace { | namespace { | ||||
/** Number of nodes with fSyncStarted. */ | /** Number of nodes with fSyncStarted. */ | ||||
int nSyncStarted = 0; | int nSyncStarted GUARDED_BY(cs_main) = 0; | ||||
/** | /** | ||||
* Sources of received blocks, saved to be able to send them reject messages or | * Sources of received blocks, saved to be able to send them reject messages or | ||||
* ban them when processing happens afterwards. Protected by cs_main. | * ban them when processing happens afterwards. | ||||
* Set mapBlockSource[hash].second to false if the node should not be punished | * Set mapBlockSource[hash].second to false if the node should not be punished | ||||
* if the block is invalid. | * if the block is invalid. | ||||
*/ | */ | ||||
std::map<uint256, std::pair<NodeId, bool>> mapBlockSource; | std::map<uint256, std::pair<NodeId, bool>> mapBlockSource GUARDED_BY(cs_main); | ||||
/** | /** | ||||
* Filter for transactions that were recently rejected by AcceptToMemoryPool. | * Filter for transactions that were recently rejected by AcceptToMemoryPool. | ||||
* These are not rerequested until the chain tip changes, at which point the | * These are not rerequested until the chain tip changes, at which point the | ||||
* entire filter is reset. Protected by cs_main. | * entire filter is reset. | ||||
* | * | ||||
* Without this filter we'd be re-requesting txs from each of our peers, | * Without this filter we'd be re-requesting txs from each of our peers, | ||||
* increasing bandwidth consumption considerably. For instance, with 100 peers, | * increasing bandwidth consumption considerably. For instance, with 100 peers, | ||||
* half of which relay a tx we don't accept, that might be a 50x bandwidth | * half of which relay a tx we don't accept, that might be a 50x bandwidth | ||||
* increase. A flooding attacker attempting to roll-over the filter using | * increase. A flooding attacker attempting to roll-over the filter using | ||||
* minimum-sized, 60byte, transactions might manage to send 1000/sec if we have | * minimum-sized, 60byte, transactions might manage to send 1000/sec if we have | ||||
* fast peers, so we pick 120,000 to give our peers a two minute window to send | * fast peers, so we pick 120,000 to give our peers a two minute window to send | ||||
* invs to us. | * invs to us. | ||||
* | * | ||||
* Decreasing the false positive rate is fairly cheap, so we pick one in a | * Decreasing the false positive rate is fairly cheap, so we pick one in a | ||||
* million to make it highly unlikely for users to have issues with this filter. | * million to make it highly unlikely for users to have issues with this filter. | ||||
* | * | ||||
* Memory used: 1.3 MB | * Memory used: 1.3 MB | ||||
*/ | */ | ||||
std::unique_ptr<CRollingBloomFilter> recentRejects; | std::unique_ptr<CRollingBloomFilter> recentRejects GUARDED_BY(cs_main); | ||||
uint256 hashRecentRejectsChainTip; | uint256 hashRecentRejectsChainTip GUARDED_BY(cs_main); | ||||
/** | /** | ||||
* Blocks that are in flight, and that are in the queue to be downloaded. | * Blocks that are in flight, and that are in the queue to be downloaded. | ||||
* Protected by cs_main. | |||||
*/ | */ | ||||
struct QueuedBlock { | struct QueuedBlock { | ||||
uint256 hash; | uint256 hash; | ||||
//!< Optional. | //!< Optional. | ||||
const CBlockIndex *pindex; | const CBlockIndex *pindex; | ||||
//!< Whether this block has validated headers at the time of request. | //!< Whether this block has validated headers at the time of request. | ||||
bool fValidatedHeaders; | bool fValidatedHeaders; | ||||
//!< Optional, used for CMPCTBLOCK downloads | //!< Optional, used for CMPCTBLOCK downloads | ||||
std::unique_ptr<PartiallyDownloadedBlock> partialBlock; | std::unique_ptr<PartiallyDownloadedBlock> partialBlock; | ||||
}; | }; | ||||
std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator>> | std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator>> | ||||
mapBlocksInFlight; | mapBlocksInFlight GUARDED_BY(cs_main); | ||||
/** Stack of nodes which we have set to announce using compact blocks */ | /** Stack of nodes which we have set to announce using compact blocks */ | ||||
std::list<NodeId> lNodesAnnouncingHeaderAndIDs; | std::list<NodeId> lNodesAnnouncingHeaderAndIDs; | ||||
/** Number of preferable block download peers. */ | /** Number of preferable block download peers. */ | ||||
int nPreferredDownload = 0; | int nPreferredDownload GUARDED_BY(cs_main) = 0; | ||||
/** Number of peers from which we're downloading blocks. */ | /** Number of peers from which we're downloading blocks. */ | ||||
int nPeersWithValidatedDownloads = 0; | int nPeersWithValidatedDownloads GUARDED_BY(cs_main) = 0; | ||||
/** Number of outbound peers with m_chain_sync.m_protect. */ | /** Number of outbound peers with m_chain_sync.m_protect. */ | ||||
int g_outbound_peers_with_protect_from_disconnect = 0; | int g_outbound_peers_with_protect_from_disconnect = 0; | ||||
/** When our tip was last updated. */ | /** When our tip was last updated. */ | ||||
int64_t g_last_tip_update = 0; | int64_t g_last_tip_update = 0; | ||||
/** Relay map, protected by cs_main. */ | /** Relay map. */ | ||||
typedef std::map<uint256, CTransactionRef> MapRelay; | typedef std::map<uint256, CTransactionRef> MapRelay; | ||||
MapRelay mapRelay; | MapRelay mapRelay GUARDED_BY(cs_main); | ||||
/** | /** | ||||
* Expiration-time ordered list of (expire time, relay map entry) pairs, | * Expiration-time ordered list of (expire time, relay map entry) pairs, | ||||
* protected by cs_main). | * protected by cs_main). | ||||
*/ | */ | ||||
std::deque<std::pair<int64_t, MapRelay::iterator>> vRelayExpiration; | std::deque<std::pair<int64_t, MapRelay::iterator>> | ||||
vRelayExpiration GUARDED_BY(cs_main); | |||||
} // namespace | } // namespace | ||||
namespace { | namespace { | ||||
struct CBlockReject { | struct CBlockReject { | ||||
uint8_t chRejectCode; | uint8_t chRejectCode; | ||||
std::string strRejectReason; | std::string strRejectReason; | ||||
uint256 hashBlock; | uint256 hashBlock; | ||||
▲ Show 20 Lines • Show All 118 Lines • ▼ Show 20 Lines | CNodeState(CAddress addrIn, std::string addrNameIn) | ||||
fPreferHeaderAndIDs = false; | fPreferHeaderAndIDs = false; | ||||
fProvidesHeaderAndIDs = false; | fProvidesHeaderAndIDs = false; | ||||
fSupportsDesiredCmpctVersion = false; | fSupportsDesiredCmpctVersion = false; | ||||
m_chain_sync = {0, nullptr, false, false}; | m_chain_sync = {0, nullptr, false, false}; | ||||
m_last_block_announcement = 0; | m_last_block_announcement = 0; | ||||
} | } | ||||
}; | }; | ||||
/** Map maintaining per-node state. Requires cs_main. */ | /** Map maintaining per-node state. */ | ||||
static std::map<NodeId, CNodeState> mapNodeState; | static std::map<NodeId, CNodeState> mapNodeState GUARDED_BY(cs_main); | ||||
// Requires cs_main. | static CNodeState *State(NodeId pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
static CNodeState *State(NodeId pnode) { | |||||
std::map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode); | std::map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode); | ||||
if (it == mapNodeState.end()) { | if (it == mapNodeState.end()) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
return &it->second; | return &it->second; | ||||
} | } | ||||
static void UpdatePreferredDownload(CNode *node, CNodeState *state) { | static void UpdatePreferredDownload(CNode *node, CNodeState *state) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | |||||
nPreferredDownload -= state->fPreferredDownload; | nPreferredDownload -= state->fPreferredDownload; | ||||
// Whether this node should be marked as a preferred download node. | // Whether this node should be marked as a preferred download node. | ||||
state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && | state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && | ||||
!node->fOneShot && !node->fClient; | !node->fOneShot && !node->fClient; | ||||
nPreferredDownload += state->fPreferredDownload; | nPreferredDownload += state->fPreferredDownload; | ||||
} | } | ||||
Show All 26 Lines | static void PushNodeVersion(const Config &config, CNode *pnode, | ||||
} else { | } else { | ||||
LogPrint( | LogPrint( | ||||
BCLog::NET, | BCLog::NET, | ||||
"send version message: version %d, blocks=%d, us=%s, peer=%d\n", | "send version message: version %d, blocks=%d, us=%s, peer=%d\n", | ||||
PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), nodeid); | PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), nodeid); | ||||
} | } | ||||
} | } | ||||
// Requires cs_main. | |||||
// Returns a bool indicating whether we requested this block. | // Returns a bool indicating whether we requested this block. | ||||
// Also used if a block was /not/ received and timed out or started with another | // Also used if a block was /not/ received and timed out or started with another | ||||
// peer. | // peer. | ||||
static bool MarkBlockAsReceived(const uint256 &hash) { | static bool MarkBlockAsReceived(const uint256 &hash) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | |||||
std::map<uint256, | std::map<uint256, | ||||
std::pair<NodeId, std::list<QueuedBlock>::iterator>>::iterator | std::pair<NodeId, std::list<QueuedBlock>::iterator>>::iterator | ||||
itInFlight = mapBlocksInFlight.find(hash); | itInFlight = mapBlocksInFlight.find(hash); | ||||
if (itInFlight != mapBlocksInFlight.end()) { | if (itInFlight != mapBlocksInFlight.end()) { | ||||
CNodeState *state = State(itInFlight->second.first); | CNodeState *state = State(itInFlight->second.first); | ||||
state->nBlocksInFlightValidHeaders -= | state->nBlocksInFlightValidHeaders -= | ||||
itInFlight->second.second->fValidatedHeaders; | itInFlight->second.second->fValidatedHeaders; | ||||
if (state->nBlocksInFlightValidHeaders == 0 && | if (state->nBlocksInFlightValidHeaders == 0 && | ||||
Show All 12 Lines | if (itInFlight != mapBlocksInFlight.end()) { | ||||
state->nStallingSince = 0; | state->nStallingSince = 0; | ||||
mapBlocksInFlight.erase(itInFlight); | mapBlocksInFlight.erase(itInFlight); | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
// Requires cs_main. | |||||
// returns false, still setting pit, if the block was already in flight from the | // returns false, still setting pit, if the block was already in flight from the | ||||
// same peer pit will only be valid as long as the same cs_main lock is being | // same peer | ||||
// held. | // pit will only be valid as long as the same cs_main lock is being held. | ||||
static bool | static bool | ||||
MarkBlockAsInFlight(const Config &config, NodeId nodeid, const uint256 &hash, | MarkBlockAsInFlight(const Config &config, NodeId nodeid, const uint256 &hash, | ||||
const Consensus::Params &consensusParams, | const Consensus::Params &consensusParams, | ||||
const CBlockIndex *pindex = nullptr, | const CBlockIndex *pindex = nullptr, | ||||
std::list<QueuedBlock>::iterator **pit = nullptr) { | std::list<QueuedBlock>::iterator **pit = nullptr) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | |||||
CNodeState *state = State(nodeid); | CNodeState *state = State(nodeid); | ||||
assert(state != nullptr); | assert(state != nullptr); | ||||
// Short-circuit most stuff in case its from the same node. | // Short-circuit most stuff in case its from the same node. | ||||
std::map<uint256, | std::map<uint256, | ||||
std::pair<NodeId, std::list<QueuedBlock>::iterator>>::iterator | std::pair<NodeId, std::list<QueuedBlock>::iterator>>::iterator | ||||
itInFlight = mapBlocksInFlight.find(hash); | itInFlight = mapBlocksInFlight.find(hash); | ||||
if (itInFlight != mapBlocksInFlight.end() && | if (itInFlight != mapBlocksInFlight.end() && | ||||
Show All 30 Lines | MarkBlockAsInFlight(const Config &config, NodeId nodeid, const uint256 &hash, | ||||
if (pit) { | if (pit) { | ||||
*pit = &itInFlight->second.second; | *pit = &itInFlight->second.second; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
/** Check whether the last unknown block a peer advertised is not yet known. */ | /** Check whether the last unknown block a peer advertised is not yet known. */ | ||||
static void ProcessBlockAvailability(NodeId nodeid) { | static void ProcessBlockAvailability(NodeId nodeid) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | |||||
CNodeState *state = State(nodeid); | CNodeState *state = State(nodeid); | ||||
assert(state != nullptr); | assert(state != nullptr); | ||||
if (!state->hashLastUnknownBlock.IsNull()) { | if (!state->hashLastUnknownBlock.IsNull()) { | ||||
BlockMap::iterator itOld = | BlockMap::iterator itOld = | ||||
mapBlockIndex.find(state->hashLastUnknownBlock); | mapBlockIndex.find(state->hashLastUnknownBlock); | ||||
if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) { | if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) { | ||||
if (state->pindexBestKnownBlock == nullptr || | if (state->pindexBestKnownBlock == nullptr || | ||||
itOld->second->nChainWork >= | itOld->second->nChainWork >= | ||||
state->pindexBestKnownBlock->nChainWork) { | state->pindexBestKnownBlock->nChainWork) { | ||||
state->pindexBestKnownBlock = itOld->second; | state->pindexBestKnownBlock = itOld->second; | ||||
} | } | ||||
state->hashLastUnknownBlock.SetNull(); | state->hashLastUnknownBlock.SetNull(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/** Update tracking information about which blocks a peer is assumed to have. */ | /** Update tracking information about which blocks a peer is assumed to have. */ | ||||
static void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { | static void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | |||||
CNodeState *state = State(nodeid); | CNodeState *state = State(nodeid); | ||||
assert(state != nullptr); | assert(state != nullptr); | ||||
ProcessBlockAvailability(nodeid); | ProcessBlockAvailability(nodeid); | ||||
BlockMap::iterator it = mapBlockIndex.find(hash); | BlockMap::iterator it = mapBlockIndex.find(hash); | ||||
if (it != mapBlockIndex.end() && it->second->nChainWork > 0) { | if (it != mapBlockIndex.end() && it->second->nChainWork > 0) { | ||||
// An actually better block was announced. | // An actually better block was announced. | ||||
if (state->pindexBestKnownBlock == nullptr || | if (state->pindexBestKnownBlock == nullptr || | ||||
it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) { | it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) { | ||||
state->pindexBestKnownBlock = it->second; | state->pindexBestKnownBlock = it->second; | ||||
} | } | ||||
} else { | } else { | ||||
// An unknown block was announced; just assume that the latest one is | // An unknown block was announced; just assume that the latest one is | ||||
// the best one. | // the best one. | ||||
state->hashLastUnknownBlock = hash; | state->hashLastUnknownBlock = hash; | ||||
} | } | ||||
} | } | ||||
/** | |||||
* 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 | |||||
* lNodesAnnouncingHeaderAndIDs, and keeping that list under a certain size by | |||||
* removing the first element if necessary. | |||||
*/ | |||||
static void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, | static void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, | ||||
CConnman *connman) { | CConnman *connman) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
CNodeState *nodestate = State(nodeid); | CNodeState *nodestate = State(nodeid); | ||||
if (!nodestate) { | if (!nodestate) { | ||||
LogPrint(BCLog::NET, "node state unavailable: peer=%d\n", nodeid); | LogPrint(BCLog::NET, "node state unavailable: peer=%d\n", nodeid); | ||||
return; | return; | ||||
} | } | ||||
if (!nodestate->fProvidesHeaderAndIDs) { | if (!nodestate->fProvidesHeaderAndIDs) { | ||||
return; | return; | ||||
} | } | ||||
for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin(); | for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin(); | ||||
it != lNodesAnnouncingHeaderAndIDs.end(); it++) { | it != lNodesAnnouncingHeaderAndIDs.end(); it++) { | ||||
if (*it == nodeid) { | if (*it == nodeid) { | ||||
lNodesAnnouncingHeaderAndIDs.erase(it); | lNodesAnnouncingHeaderAndIDs.erase(it); | ||||
lNodesAnnouncingHeaderAndIDs.push_back(nodeid); | lNodesAnnouncingHeaderAndIDs.push_back(nodeid); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
connman->ForNode(nodeid, [&connman](CNode *pfrom) { | connman->ForNode(nodeid, [&connman](CNode *pfrom) { | ||||
AssertLockHeld(cs_main); | |||||
bool fAnnounceUsingCMPCTBLOCK = false; | bool fAnnounceUsingCMPCTBLOCK = false; | ||||
uint64_t nCMPCTBLOCKVersion = 1; | uint64_t nCMPCTBLOCKVersion = 1; | ||||
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) { | if (lNodesAnnouncingHeaderAndIDs.size() >= 3) { | ||||
// As per BIP152, we only get 3 of our peers to announce | // As per BIP152, we only get 3 of our peers to announce | ||||
// blocks using compact encodings. | // blocks using compact encodings. | ||||
connman->ForNode(lNodesAnnouncingHeaderAndIDs.front(), | connman->ForNode(lNodesAnnouncingHeaderAndIDs.front(), | ||||
[&connman, fAnnounceUsingCMPCTBLOCK, | [&connman, fAnnounceUsingCMPCTBLOCK, | ||||
nCMPCTBLOCKVersion](CNode *pnodeStop) { | nCMPCTBLOCKVersion](CNode *pnodeStop) { | ||||
AssertLockHeld(cs_main); | |||||
connman->PushMessage( | connman->PushMessage( | ||||
pnodeStop, | pnodeStop, | ||||
CNetMsgMaker(pnodeStop->GetSendVersion()) | CNetMsgMaker(pnodeStop->GetSendVersion()) | ||||
.Make(NetMsgType::SENDCMPCT, | .Make(NetMsgType::SENDCMPCT, | ||||
fAnnounceUsingCMPCTBLOCK, | fAnnounceUsingCMPCTBLOCK, | ||||
nCMPCTBLOCKVersion)); | nCMPCTBLOCKVersion)); | ||||
return true; | return true; | ||||
}); | }); | ||||
lNodesAnnouncingHeaderAndIDs.pop_front(); | lNodesAnnouncingHeaderAndIDs.pop_front(); | ||||
} | } | ||||
fAnnounceUsingCMPCTBLOCK = true; | fAnnounceUsingCMPCTBLOCK = true; | ||||
connman->PushMessage(pfrom, | connman->PushMessage(pfrom, | ||||
CNetMsgMaker(pfrom->GetSendVersion()) | CNetMsgMaker(pfrom->GetSendVersion()) | ||||
.Make(NetMsgType::SENDCMPCT, | .Make(NetMsgType::SENDCMPCT, | ||||
fAnnounceUsingCMPCTBLOCK, | fAnnounceUsingCMPCTBLOCK, | ||||
nCMPCTBLOCKVersion)); | nCMPCTBLOCKVersion)); | ||||
lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId()); | lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId()); | ||||
return true; | return true; | ||||
}); | }); | ||||
} | } | ||||
static bool TipMayBeStale(const Consensus::Params &consensusParams) { | static bool TipMayBeStale(const Consensus::Params &consensusParams) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | |||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
if (g_last_tip_update == 0) { | if (g_last_tip_update == 0) { | ||||
g_last_tip_update = GetTime(); | g_last_tip_update = GetTime(); | ||||
} | } | ||||
return g_last_tip_update < | return g_last_tip_update < | ||||
GetTime() - consensusParams.nPowTargetSpacing * 3 && | GetTime() - consensusParams.nPowTargetSpacing * 3 && | ||||
mapBlocksInFlight.empty(); | mapBlocksInFlight.empty(); | ||||
} | } | ||||
// Requires cs_main | static bool CanDirectFetch(const Consensus::Params &consensusParams) | ||||
static bool CanDirectFetch(const Consensus::Params &consensusParams) { | EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
return chainActive.Tip()->GetBlockTime() > | return chainActive.Tip()->GetBlockTime() > | ||||
GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20; | GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20; | ||||
} | } | ||||
// Requires cs_main | static bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) | ||||
static bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) { | EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
if (state->pindexBestKnownBlock && | if (state->pindexBestKnownBlock && | ||||
pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight)) { | pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight)) { | ||||
return true; | return true; | ||||
} | } | ||||
if (state->pindexBestHeaderSent && | if (state->pindexBestHeaderSent && | ||||
pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight)) { | pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight)) { | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
/** | /** | ||||
* Update pindexLastCommonBlock and add not-in-flight missing successors to | * Update pindexLastCommonBlock and add not-in-flight missing successors to | ||||
* vBlocks, until it has at most count entries. | * vBlocks, until it has at most count entries. | ||||
*/ | */ | ||||
static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, | static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, | ||||
std::vector<const CBlockIndex *> &vBlocks, | std::vector<const CBlockIndex *> &vBlocks, | ||||
NodeId &nodeStaller, | NodeId &nodeStaller, | ||||
const Consensus::Params &consensusParams) { | const Consensus::Params &consensusParams) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | |||||
if (count == 0) { | if (count == 0) { | ||||
return; | return; | ||||
} | } | ||||
vBlocks.reserve(vBlocks.size() + count); | vBlocks.reserve(vBlocks.size() + count); | ||||
CNodeState *state = State(nodeid); | CNodeState *state = State(nodeid); | ||||
assert(state != nullptr); | assert(state != nullptr); | ||||
▲ Show 20 Lines • Show All 311 Lines • ▼ Show 20 Lines | while (mapOrphanTransactions.size() > nMaxOrphans) { | ||||
it = mapOrphanTransactions.begin(); | it = mapOrphanTransactions.begin(); | ||||
} | } | ||||
EraseOrphanTx(it->first); | EraseOrphanTx(it->first); | ||||
++nEvicted; | ++nEvicted; | ||||
} | } | ||||
return nEvicted; | return nEvicted; | ||||
} | } | ||||
// Requires cs_main. | /** | ||||
void Misbehaving(NodeId pnode, int howmuch, const std::string &reason) { | * Mark a misbehaving peer to be banned depending upon the value of `-banscore`. | ||||
*/ | |||||
void Misbehaving(NodeId pnode, int howmuch, const std::string &reason) | |||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | |||||
if (howmuch == 0) { | if (howmuch == 0) { | ||||
return; | return; | ||||
} | } | ||||
CNodeState *state = State(pnode); | CNodeState *state = State(pnode); | ||||
if (state == nullptr) { | if (state == nullptr) { | ||||
return; | return; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | if (vOrphanErase.size()) { | ||||
"Erased %d orphan tx included or conflicted by block\n", | "Erased %d orphan tx included or conflicted by block\n", | ||||
nErased); | nErased); | ||||
} | } | ||||
g_last_tip_update = GetTime(); | g_last_tip_update = GetTime(); | ||||
} | } | ||||
static CCriticalSection cs_most_recent_block; | static CCriticalSection cs_most_recent_block; | ||||
static std::shared_ptr<const CBlock> most_recent_block; | static std::shared_ptr<const CBlock> | ||||
most_recent_block GUARDED_BY(cs_most_recent_block); | |||||
static std::shared_ptr<const CBlockHeaderAndShortTxIDs> | static std::shared_ptr<const CBlockHeaderAndShortTxIDs> | ||||
most_recent_compact_block; | most_recent_compact_block GUARDED_BY(cs_most_recent_block); | ||||
static uint256 most_recent_block_hash; | static uint256 most_recent_block_hash GUARDED_BY(cs_most_recent_block); | ||||
void PeerLogicValidation::NewPoWValidBlock( | void PeerLogicValidation::NewPoWValidBlock( | ||||
const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &pblock) { | const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &pblock) { | ||||
std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock = | std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock = | ||||
std::make_shared<const CBlockHeaderAndShortTxIDs>(*pblock); | std::make_shared<const CBlockHeaderAndShortTxIDs>(*pblock); | ||||
const CNetMsgMaker msgMaker(PROTOCOL_VERSION); | const CNetMsgMaker msgMaker(PROTOCOL_VERSION); | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Show All 10 Lines | uint256 hashBlock(pblock->GetHash()); | ||||
LOCK(cs_most_recent_block); | LOCK(cs_most_recent_block); | ||||
most_recent_block_hash = hashBlock; | most_recent_block_hash = hashBlock; | ||||
most_recent_block = pblock; | most_recent_block = pblock; | ||||
most_recent_compact_block = pcmpctblock; | most_recent_compact_block = pcmpctblock; | ||||
} | } | ||||
connman->ForEachNode([this, &pcmpctblock, pindex, &msgMaker, | connman->ForEachNode([this, &pcmpctblock, pindex, &msgMaker, | ||||
&hashBlock](CNode *pnode) { | &hashBlock](CNode *pnode) { | ||||
AssertLockHeld(cs_main); | |||||
// TODO: Avoid the repeated-serialization here | // TODO: Avoid the repeated-serialization here | ||||
if (pnode->nVersion < INVALID_CB_NO_BAN_VERSION || pnode->fDisconnect) { | if (pnode->nVersion < INVALID_CB_NO_BAN_VERSION || pnode->fDisconnect) { | ||||
return; | return; | ||||
} | } | ||||
ProcessBlockAvailability(pnode->GetId()); | ProcessBlockAvailability(pnode->GetId()); | ||||
CNodeState &state = *State(pnode->GetId()); | CNodeState &state = *State(pnode->GetId()); | ||||
// If the peer has, or we announced to them the previous block already, | // If the peer has, or we announced to them the previous block already, | ||||
// but we don't think they have this one, go ahead and announce it. | // but we don't think they have this one, go ahead and announce it. | ||||
▲ Show 20 Lines • Show All 2,448 Lines • ▼ Show 20 Lines | void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds) { | ||||
// Pick the outbound peer that least recently announced us a new block, with | // Pick the outbound peer that least recently announced us a new block, with | ||||
// ties broken by choosing the more recent connection (higher node id) | // ties broken by choosing the more recent connection (higher node id) | ||||
NodeId worst_peer = -1; | NodeId worst_peer = -1; | ||||
int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max(); | int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max(); | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
connman->ForEachNode([&](CNode *pnode) { | connman->ForEachNode([&](CNode *pnode) { | ||||
AssertLockHeld(cs_main); | |||||
// Ignore non-outbound peers, or nodes marked for disconnect already | // Ignore non-outbound peers, or nodes marked for disconnect already | ||||
if (!IsOutboundDisconnectionCandidate(pnode) || pnode->fDisconnect) { | if (!IsOutboundDisconnectionCandidate(pnode) || pnode->fDisconnect) { | ||||
return; | return; | ||||
} | } | ||||
CNodeState *state = State(pnode->GetId()); | CNodeState *state = State(pnode->GetId()); | ||||
if (state == nullptr) { | if (state == nullptr) { | ||||
// shouldn't be possible, but just in case | // shouldn't be possible, but just in case | ||||
return; | return; | ||||
Show All 10 Lines | connman->ForEachNode([&](CNode *pnode) { | ||||
} | } | ||||
}); | }); | ||||
if (worst_peer == -1) { | if (worst_peer == -1) { | ||||
return; | return; | ||||
} | } | ||||
bool disconnected = connman->ForNode(worst_peer, [&](CNode *pnode) { | bool disconnected = connman->ForNode(worst_peer, [&](CNode *pnode) { | ||||
AssertLockHeld(cs_main); | |||||
// Only disconnect a peer that has been connected to us for some | // Only disconnect a peer that has been connected to us for some | ||||
// reasonable fraction of our check-frequency, to give it time for new | // reasonable fraction of our check-frequency, to give it time for new | ||||
// information to have arrived. | // information to have arrived. | ||||
// Also don't disconnect any peer we're trying to download a block from. | // Also don't disconnect any peer we're trying to download a block from. | ||||
CNodeState &state = *State(pnode->GetId()); | CNodeState &state = *State(pnode->GetId()); | ||||
if (time_in_seconds - pnode->nTimeConnected > MINIMUM_CONNECT_TIME && | if (time_in_seconds - pnode->nTimeConnected > MINIMUM_CONNECT_TIME && | ||||
state.nBlocksInFlight == 0) { | state.nBlocksInFlight == 0) { | ||||
LogPrint(BCLog::NET, "disconnecting extra outbound peer=%d (last " | LogPrint(BCLog::NET, "disconnecting extra outbound peer=%d (last " | ||||
▲ Show 20 Lines • Show All 724 Lines • Show Last 20 Lines |