Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 1,010 Lines • ▼ Show 20 Lines | if (vOrphanErase.size()) { | ||||
LogPrint(BCLog::MEMPOOL, | LogPrint(BCLog::MEMPOOL, | ||||
"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(); | ||||
} | } | ||||
// All of the following cache a recent block, and are protected by | |||||
// cs_most_recent_block | |||||
static CCriticalSection cs_most_recent_block; | static CCriticalSection cs_most_recent_block; | ||||
static std::shared_ptr<const CBlock> | static std::shared_ptr<const CBlock> | ||||
most_recent_block GUARDED_BY(cs_most_recent_block); | 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 GUARDED_BY(cs_most_recent_block); | most_recent_compact_block GUARDED_BY(cs_most_recent_block); | ||||
static uint256 most_recent_block_hash GUARDED_BY(cs_most_recent_block); | static uint256 most_recent_block_hash GUARDED_BY(cs_most_recent_block); | ||||
void PeerLogicValidation::NewPoWValidBlock( | void PeerLogicValidation::NewPoWValidBlock( | ||||
▲ Show 20 Lines • Show All 238 Lines • ▼ Show 20 Lines | while (it != pfrom->vRecvGetData.end()) { | ||||
} | } | ||||
it++; | it++; | ||||
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || | if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || | ||||
inv.type == MSG_CMPCT_BLOCK) { | inv.type == MSG_CMPCT_BLOCK) { | ||||
bool send = false; | bool send = false; | ||||
BlockMap::iterator mi = mapBlockIndex.find(inv.hash); | BlockMap::iterator mi = mapBlockIndex.find(inv.hash); | ||||
std::shared_ptr<const CBlock> a_recent_block; | |||||
std::shared_ptr<const CBlockHeaderAndShortTxIDs> | |||||
a_recent_compact_block; | |||||
{ | |||||
LOCK(cs_most_recent_block); | |||||
a_recent_block = most_recent_block; | |||||
a_recent_compact_block = most_recent_compact_block; | |||||
} | |||||
if (mi != mapBlockIndex.end()) { | if (mi != mapBlockIndex.end()) { | ||||
if (mi->second->nChainTx && | if (mi->second->nChainTx && | ||||
!mi->second->IsValid(BlockValidity::SCRIPTS) && | !mi->second->IsValid(BlockValidity::SCRIPTS) && | ||||
mi->second->IsValid(BlockValidity::TREE)) { | mi->second->IsValid(BlockValidity::TREE)) { | ||||
// If we have the block and all of its parents, but have | // If we have the block and all of its parents, but have | ||||
// not yet validated it, we might be in the middle of | // not yet validated it, we might be in the middle of | ||||
// connecting it (ie in the unlock of cs_main before | // connecting it (ie in the unlock of cs_main before | ||||
// ActivateBestChain but after AcceptBlock). In this | // ActivateBestChain but after AcceptBlock). In this | ||||
// case, we need to run ActivateBestChain prior to | // case, we need to run ActivateBestChain prior to | ||||
// checking the relay conditions below. | // checking the relay conditions below. | ||||
std::shared_ptr<const CBlock> a_recent_block; | |||||
{ | |||||
LOCK(cs_most_recent_block); | |||||
a_recent_block = most_recent_block; | |||||
} | |||||
CValidationState dummy; | CValidationState dummy; | ||||
ActivateBestChain(config, dummy, a_recent_block); | ActivateBestChain(config, dummy, a_recent_block); | ||||
} | } | ||||
send = BlockRequestAllowed(mi->second, consensusParams); | send = BlockRequestAllowed(mi->second, 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", | ||||
Show All 38 Lines | while (it != pfrom->vRecvGetData.end()) { | ||||
// disconnect node and prevent it from stalling (would | // disconnect node and prevent it from stalling (would | ||||
// otherwise wait for the missing block) | // otherwise wait for the missing block) | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
send = false; | send = false; | ||||
} | } | ||||
// Pruned nodes may have deleted the block, so check whether | // Pruned nodes may have deleted the block, so check whether | ||||
// it's available before trying to send. | // it's available before trying to send. | ||||
if (send && (mi->second->nStatus.hasData())) { | if (send && (mi->second->nStatus.hasData())) { | ||||
std::shared_ptr<const CBlock> pblock; | |||||
if (a_recent_block && a_recent_block->GetHash() == | |||||
(*mi).second->GetBlockHash()) { | |||||
pblock = a_recent_block; | |||||
} else { | |||||
// Send block from disk | // Send block from disk | ||||
CBlock block; | std::shared_ptr<CBlock> pblockRead = | ||||
if (!ReadBlockFromDisk(block, (*mi).second, config)) { | std::make_shared<CBlock>(); | ||||
if (!ReadBlockFromDisk(*pblockRead, (*mi).second, | |||||
config)) | |||||
assert(!"cannot load block from disk"); | assert(!"cannot load block from disk"); | ||||
pblock = pblockRead; | |||||
} | } | ||||
if (inv.type == MSG_BLOCK) { | if (inv.type == MSG_BLOCK) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, msgMaker.Make(NetMsgType::BLOCK, block)); | pfrom, 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; | ||||
{ | { | ||||
LOCK(pfrom->cs_filter); | LOCK(pfrom->cs_filter); | ||||
if (pfrom->pfilter) { | if (pfrom->pfilter) { | ||||
sendMerkleBlock = true; | sendMerkleBlock = true; | ||||
merkleBlock = | merkleBlock = | ||||
CMerkleBlock(block, *pfrom->pfilter); | CMerkleBlock(*pblock, *pfrom->pfilter); | ||||
} | } | ||||
} | } | ||||
if (sendMerkleBlock) { | if (sendMerkleBlock) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, | pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, | ||||
merkleBlock)); | merkleBlock)); | ||||
// CMerkleBlock just contains hashes, so also push | // CMerkleBlock just contains hashes, so also push | ||||
// any transactions in the block the client did not | // any transactions in the block the client did not | ||||
// see. This avoids hurting performance by | // see. This avoids hurting performance by | ||||
// pointlessly requiring a round-trip. Note that | // pointlessly requiring a round-trip. Note that | ||||
// there is currently no way for a node to request | // there is currently no way for a node to request | ||||
// any single transactions we didn't send here - | // any single transactions we didn't send here - | ||||
// they must either disconnect and retry or request | // they must either disconnect and retry or request | ||||
// the full block. Thus, the protocol spec specified | // the full block. Thus, the protocol spec specified | ||||
// allows for us to provide duplicate txn here, | // allows for us to provide duplicate txn here, | ||||
// however we MUST always provide at least what the | // however we MUST always provide at least what the | ||||
// remote peer needs. | // remote peer needs. | ||||
typedef std::pair<unsigned int, uint256> PairType; | typedef std::pair<unsigned int, uint256> PairType; | ||||
for (PairType &pair : merkleBlock.vMatchedTxn) { | for (PairType &pair : merkleBlock.vMatchedTxn) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, | pfrom, | ||||
msgMaker.Make(NetMsgType::TX, | msgMaker.Make(NetMsgType::TX, | ||||
*block.vtx[pair.first])); | *pblock->vtx[pair.first])); | ||||
} | } | ||||
} | } | ||||
// else | // else | ||||
// 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 | // If a peer is asking for old blocks, we're almost | ||||
// guaranteed they won't have a useful mempool to match | // guaranteed they won't have a useful mempool to match | ||||
// against a compact block, and we don't feel like | // against a compact block, and we don't feel like | ||||
// constructing the object for them, so instead we | // constructing the object for them, so instead we | ||||
// respond with the full, non-compact block. | // respond with the full, non-compact block. | ||||
int nSendFlags = 0; | int nSendFlags = 0; | ||||
if (CanDirectFetch(consensusParams) && | if (CanDirectFetch(consensusParams) && | ||||
mi->second->nHeight >= | mi->second->nHeight >= | ||||
chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) { | chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) { | ||||
CBlockHeaderAndShortTxIDs cmpctblock(block); | CBlockHeaderAndShortTxIDs cmpctblock(*pblock); | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, msgMaker.Make(nSendFlags, | pfrom, msgMaker.Make(nSendFlags, | ||||
NetMsgType::CMPCTBLOCK, | NetMsgType::CMPCTBLOCK, | ||||
cmpctblock)); | cmpctblock)); | ||||
} else { | } else { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, msgMaker.Make(nSendFlags, | pfrom, | ||||
NetMsgType::BLOCK, block)); | msgMaker.Make(nSendFlags, NetMsgType::BLOCK, | ||||
*pblock)); | |||||
} | } | ||||
} | } | ||||
// Trigger the peer node to send a getblocks request for the | // Trigger the peer node to send a getblocks request for the | ||||
// next batch of inventory. | // next batch of inventory. | ||||
if (inv.hash == pfrom->hashContinue) { | if (inv.hash == pfrom->hashContinue) { | ||||
// Bypass PushInventory, this must send even if | // Bypass PushInventory, this must send even if | ||||
// redundant, and we want it right after the last block | // redundant, and we want it right after the last block | ||||
▲ Show 20 Lines • Show All 2,926 Lines • Show Last 20 Lines |