Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 701 Lines • ▼ Show 20 Lines | static bool TipMayBeStale(const Consensus::Params &consensusParams) | ||||
} | } | ||||
return g_last_tip_update < | return g_last_tip_update < | ||||
GetTime() - consensusParams.nPowTargetSpacing * 3 && | GetTime() - consensusParams.nPowTargetSpacing * 3 && | ||||
mapBlocksInFlight.empty(); | mapBlocksInFlight.empty(); | ||||
} | } | ||||
static bool CanDirectFetch(const Consensus::Params &consensusParams) | static bool CanDirectFetch(const Consensus::Params &consensusParams) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
return chainActive.Tip()->GetBlockTime() > | return ::ChainActive().Tip()->GetBlockTime() > | ||||
GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20; | GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20; | ||||
} | } | ||||
static bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) | static bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | 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; | ||||
Show All 22 Lines | static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, | ||||
CNodeState *state = State(nodeid); | CNodeState *state = State(nodeid); | ||||
assert(state != nullptr); | assert(state != nullptr); | ||||
// Make sure pindexBestKnownBlock is up to date, we'll need it. | // Make sure pindexBestKnownBlock is up to date, we'll need it. | ||||
ProcessBlockAvailability(nodeid); | ProcessBlockAvailability(nodeid); | ||||
if (state->pindexBestKnownBlock == nullptr || | if (state->pindexBestKnownBlock == nullptr || | ||||
state->pindexBestKnownBlock->nChainWork < | state->pindexBestKnownBlock->nChainWork < | ||||
chainActive.Tip()->nChainWork || | ::ChainActive().Tip()->nChainWork || | ||||
state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) { | state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) { | ||||
// This peer has nothing interesting. | // This peer has nothing interesting. | ||||
return; | return; | ||||
} | } | ||||
if (state->pindexLastCommonBlock == nullptr) { | if (state->pindexLastCommonBlock == nullptr) { | ||||
// Bootstrap quickly by guessing a parent of our best tip is the forking | // Bootstrap quickly by guessing a parent of our best tip is the forking | ||||
// point. Guessing wrong in either direction is not a problem. | // point. Guessing wrong in either direction is not a problem. | ||||
state->pindexLastCommonBlock = chainActive[std::min( | state->pindexLastCommonBlock = ::ChainActive()[std::min( | ||||
state->pindexBestKnownBlock->nHeight, chainActive.Height())]; | state->pindexBestKnownBlock->nHeight, ::ChainActive().Height())]; | ||||
} | } | ||||
// If the peer reorganized, our previous pindexLastCommonBlock may not be an | // If the peer reorganized, our previous pindexLastCommonBlock may not be an | ||||
// ancestor of its current tip anymore. Go back enough to fix that. | // ancestor of its current tip anymore. Go back enough to fix that. | ||||
state->pindexLastCommonBlock = LastCommonAncestor( | state->pindexLastCommonBlock = LastCommonAncestor( | ||||
state->pindexLastCommonBlock, state->pindexBestKnownBlock); | state->pindexLastCommonBlock, state->pindexBestKnownBlock); | ||||
if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) { | if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) { | ||||
return; | return; | ||||
Show All 30 Lines | while (pindexWalk->nHeight < nMaxHeight) { | ||||
// the meantime, update pindexLastCommonBlock as long as all ancestors | // the meantime, update pindexLastCommonBlock as long as all ancestors | ||||
// are already downloaded, or if it's already part of our chain (and | // are already downloaded, or if it's already part of our chain (and | ||||
// therefore don't need it even if pruned). | // therefore don't need it even if pruned). | ||||
for (const CBlockIndex *pindex : vToFetch) { | for (const CBlockIndex *pindex : vToFetch) { | ||||
if (!pindex->IsValid(BlockValidity::TREE)) { | if (!pindex->IsValid(BlockValidity::TREE)) { | ||||
// We consider the chain that this peer is on invalid. | // We consider the chain that this peer is on invalid. | ||||
return; | return; | ||||
} | } | ||||
if (pindex->nStatus.hasData() || chainActive.Contains(pindex)) { | if (pindex->nStatus.hasData() || ::ChainActive().Contains(pindex)) { | ||||
if (pindex->HaveTxsDownloaded()) { | if (pindex->HaveTxsDownloaded()) { | ||||
state->pindexLastCommonBlock = pindex; | state->pindexLastCommonBlock = pindex; | ||||
} | } | ||||
} else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) { | } else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) { | ||||
// The block is not already downloaded, and not yet in flight. | // The block is not already downloaded, and not yet in flight. | ||||
if (pindex->nHeight > nWindowEnd) { | if (pindex->nHeight > nWindowEnd) { | ||||
// We reached the end of the window. | // We reached the end of the window. | ||||
if (vBlocks.size() == 0 && waitingfor != nodeid) { | if (vBlocks.size() == 0 && waitingfor != nodeid) { | ||||
▲ Show 20 Lines • Show All 359 Lines • ▼ Show 20 Lines | |||||
// To prevent fingerprinting attacks, only send blocks/headers outside of the | // To prevent fingerprinting attacks, only send blocks/headers outside of the | ||||
// active chain if they are no more than a month older (both in time, and in | // active chain if they are no more than a month older (both in time, and in | ||||
// best equivalent proof of work) than the best header chain we know about and | // best equivalent proof of work) than the best header chain we know about and | ||||
// we fully-validated them at some point. | // we fully-validated them at some point. | ||||
static bool BlockRequestAllowed(const CBlockIndex *pindex, | static bool BlockRequestAllowed(const CBlockIndex *pindex, | ||||
const Consensus::Params &consensusParams) | const Consensus::Params &consensusParams) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
if (chainActive.Contains(pindex)) { | if (::ChainActive().Contains(pindex)) { | ||||
return true; | return true; | ||||
} | } | ||||
return pindex->IsValid(BlockValidity::SCRIPTS) && | return pindex->IsValid(BlockValidity::SCRIPTS) && | ||||
(pindexBestHeader != nullptr) && | (pindexBestHeader != nullptr) && | ||||
(pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() < | (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() < | ||||
STALE_RELAY_AGE_LIMIT) && | STALE_RELAY_AGE_LIMIT) && | ||||
(GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, | (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, | ||||
*pindexBestHeader, consensusParams) < | *pindexBestHeader, consensusParams) < | ||||
▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | connman->ForEachNode([this, &pcmpctblock, pindex, &msgMaker, | ||||
pnode, msgMaker.Make(NetMsgType::CMPCTBLOCK, *pcmpctblock)); | pnode, msgMaker.Make(NetMsgType::CMPCTBLOCK, *pcmpctblock)); | ||||
state.pindexBestHeaderSent = pindex; | state.pindexBestHeaderSent = pindex; | ||||
} | } | ||||
}); | }); | ||||
} | } | ||||
/** | /** | ||||
* Update our best height and announce any block hashes which weren't previously | * Update our best height and announce any block hashes which weren't previously | ||||
* in chainActive to our peers. | * in ::ChainActive() to our peers. | ||||
*/ | */ | ||||
void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, | void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, | ||||
const CBlockIndex *pindexFork, | const CBlockIndex *pindexFork, | ||||
bool fInitialDownload) { | bool fInitialDownload) { | ||||
const int nNewHeight = pindexNew->nHeight; | const int nNewHeight = pindexNew->nHeight; | ||||
connman->SetBestHeight(nNewHeight); | connman->SetBestHeight(nNewHeight); | ||||
SetServiceFlagsIBDCache(!fInitialDownload); | SetServiceFlagsIBDCache(!fInitialDownload); | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | |||||
// | // | ||||
// Messages | // Messages | ||||
// | // | ||||
static bool AlreadyHave(const CInv &inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | static bool AlreadyHave(const CInv &inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
switch (inv.type) { | switch (inv.type) { | ||||
case MSG_TX: { | case MSG_TX: { | ||||
assert(recentRejects); | assert(recentRejects); | ||||
if (chainActive.Tip()->GetBlockHash() != | if (::ChainActive().Tip()->GetBlockHash() != | ||||
hashRecentRejectsChainTip) { | hashRecentRejectsChainTip) { | ||||
// If the chain tip has changed previously rejected transactions | // If the chain tip has changed previously rejected transactions | ||||
// might be now valid, e.g. due to a nLockTime'd tx becoming | // might be now valid, e.g. due to a nLockTime'd tx becoming | ||||
// valid, or a double-spend. Reset the rejects filter and give | // valid, or a double-spend. Reset the rejects filter and give | ||||
// those txs a second chance. | // those txs a second chance. | ||||
hashRecentRejectsChainTip = chainActive.Tip()->GetBlockHash(); | hashRecentRejectsChainTip = | ||||
::ChainActive().Tip()->GetBlockHash(); | |||||
recentRejects->reset(); | recentRejects->reset(); | ||||
} | } | ||||
{ | { | ||||
LOCK(g_cs_orphans); | LOCK(g_cs_orphans); | ||||
if (mapOrphanTransactions.count(inv.hash)) { | if (mapOrphanTransactions.count(inv.hash)) { | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | static void ProcessGetBlockData(const Config &config, CNode *pfrom, | ||||
} | } | ||||
// Avoid leaking prune-height by never sending blocks below the | // Avoid leaking prune-height by never sending blocks below the | ||||
// NODE_NETWORK_LIMITED threshold. | // NODE_NETWORK_LIMITED threshold. | ||||
// Add two blocks buffer extension for possible races | // Add two blocks buffer extension for possible races | ||||
if (send && !pfrom->fWhitelisted && | if (send && !pfrom->fWhitelisted && | ||||
((((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == | ((((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == | ||||
NODE_NETWORK_LIMITED) && | NODE_NETWORK_LIMITED) && | ||||
((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && | ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && | ||||
(chainActive.Tip()->nHeight - pindex->nHeight > | (::ChainActive().Tip()->nHeight - pindex->nHeight > | ||||
(int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2)))) { | (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2)))) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"Ignore block request below NODE_NETWORK_LIMITED " | "Ignore block request below NODE_NETWORK_LIMITED " | ||||
"threshold from peer=%d\n", | "threshold from peer=%d\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
// disconnect node and prevent it from stalling (would otherwise wait | // disconnect node and prevent it from stalling (would otherwise wait | ||||
// for the missing block) | // for the missing block) | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | if (send && pindex->nStatus.hasData()) { | ||||
} else if (inv.type == MSG_CMPCT_BLOCK) { | } else if (inv.type == MSG_CMPCT_BLOCK) { | ||||
// If a peer is asking for old blocks, we're almost guaranteed they | // If a peer is asking for old blocks, we're almost guaranteed they | ||||
// won't have a useful mempool to match against a compact block, and | // won't have a useful mempool to match against a compact block, and | ||||
// we don't feel like constructing the object for them, so instead | // we don't feel like constructing the object for them, so instead | ||||
// we respond with the full, non-compact block. | // we respond with the full, non-compact block. | ||||
int nSendFlags = 0; | int nSendFlags = 0; | ||||
if (CanDirectFetch(consensusParams) && | if (CanDirectFetch(consensusParams) && | ||||
pindex->nHeight >= | pindex->nHeight >= | ||||
chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) { | ::ChainActive().Height() - MAX_CMPCTBLOCK_DEPTH) { | ||||
CBlockHeaderAndShortTxIDs cmpctblock(*pblock); | CBlockHeaderAndShortTxIDs cmpctblock(*pblock); | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, | pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, | ||||
cmpctblock)); | cmpctblock)); | ||||
} else { | } else { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, | pfrom, | ||||
msgMaker.Make(nSendFlags, NetMsgType::BLOCK, *pblock)); | msgMaker.Make(nSendFlags, NetMsgType::BLOCK, *pblock)); | ||||
} | } | ||||
} | } | ||||
// Trigger the peer node to send a getblocks request for the next batch | // Trigger the peer node to send a getblocks request for the next batch | ||||
// of inventory. | // of inventory. | ||||
if (hash == pfrom->hashContinue) { | if (hash == pfrom->hashContinue) { | ||||
// Bypass PushInventory, this must send even if redundant, and we | // Bypass PushInventory, this must send even if redundant, and we | ||||
// want it right after the last block so they don't wait for other | // want it right after the last block so they don't wait for other | ||||
// stuff first. | // stuff first. | ||||
std::vector<CInv> vInv; | std::vector<CInv> vInv; | ||||
vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash())); | vInv.push_back( | ||||
CInv(MSG_BLOCK, ::ChainActive().Tip()->GetBlockHash())); | |||||
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv)); | connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv)); | ||||
pfrom->hashContinue = BlockHash(); | pfrom->hashContinue = BlockHash(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static void ProcessGetData(const Config &config, CNode *pfrom, | static void ProcessGetData(const Config &config, CNode *pfrom, | ||||
CConnman *connman, | CConnman *connman, | ||||
▲ Show 20 Lines • Show All 123 Lines • ▼ Show 20 Lines | const CBlockIndex *pindexLast = nullptr; | ||||
// - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that | // - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that | ||||
// don't connect before giving DoS points | // don't connect before giving DoS points | ||||
// - Once a headers message is received that is valid and does connect, | // - Once a headers message is received that is valid and does connect, | ||||
// nUnconnectingHeaders gets reset back to 0. | // nUnconnectingHeaders gets reset back to 0. | ||||
if (!LookupBlockIndex(headers[0].hashPrevBlock) && | if (!LookupBlockIndex(headers[0].hashPrevBlock) && | ||||
nCount < MAX_BLOCKS_TO_ANNOUNCE) { | nCount < MAX_BLOCKS_TO_ANNOUNCE) { | ||||
nodestate->nUnconnectingHeaders++; | nodestate->nUnconnectingHeaders++; | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, msgMaker.Make(NetMsgType::GETHEADERS, | pfrom, | ||||
chainActive.GetLocator(pindexBestHeader), | msgMaker.Make(NetMsgType::GETHEADERS, | ||||
::ChainActive().GetLocator(pindexBestHeader), | |||||
uint256())); | uint256())); | ||||
LogPrint( | LogPrint( | ||||
BCLog::NET, | BCLog::NET, | ||||
"received header %s: missing prev block %s, sending getheaders " | "received header %s: missing prev block %s, sending getheaders " | ||||
"(%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", | "(%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", | ||||
headers[0].GetHash().ToString(), | headers[0].GetHash().ToString(), | ||||
headers[0].hashPrevBlock.ToString(), pindexBestHeader->nHeight, | headers[0].hashPrevBlock.ToString(), pindexBestHeader->nHeight, | ||||
pfrom->GetId(), nodestate->nUnconnectingHeaders); | pfrom->GetId(), nodestate->nUnconnectingHeaders); | ||||
// Set hashLastUnknownBlock for this peer, so that if we eventually | // Set hashLastUnknownBlock for this peer, so that if we eventually | ||||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | if (!ProcessNewBlockHeaders(config, headers, state, &pindexLast, | ||||
assert(pindexLast); | assert(pindexLast); | ||||
UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash()); | UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash()); | ||||
// From here, pindexBestKnownBlock should be guaranteed to be non-null, | // From here, pindexBestKnownBlock should be guaranteed to be non-null, | ||||
// because it is set in UpdateBlockAvailability. Some nullptr checks are | // because it is set in UpdateBlockAvailability. Some nullptr checks are | ||||
// still present, however, as belt-and-suspenders. | // still present, however, as belt-and-suspenders. | ||||
if (received_new_header && | if (received_new_header && | ||||
pindexLast->nChainWork > chainActive.Tip()->nChainWork) { | pindexLast->nChainWork > ::ChainActive().Tip()->nChainWork) { | ||||
nodestate->m_last_block_announcement = GetTime(); | nodestate->m_last_block_announcement = GetTime(); | ||||
} | } | ||||
if (nCount == MAX_HEADERS_RESULTS) { | if (nCount == MAX_HEADERS_RESULTS) { | ||||
// Headers message had its maximum size; the peer may have more | // Headers message had its maximum size; the peer may have more | ||||
// headers. | // headers. | ||||
// TODO: optimize: if pindexLast is an ancestor of chainActive.Tip | // TODO: optimize: if pindexLast is an ancestor of | ||||
// or pindexBestHeader, continue from there instead. | // ::ChainActive().Tip or pindexBestHeader, continue from there | ||||
// instead. | |||||
LogPrint( | LogPrint( | ||||
BCLog::NET, | BCLog::NET, | ||||
"more getheaders (%d) to end to peer=%d (startheight:%d)\n", | "more getheaders (%d) to end to peer=%d (startheight:%d)\n", | ||||
pindexLast->nHeight, pfrom->GetId(), pfrom->nStartingHeight); | pindexLast->nHeight, pfrom->GetId(), pfrom->nStartingHeight); | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, | pfrom, msgMaker.Make(NetMsgType::GETHEADERS, | ||||
msgMaker.Make(NetMsgType::GETHEADERS, | ::ChainActive().GetLocator(pindexLast), | ||||
chainActive.GetLocator(pindexLast), uint256())); | uint256())); | ||||
} | } | ||||
bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); | bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); | ||||
// If this set of headers is valid and ends in a block with at least as | // If this set of headers is valid and ends in a block with at least as | ||||
// much work as our tip, download as much as possible. | // much work as our tip, download as much as possible. | ||||
if (fCanDirectFetch && pindexLast->IsValid(BlockValidity::TREE) && | if (fCanDirectFetch && pindexLast->IsValid(BlockValidity::TREE) && | ||||
chainActive.Tip()->nChainWork <= pindexLast->nChainWork) { | ::ChainActive().Tip()->nChainWork <= pindexLast->nChainWork) { | ||||
std::vector<const CBlockIndex *> vToFetch; | std::vector<const CBlockIndex *> vToFetch; | ||||
const CBlockIndex *pindexWalk = pindexLast; | const CBlockIndex *pindexWalk = pindexLast; | ||||
// Calculate all the blocks we'd need to switch to pindexLast, up to | // Calculate all the blocks we'd need to switch to pindexLast, up to | ||||
// a limit. | // a limit. | ||||
while (pindexWalk && !chainActive.Contains(pindexWalk) && | while (pindexWalk && !::ChainActive().Contains(pindexWalk) && | ||||
vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { | vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { | ||||
if (!pindexWalk->nStatus.hasData() && | if (!pindexWalk->nStatus.hasData() && | ||||
!mapBlocksInFlight.count(pindexWalk->GetBlockHash())) { | !mapBlocksInFlight.count(pindexWalk->GetBlockHash())) { | ||||
// We don't have this block, and it's not yet in flight. | // We don't have this block, and it's not yet in flight. | ||||
vToFetch.push_back(pindexWalk); | vToFetch.push_back(pindexWalk); | ||||
} | } | ||||
pindexWalk = pindexWalk->pprev; | pindexWalk = pindexWalk->pprev; | ||||
} | } | ||||
// If pindexWalk still isn't on our main chain, we're looking at a | // If pindexWalk still isn't on our main chain, we're looking at a | ||||
// very large reorg at a time we think we're close to caught up to | // very large reorg at a time we think we're close to caught up to | ||||
// the main chain -- this shouldn't really happen. Bail out on the | // the main chain -- this shouldn't really happen. Bail out on the | ||||
// direct fetch and rely on parallel download instead. | // direct fetch and rely on parallel download instead. | ||||
if (!chainActive.Contains(pindexWalk)) { | if (!::ChainActive().Contains(pindexWalk)) { | ||||
LogPrint( | LogPrint( | ||||
BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n", | BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n", | ||||
pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); | pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); | ||||
} else { | } else { | ||||
std::vector<CInv> vGetData; | std::vector<CInv> vGetData; | ||||
// Download as much as possible, from earliest to latest. | // Download as much as possible, from earliest to latest. | ||||
for (const CBlockIndex *pindex : reverse_iterate(vToFetch)) { | for (const CBlockIndex *pindex : reverse_iterate(vToFetch)) { | ||||
if (nodestate->nBlocksInFlight >= | if (nodestate->nBlocksInFlight >= | ||||
Show All 35 Lines | if (!ProcessNewBlockHeaders(config, headers, state, &pindexLast, | ||||
// headers to fetch from this peer. | // headers to fetch from this peer. | ||||
if (nodestate->pindexBestKnownBlock && | if (nodestate->pindexBestKnownBlock && | ||||
nodestate->pindexBestKnownBlock->nChainWork < | nodestate->pindexBestKnownBlock->nChainWork < | ||||
nMinimumChainWork) { | nMinimumChainWork) { | ||||
// This peer has too little work on their headers chain to help | // This peer has too little work on their headers chain to help | ||||
// us sync -- disconnect if using an outbound slot (unless | // us sync -- disconnect if using an outbound slot (unless | ||||
// whitelisted or addnode). | // whitelisted or addnode). | ||||
// Note: We compare their tip to nMinimumChainWork (rather than | // Note: We compare their tip to nMinimumChainWork (rather than | ||||
// chainActive.Tip()) because we won't start block download | // ::ChainActive().Tip()) because we won't start block download | ||||
// until we have a headers chain that has at least | // until we have a headers chain that has at least | ||||
// nMinimumChainWork, even if a peer has a chain past our tip, | // nMinimumChainWork, even if a peer has a chain past our tip, | ||||
// as an anti-DoS measure. | // as an anti-DoS measure. | ||||
if (IsOutboundDisconnectionCandidate(pfrom)) { | if (IsOutboundDisconnectionCandidate(pfrom)) { | ||||
LogPrintf("Disconnecting outbound peer %d -- headers " | LogPrintf("Disconnecting outbound peer %d -- headers " | ||||
"chain has insufficient work\n", | "chain has insufficient work\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && | if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && | ||||
nodestate->pindexBestKnownBlock != nullptr) { | nodestate->pindexBestKnownBlock != nullptr) { | ||||
// If this is an outbound peer, check to see if we should protect it | // If this is an outbound peer, check to see if we should protect it | ||||
// from the bad/lagging chain logic. | // from the bad/lagging chain logic. | ||||
if (g_outbound_peers_with_protect_from_disconnect < | if (g_outbound_peers_with_protect_from_disconnect < | ||||
MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && | MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && | ||||
nodestate->pindexBestKnownBlock->nChainWork >= | nodestate->pindexBestKnownBlock->nChainWork >= | ||||
chainActive.Tip()->nChainWork && | ::ChainActive().Tip()->nChainWork && | ||||
!nodestate->m_chain_sync.m_protect) { | !nodestate->m_chain_sync.m_protect) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"Protecting outbound peer=%d from eviction\n", | "Protecting outbound peer=%d from eviction\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
nodestate->m_chain_sync.m_protect = true; | nodestate->m_chain_sync.m_protect = true; | ||||
++g_outbound_peers_with_protect_from_disconnect; | ++g_outbound_peers_with_protect_from_disconnect; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 448 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::INV) { | ||||
// We used to request the full block here, but since | // We used to request the full block here, but since | ||||
// headers-announcements are now the primary method of | // headers-announcements are now the primary method of | ||||
// announcement on the network, and since, in the case that | // announcement on the network, and since, in the case that | ||||
// a node fell back to inv we probably have a reorg which we | // a node fell back to inv we probably have a reorg which we | ||||
// should get the headers for first, we now only provide a | // should get the headers for first, we now only provide a | ||||
// getheaders response here. When we receive the headers, we | // getheaders response here. When we receive the headers, we | ||||
// will then ask for the blocks we need. | // will then ask for the blocks we need. | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, | pfrom, msgMaker.Make( | ||||
msgMaker.Make(NetMsgType::GETHEADERS, | NetMsgType::GETHEADERS, | ||||
chainActive.GetLocator(pindexBestHeader), | ::ChainActive().GetLocator(pindexBestHeader), | ||||
hash)); | hash)); | ||||
LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", | LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", | ||||
pindexBestHeader->nHeight, hash.ToString(), | pindexBestHeader->nHeight, hash.ToString(), | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
} | } | ||||
} else { | } else { | ||||
pfrom->AddInventoryKnown(inv); | pfrom->AddInventoryKnown(inv); | ||||
if (fBlocksOnly) { | if (fBlocksOnly) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::GETBLOCKS) { | ||||
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", | LogPrint(BCLog::NET, "failed to activate chain (%s)\n", | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
} | } | ||||
} | } | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
// Find the last block the caller has in the main chain | // Find the last block the caller has in the main chain | ||||
const CBlockIndex *pindex = FindForkInGlobalIndex(chainActive, locator); | const CBlockIndex *pindex = | ||||
FindForkInGlobalIndex(::ChainActive(), locator); | |||||
// Send the rest of the chain | // Send the rest of the chain | ||||
if (pindex) { | if (pindex) { | ||||
pindex = chainActive.Next(pindex); | pindex = ::ChainActive().Next(pindex); | ||||
} | } | ||||
int nLimit = 500; | int nLimit = 500; | ||||
LogPrint(BCLog::NET, "getblocks %d to %s limit %d from peer=%d\n", | LogPrint(BCLog::NET, "getblocks %d to %s limit %d from peer=%d\n", | ||||
(pindex ? pindex->nHeight : -1), | (pindex ? pindex->nHeight : -1), | ||||
hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, | hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
for (; pindex; pindex = chainActive.Next(pindex)) { | for (; pindex; pindex = ::ChainActive().Next(pindex)) { | ||||
if (pindex->GetBlockHash() == hashStop) { | if (pindex->GetBlockHash() == hashStop) { | ||||
LogPrint(BCLog::NET, " getblocks stopping at %d %s\n", | LogPrint(BCLog::NET, " getblocks stopping at %d %s\n", | ||||
pindex->nHeight, pindex->GetBlockHash().ToString()); | pindex->nHeight, pindex->GetBlockHash().ToString()); | ||||
break; | break; | ||||
} | } | ||||
// If pruning, don't inv blocks unless we have on disk and are | // If pruning, don't inv blocks unless we have on disk and are | ||||
// likely to still have for some reasonable time window (1 hour) | // likely to still have for some reasonable time window (1 hour) | ||||
// that block relay might require. | // that block relay might require. | ||||
const int nPrunedBlocksLikelyToHave = | const int nPrunedBlocksLikelyToHave = | ||||
MIN_BLOCKS_TO_KEEP - | MIN_BLOCKS_TO_KEEP - | ||||
3600 / chainparams.GetConsensus().nPowTargetSpacing; | 3600 / chainparams.GetConsensus().nPowTargetSpacing; | ||||
if (fPruneMode && | if (fPruneMode && | ||||
(!pindex->nStatus.hasData() || | (!pindex->nStatus.hasData() || | ||||
pindex->nHeight <= | pindex->nHeight <= ::ChainActive().Tip()->nHeight - | ||||
chainActive.Tip()->nHeight - nPrunedBlocksLikelyToHave)) { | nPrunedBlocksLikelyToHave)) { | ||||
LogPrint( | LogPrint( | ||||
BCLog::NET, | BCLog::NET, | ||||
" getblocks stopping, pruned or too old block at %d %s\n", | " getblocks stopping, pruned or too old block at %d %s\n", | ||||
pindex->nHeight, pindex->GetBlockHash().ToString()); | pindex->nHeight, pindex->GetBlockHash().ToString()); | ||||
break; | break; | ||||
} | } | ||||
pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); | pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); | ||||
if (--nLimit <= 0) { | if (--nLimit <= 0) { | ||||
Show All 31 Lines | if (strCommand == NetMsgType::GETBLOCKTXN) { | ||||
if (!pindex || !pindex->nStatus.hasData()) { | if (!pindex || !pindex->nStatus.hasData()) { | ||||
LogPrint( | LogPrint( | ||||
BCLog::NET, | BCLog::NET, | ||||
"Peer %d sent us a getblocktxn for a block we don't have\n", | "Peer %d sent us a getblocktxn for a block we don't have\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
return true; | return true; | ||||
} | } | ||||
if (pindex->nHeight < chainActive.Height() - MAX_BLOCKTXN_DEPTH) { | if (pindex->nHeight < ::ChainActive().Height() - MAX_BLOCKTXN_DEPTH) { | ||||
// If an older block is requested (should never happen in practice, | // If an older block is requested (should never happen in practice, | ||||
// but can happen in tests) send a block response instead of a | // but can happen in tests) send a block response instead of a | ||||
// blocktxn response. Sending a full block response instead of a | // blocktxn response. Sending a full block response instead of a | ||||
// small blocktxn response is preferable in the case where a peer | // small blocktxn response is preferable in the case where a peer | ||||
// might maliciously send lots of getblocktxn requests to trigger | // might maliciously send lots of getblocktxn requests to trigger | ||||
// expensive disk reads, because it will require the peer to | // expensive disk reads, because it will require the peer to | ||||
// actually receive all the data read from disk over the network. | // actually receive all the data read from disk over the network. | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::GETHEADERS) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"%s: ignoring request from peer=%i for old block " | "%s: ignoring request from peer=%i for old block " | ||||
"header that isn't in the main chain\n", | "header that isn't in the main chain\n", | ||||
__func__, pfrom->GetId()); | __func__, pfrom->GetId()); | ||||
return true; | return true; | ||||
} | } | ||||
} else { | } else { | ||||
// Find the last block the caller has in the main chain | // Find the last block the caller has in the main chain | ||||
pindex = FindForkInGlobalIndex(chainActive, locator); | pindex = FindForkInGlobalIndex(::ChainActive(), locator); | ||||
if (pindex) { | if (pindex) { | ||||
pindex = chainActive.Next(pindex); | pindex = ::ChainActive().Next(pindex); | ||||
} | } | ||||
} | } | ||||
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx | // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx | ||||
// count at the end | // count at the end | ||||
std::vector<CBlock> vHeaders; | std::vector<CBlock> vHeaders; | ||||
int nLimit = MAX_HEADERS_RESULTS; | int nLimit = MAX_HEADERS_RESULTS; | ||||
LogPrint(BCLog::NET, "getheaders %d to %s from peer=%d\n", | LogPrint(BCLog::NET, "getheaders %d to %s from peer=%d\n", | ||||
(pindex ? pindex->nHeight : -1), | (pindex ? pindex->nHeight : -1), | ||||
hashStop.IsNull() ? "end" : hashStop.ToString(), | hashStop.IsNull() ? "end" : hashStop.ToString(), | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
for (; pindex; pindex = chainActive.Next(pindex)) { | for (; pindex; pindex = ::ChainActive().Next(pindex)) { | ||||
vHeaders.push_back(pindex->GetBlockHeader()); | vHeaders.push_back(pindex->GetBlockHeader()); | ||||
if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) { | if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
// pindex can be nullptr either if we sent chainActive.Tip() OR | // pindex can be nullptr either if we sent ::ChainActive().Tip() OR | ||||
// if our peer has chainActive.Tip() (and thus we are sending an empty | // if our peer has ::ChainActive().Tip() (and thus we are sending an | ||||
// headers message). In both cases it's safe to update | // empty headers message). In both cases it's safe to update | ||||
// pindexBestHeaderSent to be our tip. | // pindexBestHeaderSent to be our tip. | ||||
// | // | ||||
// It is important that we simply reset the BestHeaderSent value here, | // It is important that we simply reset the BestHeaderSent value here, | ||||
// and not max(BestHeaderSent, newHeaderSent). We might have announced | // and not max(BestHeaderSent, newHeaderSent). We might have announced | ||||
// the currently-being-connected tip using a compact block, which | // the currently-being-connected tip using a compact block, which | ||||
// resulted in the peer sending a headers request, which we respond to | // resulted in the peer sending a headers request, which we respond to | ||||
// without the new block. By resetting the BestHeaderSent, we ensure we | // without the new block. By resetting the BestHeaderSent, we ensure we | ||||
// will re-announce the new block via headers (or compact blocks again) | // will re-announce the new block via headers (or compact blocks again) | ||||
// in the SendMessages logic. | // in the SendMessages logic. | ||||
nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip(); | nodestate->pindexBestHeaderSent = | ||||
pindex ? pindex : ::ChainActive().Tip(); | |||||
connman->PushMessage(pfrom, | connman->PushMessage(pfrom, | ||||
msgMaker.Make(NetMsgType::HEADERS, vHeaders)); | msgMaker.Make(NetMsgType::HEADERS, vHeaders)); | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::TX) { | if (strCommand == NetMsgType::TX) { | ||||
// Stop processing the transaction early if | // Stop processing the transaction early if | ||||
// We are in blocks only mode and peer is either not whitelisted or | // We are in blocks only mode and peer is either not whitelisted or | ||||
▲ Show 20 Lines • Show All 233 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) { | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
if (!LookupBlockIndex(cmpctblock.header.hashPrevBlock)) { | if (!LookupBlockIndex(cmpctblock.header.hashPrevBlock)) { | ||||
// Doesn't connect (or is genesis), instead of DoSing in | // Doesn't connect (or is genesis), instead of DoSing in | ||||
// AcceptBlockHeader, request deeper headers | // AcceptBlockHeader, request deeper headers | ||||
if (!IsInitialBlockDownload()) { | if (!IsInitialBlockDownload()) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, | pfrom, msgMaker.Make( | ||||
msgMaker.Make(NetMsgType::GETHEADERS, | NetMsgType::GETHEADERS, | ||||
chainActive.GetLocator(pindexBestHeader), | ::ChainActive().GetLocator(pindexBestHeader), | ||||
uint256())); | uint256())); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (!LookupBlockIndex(cmpctblock.header.GetHash())) { | if (!LookupBlockIndex(cmpctblock.header.GetHash())) { | ||||
received_new_header = true; | received_new_header = true; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) { | ||||
assert(pindex); | assert(pindex); | ||||
UpdateBlockAvailability(pfrom->GetId(), pindex->GetBlockHash()); | UpdateBlockAvailability(pfrom->GetId(), pindex->GetBlockHash()); | ||||
CNodeState *nodestate = State(pfrom->GetId()); | CNodeState *nodestate = State(pfrom->GetId()); | ||||
// If this was a new header with more work than our tip, update the | // If this was a new header with more work than our tip, update the | ||||
// peer's last block announcement time | // peer's last block announcement time | ||||
if (received_new_header && | if (received_new_header && | ||||
pindex->nChainWork > chainActive.Tip()->nChainWork) { | pindex->nChainWork > ::ChainActive().Tip()->nChainWork) { | ||||
nodestate->m_last_block_announcement = GetTime(); | nodestate->m_last_block_announcement = GetTime(); | ||||
} | } | ||||
std::map<uint256, | std::map<uint256, | ||||
std::pair<NodeId, std::list<QueuedBlock>::iterator>>:: | std::pair<NodeId, std::list<QueuedBlock>::iterator>>:: | ||||
iterator blockInFlightIt = | iterator blockInFlightIt = | ||||
mapBlocksInFlight.find(pindex->GetBlockHash()); | mapBlocksInFlight.find(pindex->GetBlockHash()); | ||||
bool fAlreadyInFlight = blockInFlightIt != mapBlocksInFlight.end(); | bool fAlreadyInFlight = blockInFlightIt != mapBlocksInFlight.end(); | ||||
if (pindex->nStatus.hasData()) { | if (pindex->nStatus.hasData()) { | ||||
// Nothing to do here | // Nothing to do here | ||||
return true; | return true; | ||||
} | } | ||||
if (pindex->nChainWork <= | if (pindex->nChainWork <= | ||||
chainActive.Tip()->nChainWork || // We know something better | ::ChainActive() | ||||
.Tip() | |||||
->nChainWork || // We know something better | |||||
pindex->nTx != 0) { | pindex->nTx != 0) { | ||||
// We had this block at some point, but pruned it | // We had this block at some point, but pruned it | ||||
if (fAlreadyInFlight) { | if (fAlreadyInFlight) { | ||||
// We requested this block for some reason, but our mempool | // We requested this block for some reason, but our mempool | ||||
// will probably be useless so we just grab the block via | // will probably be useless so we just grab the block via | ||||
// normal getdata. | // normal getdata. | ||||
std::vector<CInv> vInv(1); | std::vector<CInv> vInv(1); | ||||
vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); | vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); | pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
// If we're not close to tip yet, give up and let parallel block | // If we're not close to tip yet, give up and let parallel block | ||||
// fetch work its magic. | // fetch work its magic. | ||||
if (!fAlreadyInFlight && | if (!fAlreadyInFlight && | ||||
!CanDirectFetch(chainparams.GetConsensus())) { | !CanDirectFetch(chainparams.GetConsensus())) { | ||||
return true; | return true; | ||||
} | } | ||||
// We want to be a bit conservative just to be extra careful about | // We want to be a bit conservative just to be extra careful about | ||||
// DoS possibilities in compact block processing... | // DoS possibilities in compact block processing... | ||||
if (pindex->nHeight <= chainActive.Height() + 2) { | if (pindex->nHeight <= ::ChainActive().Height() + 2) { | ||||
if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < | if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < | ||||
MAX_BLOCKS_IN_TRANSIT_PER_PEER) || | MAX_BLOCKS_IN_TRANSIT_PER_PEER) || | ||||
(fAlreadyInFlight && | (fAlreadyInFlight && | ||||
blockInFlightIt->second.first == pfrom->GetId())) { | blockInFlightIt->second.first == pfrom->GetId())) { | ||||
std::list<QueuedBlock>::iterator *queuedBlockIt = nullptr; | std::list<QueuedBlock>::iterator *queuedBlockIt = nullptr; | ||||
if (!MarkBlockAsInFlight(config, pfrom->GetId(), | if (!MarkBlockAsInFlight(config, pfrom->GetId(), | ||||
pindex->GetBlockHash(), | pindex->GetBlockHash(), | ||||
chainparams.GetConsensus(), pindex, | chainparams.GetConsensus(), pindex, | ||||
▲ Show 20 Lines • Show All 753 Lines • ▼ Show 20 Lines | if (!state.m_chain_sync.m_protect && | ||||
// This is an outbound peer subject to disconnection if they don't | // This is an outbound peer subject to disconnection if they don't | ||||
// announce a block with as much work as the current tip within | // announce a block with as much work as the current tip within | ||||
// CHAIN_SYNC_TIMEOUT + HEADERS_RESPONSE_TIME seconds (note: if their | // CHAIN_SYNC_TIMEOUT + HEADERS_RESPONSE_TIME seconds (note: if their | ||||
// chain has more work than ours, we should sync to it, unless it's | // chain has more work than ours, we should sync to it, unless it's | ||||
// invalid, in which case we should find that out and disconnect from | // invalid, in which case we should find that out and disconnect from | ||||
// them elsewhere). | // them elsewhere). | ||||
if (state.pindexBestKnownBlock != nullptr && | if (state.pindexBestKnownBlock != nullptr && | ||||
state.pindexBestKnownBlock->nChainWork >= | state.pindexBestKnownBlock->nChainWork >= | ||||
chainActive.Tip()->nChainWork) { | ::ChainActive().Tip()->nChainWork) { | ||||
if (state.m_chain_sync.m_timeout != 0) { | if (state.m_chain_sync.m_timeout != 0) { | ||||
state.m_chain_sync.m_timeout = 0; | state.m_chain_sync.m_timeout = 0; | ||||
state.m_chain_sync.m_work_header = nullptr; | state.m_chain_sync.m_work_header = nullptr; | ||||
state.m_chain_sync.m_sent_getheaders = false; | state.m_chain_sync.m_sent_getheaders = false; | ||||
} | } | ||||
} else if (state.m_chain_sync.m_timeout == 0 || | } else if (state.m_chain_sync.m_timeout == 0 || | ||||
(state.m_chain_sync.m_work_header != nullptr && | (state.m_chain_sync.m_work_header != nullptr && | ||||
state.pindexBestKnownBlock != nullptr && | state.pindexBestKnownBlock != nullptr && | ||||
state.pindexBestKnownBlock->nChainWork >= | state.pindexBestKnownBlock->nChainWork >= | ||||
state.m_chain_sync.m_work_header->nChainWork)) { | state.m_chain_sync.m_work_header->nChainWork)) { | ||||
// Our best block known by this peer is behind our tip, and we're | // Our best block known by this peer is behind our tip, and we're | ||||
// either noticing that for the first time, OR this peer was able to | // either noticing that for the first time, OR this peer was able to | ||||
// catch up to some earlier point where we checked against our tip. | // catch up to some earlier point where we checked against our tip. | ||||
// Either way, set a new timeout based on current tip. | // Either way, set a new timeout based on current tip. | ||||
state.m_chain_sync.m_timeout = time_in_seconds + CHAIN_SYNC_TIMEOUT; | state.m_chain_sync.m_timeout = time_in_seconds + CHAIN_SYNC_TIMEOUT; | ||||
state.m_chain_sync.m_work_header = chainActive.Tip(); | state.m_chain_sync.m_work_header = ::ChainActive().Tip(); | ||||
state.m_chain_sync.m_sent_getheaders = false; | state.m_chain_sync.m_sent_getheaders = false; | ||||
} else if (state.m_chain_sync.m_timeout > 0 && | } else if (state.m_chain_sync.m_timeout > 0 && | ||||
time_in_seconds > state.m_chain_sync.m_timeout) { | time_in_seconds > state.m_chain_sync.m_timeout) { | ||||
// No evidence yet that our peer has synced to a chain with work | // No evidence yet that our peer has synced to a chain with work | ||||
// equal to that of our tip, when we first detected it was behind. | // equal to that of our tip, when we first detected it was behind. | ||||
// Send a single getheaders message to give the peer a chance to | // Send a single getheaders message to give the peer a chance to | ||||
// update us. | // update us. | ||||
if (state.m_chain_sync.m_sent_getheaders) { | if (state.m_chain_sync.m_sent_getheaders) { | ||||
Show All 17 Lines | if (!state.m_chain_sync.m_protect && | ||||
state.pindexBestKnownBlock != nullptr | state.pindexBestKnownBlock != nullptr | ||||
? state.pindexBestKnownBlock->GetBlockHash().ToString() | ? state.pindexBestKnownBlock->GetBlockHash().ToString() | ||||
: "<none>", | : "<none>", | ||||
state.m_chain_sync.m_work_header->GetBlockHash() | state.m_chain_sync.m_work_header->GetBlockHash() | ||||
.ToString()); | .ToString()); | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pto, | pto, | ||||
msgMaker.Make(NetMsgType::GETHEADERS, | msgMaker.Make(NetMsgType::GETHEADERS, | ||||
chainActive.GetLocator( | ::ChainActive().GetLocator( | ||||
state.m_chain_sync.m_work_header->pprev), | state.m_chain_sync.m_work_header->pprev), | ||||
uint256())); | uint256())); | ||||
state.m_chain_sync.m_sent_getheaders = true; | state.m_chain_sync.m_sent_getheaders = true; | ||||
// 2 minutes | // 2 minutes | ||||
constexpr int64_t HEADERS_RESPONSE_TIME = 120; | constexpr int64_t HEADERS_RESPONSE_TIME = 120; | ||||
// Bump the timeout to allow a response, which could clear the | // Bump the timeout to allow a response, which could clear the | ||||
// timeout (if the response shows the peer has synced), reset | // timeout (if the response shows the peer has synced), reset | ||||
// the timeout (if the peer syncs to the required work but not | // the timeout (if the peer syncs to the required work but not | ||||
▲ Show 20 Lines • Show All 223 Lines • ▼ Show 20 Lines | if (pto->nNextAddrSend < nNow) { | ||||
// we only send the big addr message once | // we only send the big addr message once | ||||
if (pto->vAddrToSend.capacity() > 40) { | if (pto->vAddrToSend.capacity() > 40) { | ||||
pto->vAddrToSend.shrink_to_fit(); | pto->vAddrToSend.shrink_to_fit(); | ||||
} | } | ||||
} | } | ||||
// Start block sync | // Start block sync | ||||
if (pindexBestHeader == nullptr) { | if (pindexBestHeader == nullptr) { | ||||
pindexBestHeader = chainActive.Tip(); | pindexBestHeader = ::ChainActive().Tip(); | ||||
} | } | ||||
// Download if this is a nice peer, or we have no nice peers and this one | // Download if this is a nice peer, or we have no nice peers and this one | ||||
// might do. | // might do. | ||||
bool fFetch = state.fPreferredDownload || | bool fFetch = state.fPreferredDownload || | ||||
(nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); | (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); | ||||
if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { | if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { | ||||
Show All 21 Lines | if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { | ||||
if (pindexStart->pprev) { | if (pindexStart->pprev) { | ||||
pindexStart = pindexStart->pprev; | pindexStart = pindexStart->pprev; | ||||
} | } | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"initial getheaders (%d) to peer=%d (startheight:%d)\n", | "initial getheaders (%d) to peer=%d (startheight:%d)\n", | ||||
pindexStart->nHeight, pto->GetId(), pto->nStartingHeight); | pindexStart->nHeight, pto->GetId(), pto->nStartingHeight); | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pto, | pto, msgMaker.Make(NetMsgType::GETHEADERS, | ||||
msgMaker.Make(NetMsgType::GETHEADERS, | ::ChainActive().GetLocator(pindexStart), | ||||
chainActive.GetLocator(pindexStart), uint256())); | uint256())); | ||||
} | } | ||||
} | } | ||||
// Resend wallet transactions that haven't gotten in a block yet | // Resend wallet transactions that haven't gotten in a block yet | ||||
// Except during reindex, importing and IBD, when old wallet transactions | // Except during reindex, importing and IBD, when old wallet transactions | ||||
// become unconfirmed and spams other nodes. | // become unconfirmed and spams other nodes. | ||||
if (!fReindex && !fImporting && !IsInitialBlockDownload()) { | if (!fReindex && !fImporting && !IsInitialBlockDownload()) { | ||||
GetMainSignals().Broadcast(nTimeBestReceived, connman); | GetMainSignals().Broadcast(nTimeBestReceived, connman); | ||||
Show All 19 Lines | // | ||||
const CBlockIndex *pBestIndex = nullptr; | const CBlockIndex *pBestIndex = nullptr; | ||||
// ensure pindexBestKnownBlock is up-to-date | // ensure pindexBestKnownBlock is up-to-date | ||||
ProcessBlockAvailability(pto->GetId()); | ProcessBlockAvailability(pto->GetId()); | ||||
if (!fRevertToInv) { | if (!fRevertToInv) { | ||||
bool fFoundStartingHeader = false; | bool fFoundStartingHeader = false; | ||||
// Try to find first header that our peer doesn't have, and then | // Try to find first header that our peer doesn't have, and then | ||||
// send all headers past that one. If we come across an headers that | // send all headers past that one. If we come across an headers that | ||||
// aren't on chainActive, give up. | // aren't on ::ChainActive(), give up. | ||||
for (const BlockHash &hash : pto->vBlockHashesToAnnounce) { | for (const BlockHash &hash : pto->vBlockHashesToAnnounce) { | ||||
const CBlockIndex *pindex = LookupBlockIndex(hash); | const CBlockIndex *pindex = LookupBlockIndex(hash); | ||||
assert(pindex); | assert(pindex); | ||||
if (chainActive[pindex->nHeight] != pindex) { | if (::ChainActive()[pindex->nHeight] != pindex) { | ||||
// Bail out if we reorged away from this block | // Bail out if we reorged away from this block | ||||
fRevertToInv = true; | fRevertToInv = true; | ||||
break; | break; | ||||
} | } | ||||
if (pBestIndex != nullptr && pindex->pprev != pBestIndex) { | if (pBestIndex != nullptr && pindex->pprev != pBestIndex) { | ||||
// This means that the list of blocks to announce don't | // This means that the list of blocks to announce don't | ||||
// connect to each other. This shouldn't really be possible | // connect to each other. This shouldn't really be possible | ||||
// to hit during regular operation (because reorgs should | // to hit during regular operation (because reorgs should | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | // | ||||
const BlockHash &hashToAnnounce = | const BlockHash &hashToAnnounce = | ||||
pto->vBlockHashesToAnnounce.back(); | pto->vBlockHashesToAnnounce.back(); | ||||
const CBlockIndex *pindex = LookupBlockIndex(hashToAnnounce); | const CBlockIndex *pindex = LookupBlockIndex(hashToAnnounce); | ||||
assert(pindex); | assert(pindex); | ||||
// Warn if we're announcing a block that is not on the main | // Warn if we're announcing a block that is not on the main | ||||
// chain. This should be very rare and could be optimized out. | // chain. This should be very rare and could be optimized out. | ||||
// Just log for now. | // Just log for now. | ||||
if (chainActive[pindex->nHeight] != pindex) { | if (::ChainActive()[pindex->nHeight] != pindex) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"Announcing block %s not on main chain (tip=%s)\n", | "Announcing block %s not on main chain (tip=%s)\n", | ||||
hashToAnnounce.ToString(), | hashToAnnounce.ToString(), | ||||
chainActive.Tip()->GetBlockHash().ToString()); | ::ChainActive().Tip()->GetBlockHash().ToString()); | ||||
} | } | ||||
// If the peer's chain has this block, don't inv it back. | // If the peer's chain has this block, don't inv it back. | ||||
if (!PeerHasHeader(&state, pindex)) { | if (!PeerHasHeader(&state, pindex)) { | ||||
pto->PushInventory(CInv(MSG_BLOCK, hashToAnnounce)); | pto->PushInventory(CInv(MSG_BLOCK, hashToAnnounce)); | ||||
LogPrint(BCLog::NET, "%s: sending inv peer=%d hash=%s\n", | LogPrint(BCLog::NET, "%s: sending inv peer=%d hash=%s\n", | ||||
__func__, pto->GetId(), hashToAnnounce.ToString()); | __func__, pto->GetId(), hashToAnnounce.ToString()); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 402 Lines • Show Last 20 Lines |