Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 508 Lines • ▼ Show 20 Lines | connman.ForNode(nodeid, [&connman](CNode *pfrom) { | ||||
.Make(NetMsgType::SENDCMPCT, | .Make(NetMsgType::SENDCMPCT, | ||||
fAnnounceUsingCMPCTBLOCK, | fAnnounceUsingCMPCTBLOCK, | ||||
nCMPCTBLOCKVersion)); | nCMPCTBLOCKVersion)); | ||||
return true; | return true; | ||||
}); | }); | ||||
lNodesAnnouncingHeaderAndIDs.pop_front(); | lNodesAnnouncingHeaderAndIDs.pop_front(); | ||||
} | } | ||||
fAnnounceUsingCMPCTBLOCK = true; | fAnnounceUsingCMPCTBLOCK = true; | ||||
connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()) | connman.PushMessage(pfrom, | ||||
CNetMsgMaker(pfrom->GetSendVersion()) | |||||
.Make(NetMsgType::SENDCMPCT, | .Make(NetMsgType::SENDCMPCT, | ||||
fAnnounceUsingCMPCTBLOCK, | fAnnounceUsingCMPCTBLOCK, | ||||
nCMPCTBLOCKVersion)); | nCMPCTBLOCKVersion)); | ||||
lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId()); | lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId()); | ||||
return true; | return true; | ||||
}); | }); | ||||
} | } | ||||
// Requires cs_main | // Requires cs_main | ||||
bool CanDirectFetch(const Consensus::Params &consensusParams) { | bool CanDirectFetch(const Consensus::Params &consensusParams) { | ||||
return chainActive.Tip()->GetBlockTime() > | return chainActive.Tip()->GetBlockTime() > | ||||
▲ Show 20 Lines • Show All 715 Lines • ▼ Show 20 Lines | while (it != pfrom->vRecvGetData.end()) { | ||||
if (pfrom->pfilter) { | if (pfrom->pfilter) { | ||||
sendMerkleBlock = true; | sendMerkleBlock = true; | ||||
merkleBlock = | merkleBlock = | ||||
CMerkleBlock(block, *pfrom->pfilter); | CMerkleBlock(block, *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 | ||||
Show All 17 Lines | while (it != pfrom->vRecvGetData.end()) { | ||||
// 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(block); | ||||
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, | ||||
pfrom, msgMaker.Make(nSendFlags, | msgMaker.Make(nSendFlags, | ||||
NetMsgType::BLOCK, block)); | NetMsgType::BLOCK, | ||||
block)); | |||||
} | } | ||||
} | } | ||||
// 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 All 18 Lines | while (it != pfrom->vRecvGetData.end()) { | ||||
push = true; | push = true; | ||||
} else if (pfrom->timeLastMempoolReq) { | } else if (pfrom->timeLastMempoolReq) { | ||||
auto txinfo = mempool.info(inv.hash); | auto txinfo = mempool.info(inv.hash); | ||||
// To protect privacy, do not answer getdata using the | // To protect privacy, do not answer getdata using the | ||||
// mempool when that TX couldn't have been INVed in reply to | // mempool when that TX couldn't have been INVed in reply to | ||||
// a MEMPOOL request. | // a MEMPOOL request. | ||||
if (txinfo.tx && | if (txinfo.tx && | ||||
txinfo.nTime <= pfrom->timeLastMempoolReq) { | txinfo.nTime <= pfrom->timeLastMempoolReq) { | ||||
connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, | connman.PushMessage(pfrom, | ||||
msgMaker.Make(nSendFlags, | |||||
NetMsgType::TX, | NetMsgType::TX, | ||||
*txinfo.tx)); | *txinfo.tx)); | ||||
push = true; | push = true; | ||||
} | } | ||||
} | } | ||||
if (!push) { | if (!push) { | ||||
vNotFound.push_back(inv); | vNotFound.push_back(inv); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 323 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::VERACK) { | ||||
} | } | ||||
if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION) { | if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION) { | ||||
// Tell our peer we are willing to provide version 1 or 2 | // Tell our peer we are willing to provide version 1 or 2 | ||||
// cmpctblocks. However, we do not request new block announcements | // cmpctblocks. However, we do not request new block announcements | ||||
// using cmpctblock messages. We send this to non-NODE NETWORK peers | // using cmpctblock messages. We send this to non-NODE NETWORK peers | ||||
// as well, because they may wish to request compact blocks from us. | // as well, because they may wish to request compact blocks from us. | ||||
bool fAnnounceUsingCMPCTBLOCK = false; | bool fAnnounceUsingCMPCTBLOCK = false; | ||||
uint64_t nCMPCTBLOCKVersion = 1; | uint64_t nCMPCTBLOCKVersion = 1; | ||||
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, | connman.PushMessage(pfrom, | ||||
msgMaker.Make(NetMsgType::SENDCMPCT, | |||||
fAnnounceUsingCMPCTBLOCK, | fAnnounceUsingCMPCTBLOCK, | ||||
nCMPCTBLOCKVersion)); | nCMPCTBLOCKVersion)); | ||||
} | } | ||||
pfrom->fSuccessfullyConnected = true; | pfrom->fSuccessfullyConnected = true; | ||||
} | } | ||||
else if (!pfrom->fSuccessfullyConnected) { | else if (!pfrom->fSuccessfullyConnected) { | ||||
// Must have a verack message before anything else | // Must have a verack message before anything else | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom, 1, "missing-verack"); | Misbehaving(pfrom, 1, "missing-verack"); | ||||
▲ Show 20 Lines • Show All 567 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::TX) { | ||||
int nDoS = 0; | int nDoS = 0; | ||||
if (state.IsInvalid(nDoS)) { | if (state.IsInvalid(nDoS)) { | ||||
LogPrint( | LogPrint( | ||||
BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", | BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", | ||||
tx.GetId().ToString(), pfrom->id, FormatStateMessage(state)); | tx.GetId().ToString(), pfrom->id, FormatStateMessage(state)); | ||||
// Never send AcceptToMemoryPool's internal codes over P2P. | // Never send AcceptToMemoryPool's internal codes over P2P. | ||||
if (state.GetRejectCode() < REJECT_INTERNAL) { | if (state.GetRejectCode() < REJECT_INTERNAL) { | ||||
connman.PushMessage( | connman.PushMessage( | ||||
pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, | pfrom, | ||||
msgMaker.Make(NetMsgType::REJECT, strCommand, | |||||
uint8_t(state.GetRejectCode()), | uint8_t(state.GetRejectCode()), | ||||
state.GetRejectReason().substr( | state.GetRejectReason().substr( | ||||
0, MAX_REJECT_MESSAGE_LENGTH), | 0, MAX_REJECT_MESSAGE_LENGTH), | ||||
inv.hash)); | inv.hash)); | ||||
} | } | ||||
if (nDoS > 0) { | if (nDoS > 0) { | ||||
Misbehaving(pfrom, nDoS, state.GetRejectReason()); | Misbehaving(pfrom, nDoS, state.GetRejectReason()); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Ignore blocks received while importing | // Ignore blocks received while importing | ||||
▲ Show 20 Lines • Show All 258 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::BLOCKTXN && !fImporting && | ||||
vRecv >> resp; | vRecv >> resp; | ||||
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(); | std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(); | ||||
bool fBlockRead = false; | bool fBlockRead = false; | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
std::map<uint256, | std::map<uint256, | ||||
std::pair<NodeId, | std::pair<NodeId, std::list<QueuedBlock>::iterator>>:: | ||||
std::list<QueuedBlock>::iterator>>::iterator it = | iterator it = mapBlocksInFlight.find(resp.blockhash); | ||||
mapBlocksInFlight.find(resp.blockhash); | |||||
if (it == mapBlocksInFlight.end() || | if (it == mapBlocksInFlight.end() || | ||||
!it->second.second->partialBlock || | !it->second.second->partialBlock || | ||||
it->second.first != pfrom->GetId()) { | it->second.first != pfrom->GetId()) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"Peer %d sent us block transactions for block " | "Peer %d sent us block transactions for block " | ||||
"we weren't expecting\n", | "we weren't expecting\n", | ||||
pfrom->id); | pfrom->id); | ||||
return true; | return true; | ||||
▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) { | ||||
// 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 | // - Once a headers message is received that is valid and does | ||||
// connect, | // connect, | ||||
// nUnconnectingHeaders gets reset back to 0. | // nUnconnectingHeaders gets reset back to 0. | ||||
if (mapBlockIndex.find(headers[0].hashPrevBlock) == | if (mapBlockIndex.find(headers[0].hashPrevBlock) == | ||||
mapBlockIndex.end() && | mapBlockIndex.end() && | ||||
nCount < MAX_BLOCKS_TO_ANNOUNCE) { | nCount < MAX_BLOCKS_TO_ANNOUNCE) { | ||||
nodestate->nUnconnectingHeaders++; | nodestate->nUnconnectingHeaders++; | ||||
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, | connman.PushMessage( | ||||
chainActive.GetLocator( | pfrom, | ||||
pindexBestHeader), | msgMaker.Make(NetMsgType::GETHEADERS, | ||||
chainActive.GetLocator(pindexBestHeader), | |||||
uint256())); | uint256())); | ||||
LogPrint(BCLog::NET, "received header %s: missing prev block " | LogPrint(BCLog::NET, "received header %s: missing prev block " | ||||
"%s, sending getheaders (%d) to end " | "%s, sending getheaders (%d) to end " | ||||
"(peer=%d, nUnconnectingHeaders=%d)\n", | "(peer=%d, nUnconnectingHeaders=%d)\n", | ||||
headers[0].GetHash().ToString(), | headers[0].GetHash().ToString(), | ||||
headers[0].hashPrevBlock.ToString(), | headers[0].hashPrevBlock.ToString(), | ||||
pindexBestHeader->nHeight, pfrom->id, | pindexBestHeader->nHeight, pfrom->id, | ||||
nodestate->nUnconnectingHeaders); | nodestate->nUnconnectingHeaders); | ||||
// Set hashLastUnknownBlock for this peer, so that if we | // Set hashLastUnknownBlock for this peer, so that if we | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) { | ||||
// TODO: optimize: if pindexLast is an ancestor of | // TODO: optimize: if pindexLast is an ancestor of | ||||
// chainActive.Tip or pindexBestHeader, continue from there | // chainActive.Tip or pindexBestHeader, continue from there | ||||
// instead. | // 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->id, pfrom->nStartingHeight); | pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight); | ||||
connman.PushMessage( | connman.PushMessage( | ||||
pfrom, msgMaker.Make(NetMsgType::GETHEADERS, | pfrom, | ||||
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 | // 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. | // as much work as our tip, download as much as possible. | ||||
if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && | if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && | ||||
chainActive.Tip()->nChainWork <= pindexLast->nChainWork) { | chainActive.Tip()->nChainWork <= pindexLast->nChainWork) { | ||||
std::vector<const CBlockIndex *> vToFetch; | std::vector<const CBlockIndex *> vToFetch; | ||||
▲ Show 20 Lines • Show All 308 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static bool SendRejectsAndCheckIfBanned(CNode *pnode, CConnman &connman) { | static bool SendRejectsAndCheckIfBanned(CNode *pnode, CConnman &connman) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
CNodeState &state = *State(pnode->GetId()); | CNodeState &state = *State(pnode->GetId()); | ||||
for (const CBlockReject &reject : state.rejects) { | for (const CBlockReject &reject : state.rejects) { | ||||
connman.PushMessage( | connman.PushMessage( | ||||
pnode, CNetMsgMaker(INIT_PROTO_VERSION) | pnode, | ||||
CNetMsgMaker(INIT_PROTO_VERSION) | |||||
.Make(NetMsgType::REJECT, (std::string)NetMsgType::BLOCK, | .Make(NetMsgType::REJECT, (std::string)NetMsgType::BLOCK, | ||||
reject.chRejectCode, reject.strRejectReason, | reject.chRejectCode, reject.strRejectReason, | ||||
reject.hashBlock)); | reject.hashBlock)); | ||||
} | } | ||||
state.rejects.clear(); | state.rejects.clear(); | ||||
if (state.fShouldBan) { | if (state.fShouldBan) { | ||||
state.fShouldBan = false; | state.fShouldBan = false; | ||||
if (pnode->fWhitelisted) { | if (pnode->fWhitelisted) { | ||||
LogPrintf("Warning: not punishing whitelisted peer %s!\n", | LogPrintf("Warning: not punishing whitelisted peer %s!\n", | ||||
pnode->addr.ToString()); | pnode->addr.ToString()); | ||||
▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | try { | ||||
chainparams, connman, interruptMsgProc); | chainparams, connman, interruptMsgProc); | ||||
if (interruptMsgProc) { | if (interruptMsgProc) { | ||||
return false; | return false; | ||||
} | } | ||||
if (!pfrom->vRecvGetData.empty()) { | if (!pfrom->vRecvGetData.empty()) { | ||||
fMoreWork = true; | fMoreWork = true; | ||||
} | } | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
connman.PushMessage( | connman.PushMessage(pfrom, | ||||
pfrom, CNetMsgMaker(INIT_PROTO_VERSION) | CNetMsgMaker(INIT_PROTO_VERSION) | ||||
.Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, | .Make(NetMsgType::REJECT, strCommand, | ||||
REJECT_MALFORMED, | |||||
std::string("error parsing message"))); | std::string("error parsing message"))); | ||||
if (strstr(e.what(), "end of data")) { | if (strstr(e.what(), "end of data")) { | ||||
// Allow exceptions from under-length message on vRecv | // Allow exceptions from under-length message on vRecv | ||||
LogPrintf( | LogPrintf( | ||||
"%s(%s, %u bytes): Exception '%s' caught, normally caused by a " | "%s(%s, %u bytes): Exception '%s' caught, normally caused by a " | ||||
"message being shorter than its stated length\n", | "message being shorter than its stated length\n", | ||||
__func__, SanitizeString(strCommand), nMessageSize, e.what()); | __func__, SanitizeString(strCommand), nMessageSize, e.what()); | ||||
} else if (strstr(e.what(), "size too large")) { | } else if (strstr(e.what(), "size too large")) { | ||||
// Allow exceptions from over-long size | // Allow exceptions from over-long size | ||||
▲ Show 20 Lines • Show All 273 Lines • ▼ Show 20 Lines | // | ||||
fGotBlockFromCache = true; | fGotBlockFromCache = true; | ||||
} | } | ||||
} | } | ||||
if (!fGotBlockFromCache) { | if (!fGotBlockFromCache) { | ||||
CBlock block; | CBlock block; | ||||
bool ret = ReadBlockFromDisk(block, pBestIndex, config); | bool ret = ReadBlockFromDisk(block, pBestIndex, config); | ||||
assert(ret); | assert(ret); | ||||
CBlockHeaderAndShortTxIDs cmpctblock(block); | CBlockHeaderAndShortTxIDs cmpctblock(block); | ||||
connman.PushMessage( | connman.PushMessage(pto, | ||||
pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, | msgMaker.Make(nSendFlags, | ||||
NetMsgType::CMPCTBLOCK, | |||||
cmpctblock)); | cmpctblock)); | ||||
} | } | ||||
state.pindexBestHeaderSent = pBestIndex; | state.pindexBestHeaderSent = pBestIndex; | ||||
} else if (state.fPreferHeaders) { | } else if (state.fPreferHeaders) { | ||||
if (vHeaders.size() > 1) { | if (vHeaders.size() > 1) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"%s: %u headers, range (%s, %s), to peer=%d\n", | "%s: %u headers, range (%s, %s), to peer=%d\n", | ||||
__func__, vHeaders.size(), | __func__, vHeaders.size(), | ||||
vHeaders.front().GetHash().ToString(), | vHeaders.front().GetHash().ToString(), | ||||
▲ Show 20 Lines • Show All 241 Lines • ▼ Show 20 Lines | bool SendMessages(const Config &config, CNode *pto, CConnman &connman, | ||||
// | // | ||||
// Message: getdata (blocks) | // Message: getdata (blocks) | ||||
// | // | ||||
std::vector<CInv> vGetData; | std::vector<CInv> vGetData; | ||||
if (!pto->fClient && (fFetch || !IsInitialBlockDownload()) && | if (!pto->fClient && (fFetch || !IsInitialBlockDownload()) && | ||||
state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { | state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { | ||||
std::vector<const CBlockIndex *> vToDownload; | std::vector<const CBlockIndex *> vToDownload; | ||||
NodeId staller = -1; | NodeId staller = -1; | ||||
FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - | FindNextBlocksToDownload(pto->GetId(), | ||||
MAX_BLOCKS_IN_TRANSIT_PER_PEER - | |||||
state.nBlocksInFlight, | state.nBlocksInFlight, | ||||
vToDownload, staller, consensusParams); | vToDownload, staller, consensusParams); | ||||
for (const CBlockIndex *pindex : vToDownload) { | for (const CBlockIndex *pindex : vToDownload) { | ||||
uint32_t nFetchFlags = | uint32_t nFetchFlags = | ||||
GetFetchFlags(pto, pindex->pprev, consensusParams); | GetFetchFlags(pto, pindex->pprev, consensusParams); | ||||
vGetData.push_back( | vGetData.push_back( | ||||
CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash())); | CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash())); | ||||
MarkBlockAsInFlight(config, pto->GetId(), pindex->GetBlockHash(), | MarkBlockAsInFlight(config, pto->GetId(), pindex->GetBlockHash(), | ||||
consensusParams, pindex); | consensusParams, pindex); | ||||
▲ Show 20 Lines • Show All 94 Lines • Show Last 20 Lines |