Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 1,261 Lines • ▼ Show 20 Lines | void static ProcessGetBlockData(const Config &config, CNode *pfrom, | ||||
bool need_activate_chain = false; | bool need_activate_chain = false; | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
BlockMap::iterator mi = mapBlockIndex.find(inv.hash); | BlockMap::iterator mi = mapBlockIndex.find(inv.hash); | ||||
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 | ||||
// not yet validated it, we might be in the middle of | // validated it, we might be in the middle of connecting it (ie | ||||
// connecting it (ie in the unlock of cs_main before | // in the unlock of cs_main before ActivateBestChain but after | ||||
// ActivateBestChain but after AcceptBlock). In this | // AcceptBlock). In this case, we need to run ActivateBestChain | ||||
// case, we need to run ActivateBestChain prior to | // prior to checking the relay conditions below. | ||||
// 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); | BlockMap::iterator mi = mapBlockIndex.find(inv.hash); | ||||
if (mi != mapBlockIndex.end()) { | if (mi != mapBlockIndex.end()) { | ||||
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", | ||||
__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 | // Disconnect node in case we have reached the outbound limit for serving | ||||
// 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() - mi->second->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, | ||||
Show All 14 Lines | if (send && !pfrom->fWhitelisted && | ||||
((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && | ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && | ||||
(chainActive.Tip()->nHeight - mi->second->nHeight > | (chainActive.Tip()->nHeight - mi->second->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 | // disconnect node and prevent it from stalling (would otherwise wait | ||||
// 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 | // Pruned nodes may have deleted the block, so check whether it's available | ||||
// it's available before trying to send. | // before trying to send. | ||||
if (send && (mi->second->nStatus.hasData())) { | if (send && (mi->second->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() == (*mi).second->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>(); | ||||
Show All 12 Lines | if (send && (mi->second->nStatus.hasData())) { | ||||
if (pfrom->pfilter) { | if (pfrom->pfilter) { | ||||
sendMerkleBlock = true; | sendMerkleBlock = true; | ||||
merkleBlock = CMerkleBlock(*pblock, *pfrom->pfilter); | merkleBlock = CMerkleBlock(*pblock, *pfrom->pfilter); | ||||
} | } | ||||
} | } | ||||
if (sendMerkleBlock) { | if (sendMerkleBlock) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock)); | pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock)); | ||||
// CMerkleBlock just contains hashes, so also push | // CMerkleBlock just contains hashes, so also push any | ||||
// any transactions in the block the client did not | // transactions in the block the client did not see. This avoids | ||||
// see. This avoids hurting performance by | // hurting performance by pointlessly requiring a round-trip. | ||||
// pointlessly requiring a round-trip. Note that | // Note that there is currently no way for a node to request any | ||||
// there is currently no way for a node to request | // single transactions we didn't send here - they must either | ||||
// any single transactions we didn't send here - | // disconnect and retry or request the full block. Thus, the | ||||
// they must either disconnect and retry or request | // protocol spec specified allows for us to provide duplicate | ||||
// the full block. Thus, the protocol spec specified | // txn here, however we MUST always provide at least what the | ||||
// allows for us to provide duplicate txn here, | |||||
// 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, msgMaker.Make(NetMsgType::TX, | pfrom, msgMaker.Make(NetMsgType::TX, | ||||
*pblock->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 | ||||
// guaranteed they won't have a useful mempool to match | // won't have a useful mempool to match against a compact block, and | ||||
// against a compact block, and we don't feel like | // we don't feel like constructing the object for them, so instead | ||||
// constructing the object for them, so instead we | // 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(*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 | // Trigger the peer node to send a getblocks request for the next batch | ||||
// next batch of inventory. | // 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 | ||||
// redundant, and we want it right after the last block | // want it right after the last block so they don't wait for other | ||||
// 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.SetNull(); | pfrom->hashContinue.SetNull(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
Show All 26 Lines | const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); | ||||
int nSendFlags = 0; | int nSendFlags = 0; | ||||
if (mi != mapRelay.end()) { | if (mi != mapRelay.end()) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, | pfrom, | ||||
msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second)); | msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second)); | ||||
push = true; | push = true; | ||||
} else if (pfrom->timeLastMempoolReq) { | } else if (pfrom->timeLastMempoolReq) { | ||||
auto txinfo = g_mempool.info(inv.hash); | auto txinfo = g_mempool.info(inv.hash); | ||||
// To protect privacy, do not answer getdata using the | // To protect privacy, do not answer getdata using the mempool | ||||
// mempool when that TX couldn't have been INVed in reply to | // when that TX couldn't have been INVed in reply to a MEMPOOL | ||||
// a MEMPOOL request. | // request. | ||||
if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) { | if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, | pfrom, | ||||
msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx)); | msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx)); | ||||
push = true; | push = true; | ||||
} | } | ||||
} | } | ||||
if (!push) { | if (!push) { | ||||
▲ Show 20 Lines • Show All 2,897 Lines • Show Last 20 Lines |