Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 433 Lines • ▼ Show 20 Lines | |||||
/** 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) { | 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 = | const CBlockIndex *pindex = | ||||
mapBlockIndex.find(state->hashLastUnknownBlock); | LookupBlockIndex(state->hashLastUnknownBlock); | ||||
if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) { | if (pindex && pindex->nChainWork > 0) { | ||||
if (state->pindexBestKnownBlock == nullptr || | if (state->pindexBestKnownBlock == nullptr || | ||||
itOld->second->nChainWork >= | pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) { | ||||
state->pindexBestKnownBlock->nChainWork) { | state->pindexBestKnownBlock = pindex; | ||||
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) { | 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); | const CBlockIndex *pindex = LookupBlockIndex(hash); | ||||
if (it != mapBlockIndex.end() && it->second->nChainWork > 0) { | if (pindex && pindex->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) { | pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) { | ||||
state->pindexBestKnownBlock = it->second; | state->pindexBestKnownBlock = pindex; | ||||
} | } | ||||
} 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; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 709 Lines • ▼ Show 20 Lines | switch (inv.type) { | ||||
// output 0 and 1. This works well enough in practice and we get | // output 0 and 1. This works well enough in practice and we get | ||||
// diminishing returns with 2 onward. | // diminishing returns with 2 onward. | ||||
return recentRejects->contains(inv.hash) || | return recentRejects->contains(inv.hash) || | ||||
g_mempool.exists(inv.hash) || | g_mempool.exists(inv.hash) || | ||||
pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 0)) || | pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 0)) || | ||||
pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 1)); | pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 1)); | ||||
} | } | ||||
case MSG_BLOCK: | case MSG_BLOCK: | ||||
return mapBlockIndex.count(inv.hash); | return LookupBlockIndex(inv.hash) != nullptr; | ||||
} | } | ||||
// Don't know what it is, just say we already got one | // Don't know what it is, just say we already got one | ||||
return true; | return true; | ||||
} | } | ||||
static void RelayTransaction(const CTransaction &tx, CConnman *connman) { | static void RelayTransaction(const CTransaction &tx, CConnman *connman) { | ||||
CInv inv(MSG_TX, tx.GetId()); | CInv inv(MSG_TX, tx.GetId()); | ||||
connman->ForEachNode([&inv](CNode *pnode) { pnode->PushInventory(inv); }); | connman->ForEachNode([&inv](CNode *pnode) { pnode->PushInventory(inv); }); | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block; | ||||
LOCK(cs_most_recent_block); | LOCK(cs_most_recent_block); | ||||
a_recent_block = most_recent_block; | a_recent_block = most_recent_block; | ||||
a_recent_compact_block = most_recent_compact_block; | a_recent_compact_block = most_recent_compact_block; | ||||
} | } | ||||
bool need_activate_chain = false; | bool need_activate_chain = false; | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
BlockMap::iterator mi = mapBlockIndex.find(inv.hash); | const CBlockIndex *pindex = LookupBlockIndex(inv.hash); | ||||
if (mi != mapBlockIndex.end()) { | if (pindex) { | ||||
if (mi->second->nChainTx && | if (pindex->nChainTx && !pindex->IsValid(BlockValidity::SCRIPTS) && | ||||
!mi->second->IsValid(BlockValidity::SCRIPTS) && | pindex->IsValid(BlockValidity::TREE)) { | ||||
mi->second->IsValid(BlockValidity::TREE)) { | |||||
// If we have the block and all of its parents, but have not yet | // If we have the block and all of its parents, but have not yet | ||||
// validated it, we might be in the middle of connecting it (ie | // validated it, we might be in the middle of connecting it (ie | ||||
// in the unlock of cs_main before ActivateBestChain but after | // in the unlock of cs_main before ActivateBestChain but after | ||||
// AcceptBlock). In this case, we need to run ActivateBestChain | // AcceptBlock). In this case, we need to run ActivateBestChain | ||||
// prior to checking the relay conditions below. | // prior to checking the relay conditions below. | ||||
need_activate_chain = true; | need_activate_chain = true; | ||||
} | } | ||||
} | } | ||||
} // release cs_main before calling ActivateBestChain | } // release cs_main before calling ActivateBestChain | ||||
if (need_activate_chain) { | if (need_activate_chain) { | ||||
CValidationState dummy; | CValidationState dummy; | ||||
ActivateBestChain(config, dummy, a_recent_block); | ActivateBestChain(config, dummy, a_recent_block); | ||||
} | } | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
BlockMap::iterator mi = mapBlockIndex.find(inv.hash); | const CBlockIndex *pindex = LookupBlockIndex(inv.hash); | ||||
if (mi != mapBlockIndex.end()) { | if (pindex) { | ||||
send = BlockRequestAllowed(mi->second, consensusParams); | send = BlockRequestAllowed(pindex, consensusParams); | ||||
if (!send) { | if (!send) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"%s: ignoring request from peer=%i for old " | "%s: ignoring request from peer=%i for old " | ||||
"block that isn't in the main chain\n", | "block that isn't in the main chain\n", | ||||
__func__, pfrom->GetId()); | __func__, pfrom->GetId()); | ||||
} | } | ||||
} | } | ||||
const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); | const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); | ||||
// Disconnect node in case we have reached the outbound limit for serving | // Disconnect node in case we have reached the outbound limit for serving | ||||
// historical blocks. | // historical blocks. | ||||
// Never disconnect whitelisted nodes. | // Never disconnect whitelisted nodes. | ||||
if (send && connman->OutboundTargetReached(true) && | if (send && connman->OutboundTargetReached(true) && | ||||
(((pindexBestHeader != nullptr) && | (((pindexBestHeader != nullptr) && | ||||
(pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > | (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > | ||||
HISTORICAL_BLOCK_AGE)) || | HISTORICAL_BLOCK_AGE)) || | ||||
inv.type == MSG_FILTERED_BLOCK) && | inv.type == MSG_FILTERED_BLOCK) && | ||||
!pfrom->fWhitelisted) { | !pfrom->fWhitelisted) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"historical block serving limit reached, " | "historical block serving limit reached, " | ||||
"disconnect peer=%d\n", | "disconnect peer=%d\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
// disconnect node | // disconnect node | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
send = false; | send = false; | ||||
} | } | ||||
// 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 - mi->second->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) | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
send = false; | send = false; | ||||
} | } | ||||
// Pruned nodes may have deleted the block, so check whether it's available | // Pruned nodes may have deleted the block, so check whether it's available | ||||
// before trying to send. | // before trying to send. | ||||
if (send && (mi->second->nStatus.hasData())) { | if (send && pindex->nStatus.hasData()) { | ||||
std::shared_ptr<const CBlock> pblock; | std::shared_ptr<const CBlock> pblock; | ||||
if (a_recent_block && | if (a_recent_block && | ||||
a_recent_block->GetHash() == (*mi).second->GetBlockHash()) { | a_recent_block->GetHash() == pindex->GetBlockHash()) { | ||||
pblock = a_recent_block; | pblock = a_recent_block; | ||||
} else { | } else { | ||||
// Send block from disk | // Send block from disk | ||||
std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>(); | std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>(); | ||||
if (!ReadBlockFromDisk(*pblockRead, (*mi).second, config)) | if (!ReadBlockFromDisk(*pblockRead, pindex, config)) { | ||||
assert(!"cannot load block from disk"); | assert(!"cannot load block from disk"); | ||||
} | |||||
pblock = pblockRead; | pblock = pblockRead; | ||||
} | } | ||||
if (inv.type == MSG_BLOCK) { | if (inv.type == MSG_BLOCK) { | ||||
connman->PushMessage(pfrom, | connman->PushMessage(pfrom, | ||||
msgMaker.Make(NetMsgType::BLOCK, *pblock)); | msgMaker.Make(NetMsgType::BLOCK, *pblock)); | ||||
} else if (inv.type == MSG_FILTERED_BLOCK) { | } else if (inv.type == MSG_FILTERED_BLOCK) { | ||||
bool sendMerkleBlock = false; | bool sendMerkleBlock = false; | ||||
CMerkleBlock merkleBlock; | CMerkleBlock merkleBlock; | ||||
Show All 27 Lines | if (send && pindex->nStatus.hasData()) { | ||||
// no response | // no response | ||||
} 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) && | ||||
mi->second->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, | ||||
▲ Show 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | const CBlockIndex *pindexLast = nullptr; | ||||
// If this looks like it could be a block announcement (nCount < | // If this looks like it could be a block announcement (nCount < | ||||
// MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that | // MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that | ||||
// don't connect: | // don't connect: | ||||
// - Send a getheaders message in response to try to connect the chain. | // - Send a getheaders message in response to try to connect the chain. | ||||
// - 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 (mapBlockIndex.find(headers[0].hashPrevBlock) == | if (!LookupBlockIndex(headers[0].hashPrevBlock) && | ||||
mapBlockIndex.end() && | |||||
nCount < MAX_BLOCKS_TO_ANNOUNCE) { | nCount < MAX_BLOCKS_TO_ANNOUNCE) { | ||||
nodestate->nUnconnectingHeaders++; | nodestate->nUnconnectingHeaders++; | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, msgMaker.Make(NetMsgType::GETHEADERS, | pfrom, msgMaker.Make(NetMsgType::GETHEADERS, | ||||
chainActive.GetLocator(pindexBestHeader), | chainActive.GetLocator(pindexBestHeader), | ||||
uint256())); | uint256())); | ||||
LogPrint( | LogPrint( | ||||
BCLog::NET, | BCLog::NET, | ||||
Show All 22 Lines | const CBlockIndex *pindexLast = nullptr; | ||||
Misbehaving(pfrom, 20, "disconnected-header"); | Misbehaving(pfrom, 20, "disconnected-header"); | ||||
return error("non-continuous headers sequence"); | return error("non-continuous headers sequence"); | ||||
} | } | ||||
hashLastBlock = header.GetHash(); | hashLastBlock = header.GetHash(); | ||||
} | } | ||||
// If we don't have the last header, then they'll have given us | // If we don't have the last header, then they'll have given us | ||||
// something new (if these headers are valid). | // something new (if these headers are valid). | ||||
if (mapBlockIndex.find(hashLastBlock) == mapBlockIndex.end()) { | if (!LookupBlockIndex(hashLastBlock)) { | ||||
received_new_header = true; | received_new_header = true; | ||||
} | } | ||||
} | } | ||||
CValidationState state; | CValidationState state; | ||||
CBlockHeader first_invalid_header; | CBlockHeader first_invalid_header; | ||||
if (!ProcessNewBlockHeaders(config, headers, state, &pindexLast, | if (!ProcessNewBlockHeaders(config, headers, state, &pindexLast, | ||||
&first_invalid_header)) { | &first_invalid_header)) { | ||||
int nDoS; | int nDoS; | ||||
if (state.IsInvalid(nDoS)) { | if (state.IsInvalid(nDoS)) { | ||||
if (nDoS > 0) { | if (nDoS > 0) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom, nDoS, state.GetRejectReason()); | Misbehaving(pfrom, nDoS, state.GetRejectReason()); | ||||
} | } | ||||
if (punish_duplicate_invalid && | if (punish_duplicate_invalid && | ||||
mapBlockIndex.find(first_invalid_header.GetHash()) != | LookupBlockIndex(first_invalid_header.GetHash())) { | ||||
mapBlockIndex.end()) { | |||||
// Goal: don't allow outbound peers to use up our outbound | // Goal: don't allow outbound peers to use up our outbound | ||||
// connection slots if they are on incompatible chains. | // connection slots if they are on incompatible chains. | ||||
// | // | ||||
// We ask the caller to set punish_invalid appropriately based | // We ask the caller to set punish_invalid appropriately based | ||||
// on the peer and the method of header delivery (compact blocks | // on the peer and the method of header delivery (compact blocks | ||||
// are allowed to be invalid in some circumstances, under BIP | // are allowed to be invalid in some circumstances, under BIP | ||||
// 152). | // 152). | ||||
// Here, we try to detect the narrow situation that we have a | // Here, we try to detect the narrow situation that we have a | ||||
▲ Show 20 Lines • Show All 745 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::GETBLOCKTXN) { | ||||
} | } | ||||
if (recent_block) { | if (recent_block) { | ||||
SendBlockTransactions(*recent_block, req, pfrom, connman); | SendBlockTransactions(*recent_block, req, pfrom, connman); | ||||
return true; | return true; | ||||
} | } | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
BlockMap::iterator it = mapBlockIndex.find(req.blockhash); | const CBlockIndex *pindex = LookupBlockIndex(req.blockhash); | ||||
if (it == mapBlockIndex.end() || !it->second->nStatus.hasData()) { | if (!pindex || !pindex->nStatus.hasData()) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"Peer %d sent us a getblocktxn for a block we don't have", | "Peer %d sent us a getblocktxn for a block we don't have", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
return true; | return true; | ||||
} | } | ||||
if (it->second->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, | ||||
"Peer %d sent us a getblocktxn for a block > %i deep", | "Peer %d sent us a getblocktxn for a block > %i deep", | ||||
pfrom->GetId(), MAX_BLOCKTXN_DEPTH); | pfrom->GetId(), MAX_BLOCKTXN_DEPTH); | ||||
CInv inv; | CInv inv; | ||||
inv.type = MSG_BLOCK; | inv.type = MSG_BLOCK; | ||||
inv.hash = req.blockhash; | inv.hash = req.blockhash; | ||||
pfrom->vRecvGetData.push_back(inv); | pfrom->vRecvGetData.push_back(inv); | ||||
// The message processing loop will go around again (without | // The message processing loop will go around again (without | ||||
// pausing) and we'll respond then (without cs_main) | // pausing) and we'll respond then (without cs_main) | ||||
return true; | return true; | ||||
} | } | ||||
CBlock block; | CBlock block; | ||||
bool ret = ReadBlockFromDisk(block, it->second, config); | bool ret = ReadBlockFromDisk(block, pindex, config); | ||||
assert(ret); | assert(ret); | ||||
SendBlockTransactions(block, req, pfrom, connman); | SendBlockTransactions(block, req, pfrom, connman); | ||||
} | } | ||||
else if (strCommand == NetMsgType::GETHEADERS) { | else if (strCommand == NetMsgType::GETHEADERS) { | ||||
CBlockLocator locator; | CBlockLocator locator; | ||||
uint256 hashStop; | uint256 hashStop; | ||||
vRecv >> locator >> hashStop; | vRecv >> locator >> hashStop; | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
if (IsInitialBlockDownload() && !pfrom->fWhitelisted) { | if (IsInitialBlockDownload() && !pfrom->fWhitelisted) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"Ignoring getheaders from peer=%d because node is in " | "Ignoring getheaders from peer=%d because node is in " | ||||
"initial block download\n", | "initial block download\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
return true; | return true; | ||||
} | } | ||||
CNodeState *nodestate = State(pfrom->GetId()); | CNodeState *nodestate = State(pfrom->GetId()); | ||||
const CBlockIndex *pindex = nullptr; | const CBlockIndex *pindex = nullptr; | ||||
if (locator.IsNull()) { | if (locator.IsNull()) { | ||||
// If locator is null, return the hashStop block | // If locator is null, return the hashStop block | ||||
BlockMap::iterator mi = mapBlockIndex.find(hashStop); | pindex = LookupBlockIndex(hashStop); | ||||
if (mi == mapBlockIndex.end()) { | if (!pindex) { | ||||
return true; | return true; | ||||
} | } | ||||
pindex = (*mi).second; | |||||
if (!BlockRequestAllowed(pindex, chainparams.GetConsensus())) { | if (!BlockRequestAllowed(pindex, chainparams.GetConsensus())) { | ||||
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; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 260 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) { | ||||
CBlockHeaderAndShortTxIDs cmpctblock; | CBlockHeaderAndShortTxIDs cmpctblock; | ||||
vRecv >> cmpctblock; | vRecv >> cmpctblock; | ||||
bool received_new_header = false; | bool received_new_header = false; | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
if (mapBlockIndex.find(cmpctblock.header.hashPrevBlock) == | if (!LookupBlockIndex(cmpctblock.header.hashPrevBlock)) { | ||||
mapBlockIndex.end()) { | |||||
// 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(NetMsgType::GETHEADERS, | msgMaker.Make(NetMsgType::GETHEADERS, | ||||
chainActive.GetLocator(pindexBestHeader), | chainActive.GetLocator(pindexBestHeader), | ||||
uint256())); | uint256())); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (mapBlockIndex.find(cmpctblock.header.GetHash()) == | if (!LookupBlockIndex(cmpctblock.header.GetHash())) { | ||||
mapBlockIndex.end()) { | |||||
received_new_header = true; | received_new_header = true; | ||||
} | } | ||||
} | } | ||||
const CBlockIndex *pindex = nullptr; | const CBlockIndex *pindex = nullptr; | ||||
CValidationState state; | CValidationState state; | ||||
if (!ProcessNewBlockHeaders(config, {cmpctblock.header}, state, | if (!ProcessNewBlockHeaders(config, {cmpctblock.header}, state, | ||||
&pindex)) { | &pindex)) { | ||||
▲ Show 20 Lines • Show All 1,155 Lines • ▼ Show 20 Lines | // | ||||
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 uint256 &hash : pto->vBlockHashesToAnnounce) { | for (const uint256 &hash : pto->vBlockHashesToAnnounce) { | ||||
BlockMap::iterator mi = mapBlockIndex.find(hash); | const CBlockIndex *pindex = LookupBlockIndex(hash); | ||||
assert(mi != mapBlockIndex.end()); | assert(pindex); | ||||
const CBlockIndex *pindex = mi->second; | |||||
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 | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | // | ||||
} | } | ||||
if (fRevertToInv) { | if (fRevertToInv) { | ||||
// If falling back to using an inv, just try to inv the tip. The | // If falling back to using an inv, just try to inv the tip. The | ||||
// last entry in vBlockHashesToAnnounce was our tip at some point in | // last entry in vBlockHashesToAnnounce was our tip at some point in | ||||
// the past. | // the past. | ||||
if (!pto->vBlockHashesToAnnounce.empty()) { | if (!pto->vBlockHashesToAnnounce.empty()) { | ||||
const uint256 &hashToAnnounce = | const uint256 &hashToAnnounce = | ||||
pto->vBlockHashesToAnnounce.back(); | pto->vBlockHashesToAnnounce.back(); | ||||
BlockMap::iterator mi = mapBlockIndex.find(hashToAnnounce); | const CBlockIndex *pindex = LookupBlockIndex(hashToAnnounce); | ||||
assert(mi != mapBlockIndex.end()); | assert(pindex); | ||||
const CBlockIndex *pindex = mi->second; | |||||
// 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(), | ||||
▲ Show 20 Lines • Show All 366 Lines • Show Last 20 Lines |