Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 1,274 Lines • ▼ Show 20 Lines | while (it != pfrom->vRecvGetData.end()) { | ||||
LOCK(cs_most_recent_block); | LOCK(cs_most_recent_block); | ||||
a_recent_block = 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) { | ||||
LogPrintf("%s: ignoring request from peer=%i for old " | LogPrint(BCLog::NET, | ||||
"%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()); | ||||
} | } | ||||
} | } | ||||
// Disconnect node in case we have reached the outbound limit | // Disconnect node in case we have reached the outbound limit | ||||
// for serving historical blocks. | // for serving historical blocks. | ||||
// Never disconnect whitelisted nodes. | // Never disconnect whitelisted nodes. | ||||
if (send && connman->OutboundTargetReached(true) && | if (send && connman->OutboundTargetReached(true) && | ||||
(((pindexBestHeader != nullptr) && | (((pindexBestHeader != nullptr) && | ||||
▲ Show 20 Lines • Show All 538 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::VERSION) { | ||||
strprintf("Expected to offer services %08x", | strprintf("Expected to offer services %08x", | ||||
GetDesirableServiceFlags(nServices)))); | GetDesirableServiceFlags(nServices)))); | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
return false; | return false; | ||||
} | } | ||||
if (nVersion < MIN_PEER_PROTO_VERSION) { | if (nVersion < MIN_PEER_PROTO_VERSION) { | ||||
// disconnect from peers older than this proto version | // disconnect from peers older than this proto version | ||||
LogPrintf("peer=%d using obsolete version %i; disconnecting\n", | LogPrint(BCLog::NET, | ||||
"peer=%d using obsolete version %i; disconnecting\n", | |||||
pfrom->GetId(), nVersion); | pfrom->GetId(), nVersion); | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, | pfrom, | ||||
CNetMsgMaker(INIT_PROTO_VERSION) | CNetMsgMaker(INIT_PROTO_VERSION) | ||||
.Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, | .Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, | ||||
strprintf("Version must be %d or greater", | strprintf("Version must be %d or greater", | ||||
MIN_PEER_PROTO_VERSION))); | MIN_PEER_PROTO_VERSION))); | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
return false; | return false; | ||||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::VERSION) { | ||||
connman->MarkAddressGood(pfrom->addr); | connman->MarkAddressGood(pfrom->addr); | ||||
} | } | ||||
std::string remoteAddr; | std::string remoteAddr; | ||||
if (fLogIPs) { | if (fLogIPs) { | ||||
remoteAddr = ", peeraddr=" + pfrom->addr.ToString(); | remoteAddr = ", peeraddr=" + pfrom->addr.ToString(); | ||||
} | } | ||||
LogPrintf("receive version message: [%s] %s: version %d, blocks=%d, " | LogPrint(BCLog::NET, | ||||
"receive version message: [%s] %s: version %d, blocks=%d, " | |||||
"us=%s, peer=%d%s\n", | "us=%s, peer=%d%s\n", | ||||
pfrom->addr.ToString().c_str(), cleanSubVer, pfrom->nVersion, | pfrom->addr.ToString().c_str(), cleanSubVer, pfrom->nVersion, | ||||
pfrom->nStartingHeight, addrMe.ToString(), pfrom->GetId(), | pfrom->nStartingHeight, addrMe.ToString(), pfrom->GetId(), | ||||
remoteAddr); | remoteAddr); | ||||
int64_t nTimeOffset = nTime - GetTime(); | int64_t nTimeOffset = nTime - GetTime(); | ||||
pfrom->nTimeOffset = nTimeOffset; | pfrom->nTimeOffset = nTimeOffset; | ||||
AddTimeData(pfrom->addr, nTimeOffset); | AddTimeData(pfrom->addr, nTimeOffset); | ||||
// If the peer is old enough to have the old alert system, send it the | // If the peer is old enough to have the old alert system, send it the | ||||
// final alert. | // final alert. | ||||
if (pfrom->nVersion <= 70012) { | if (pfrom->nVersion <= 70012) { | ||||
Show All 32 Lines | if (strCommand == NetMsgType::VERACK) { | ||||
pfrom->SetRecvVersion( | pfrom->SetRecvVersion( | ||||
std::min(pfrom->nVersion.load(), PROTOCOL_VERSION)); | std::min(pfrom->nVersion.load(), PROTOCOL_VERSION)); | ||||
if (!pfrom->fInbound) { | if (!pfrom->fInbound) { | ||||
// Mark this node as currently connected, so we update its timestamp | // Mark this node as currently connected, so we update its timestamp | ||||
// later. | // later. | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
State(pfrom->GetId())->fCurrentlyConnected = true; | State(pfrom->GetId())->fCurrentlyConnected = true; | ||||
LogPrintf( | |||||
"New outbound peer connected: version: %d, blocks=%d, " | |||||
"peer=%d%s\n", | |||||
pfrom->nVersion.load(), pfrom->nStartingHeight, pfrom->GetId(), | |||||
(fLogIPs ? strprintf(", peeraddr=%s", pfrom->addr.ToString()) | |||||
: "")); | |||||
} | } | ||||
if (pfrom->nVersion >= SENDHEADERS_VERSION) { | if (pfrom->nVersion >= SENDHEADERS_VERSION) { | ||||
// Tell our peer we prefer to receive headers rather than inv's | // Tell our peer we prefer to receive headers rather than inv's | ||||
// We send this to non-NODE NETWORK peers as well, because even | // We send this to non-NODE NETWORK peers as well, because even | ||||
// non-NODE NETWORK peers can announce blocks (such as pruning | // non-NODE NETWORK peers can announce blocks (such as pruning | ||||
// nodes) | // nodes) | ||||
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDHEADERS)); | connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDHEADERS)); | ||||
▲ Show 20 Lines • Show All 282 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::GETBLOCKTXN) { | ||||
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); | BlockMap::iterator it = mapBlockIndex.find(req.blockhash); | ||||
if (it == mapBlockIndex.end() || !it->second->nStatus.hasData()) { | if (it == mapBlockIndex.end() || !it->second->nStatus.hasData()) { | ||||
LogPrintf("Peer %d sent us a getblocktxn for a block we don't have", | LogPrint(BCLog::NET, | ||||
"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 (it->second->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 | ||||
Show All 38 Lines | else if (strCommand == NetMsgType::GETHEADERS) { | ||||
// If locator is null, return the hashStop block | // If locator is null, return the hashStop block | ||||
BlockMap::iterator mi = mapBlockIndex.find(hashStop); | BlockMap::iterator mi = mapBlockIndex.find(hashStop); | ||||
if (mi == mapBlockIndex.end()) { | if (mi == mapBlockIndex.end()) { | ||||
return true; | return true; | ||||
} | } | ||||
pindex = (*mi).second; | pindex = (*mi).second; | ||||
if (!BlockRequestAllowed(pindex, chainparams.GetConsensus())) { | if (!BlockRequestAllowed(pindex, chainparams.GetConsensus())) { | ||||
LogPrintf("%s: ignoring request from peer=%i for old block " | LogPrint(BCLog::NET, | ||||
"%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); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 275 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) { | ||||
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)) { | ||||
int nDoS; | int nDoS; | ||||
if (state.IsInvalid(nDoS)) { | if (state.IsInvalid(nDoS)) { | ||||
if (nDoS > 0) { | if (nDoS > 0) { | ||||
LogPrintf("Peer %d sent us invalid header via cmpctblock\n", | |||||
pfrom->GetId()); | |||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom, nDoS, state.GetRejectReason()); | Misbehaving(pfrom, nDoS, state.GetRejectReason()); | ||||
} | } else { | ||||
LogPrintf("Peer %d sent us invalid header via cmpctblock\n", | LogPrint(BCLog::NET, | ||||
"Peer %d sent us invalid header via cmpctblock\n", | |||||
pfrom->GetId()); | pfrom->GetId()); | ||||
} | |||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
// When we succeed in decoding a block's txids from a cmpctblock | // When we succeed in decoding a block's txids from a cmpctblock | ||||
// message we typically jump to the BLOCKTXN handling code, with a | // message we typically jump to the BLOCKTXN handling code, with a | ||||
// dummy (empty) BLOCKTXN message, to re-use the logic there in | // dummy (empty) BLOCKTXN message, to re-use the logic there in | ||||
// completing processing of the putative block (without cs_main). | // completing processing of the putative block (without cs_main). | ||||
▲ Show 20 Lines • Show All 658 Lines • ▼ Show 20 Lines | bool PeerLogicValidation::ProcessMessages(const Config &config, CNode *pfrom, | ||||
CNetMessage &msg(msgs.front()); | CNetMessage &msg(msgs.front()); | ||||
msg.SetVersion(pfrom->GetRecvVersion()); | msg.SetVersion(pfrom->GetRecvVersion()); | ||||
// Scan for message start | // Scan for message start | ||||
if (memcmp(std::begin(msg.hdr.pchMessageStart), | if (memcmp(std::begin(msg.hdr.pchMessageStart), | ||||
std::begin(chainparams.NetMagic()), | std::begin(chainparams.NetMagic()), | ||||
CMessageHeader::MESSAGE_START_SIZE) != 0) { | CMessageHeader::MESSAGE_START_SIZE) != 0) { | ||||
LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", | LogPrint(BCLog::NET, | ||||
"PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", | |||||
SanitizeString(msg.hdr.GetCommand()), pfrom->GetId()); | SanitizeString(msg.hdr.GetCommand()), pfrom->GetId()); | ||||
// Make sure we ban where that come from for some time. | // Make sure we ban where that come from for some time. | ||||
connman->Ban(pfrom->addr, BanReasonNodeMisbehaving); | connman->Ban(pfrom->addr, BanReasonNodeMisbehaving); | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
return false; | return false; | ||||
} | } | ||||
// Read header | // Read header | ||||
CMessageHeader &hdr = msg.hdr; | CMessageHeader &hdr = msg.hdr; | ||||
if (!hdr.IsValid(config)) { | if (!hdr.IsValid(config)) { | ||||
LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", | LogPrint(BCLog::NET, "PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", | ||||
SanitizeString(hdr.GetCommand()), pfrom->GetId()); | SanitizeString(hdr.GetCommand()), pfrom->GetId()); | ||||
return fMoreWork; | return fMoreWork; | ||||
} | } | ||||
std::string strCommand = hdr.GetCommand(); | std::string strCommand = hdr.GetCommand(); | ||||
// Message size | // Message size | ||||
unsigned int nMessageSize = hdr.nMessageSize; | unsigned int nMessageSize = hdr.nMessageSize; | ||||
// Checksum | // Checksum | ||||
CDataStream &vRecv = msg.vRecv; | CDataStream &vRecv = msg.vRecv; | ||||
const uint256 &hash = msg.GetMessageHash(); | const uint256 &hash = msg.GetMessageHash(); | ||||
if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != | if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != | ||||
0) { | 0) { | ||||
LogPrintf( | LogPrint( | ||||
"%s(%s, %u bytes): CHECKSUM ERROR expected %s was %s\n", __func__, | BCLog::NET, "%s(%s, %u bytes): CHECKSUM ERROR expected %s was %s\n", | ||||
SanitizeString(strCommand), nMessageSize, | __func__, SanitizeString(strCommand), nMessageSize, | ||||
HexStr(hash.begin(), hash.begin() + CMessageHeader::CHECKSUM_SIZE), | HexStr(hash.begin(), hash.begin() + CMessageHeader::CHECKSUM_SIZE), | ||||
HexStr(hdr.pchChecksum, | HexStr(hdr.pchChecksum, | ||||
hdr.pchChecksum + CMessageHeader::CHECKSUM_SIZE)); | hdr.pchChecksum + CMessageHeader::CHECKSUM_SIZE)); | ||||
return fMoreWork; | return fMoreWork; | ||||
} | } | ||||
// Process message | // Process message | ||||
bool fRet = false; | bool fRet = false; | ||||
try { | try { | ||||
fRet = ProcessMessage(config, pfrom, strCommand, vRecv, msg.nTime, | fRet = ProcessMessage(config, pfrom, strCommand, vRecv, msg.nTime, | ||||
connman, interruptMsgProc); | 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, CNetMsgMaker(INIT_PROTO_VERSION) | pfrom, 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( | LogPrint( | ||||
BCLog::NET, | |||||
"%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 | ||||
LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, | LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught\n", | ||||
SanitizeString(strCommand), nMessageSize, e.what()); | __func__, SanitizeString(strCommand), nMessageSize, | ||||
e.what()); | |||||
} else if (strstr(e.what(), "non-canonical ReadCompactSize()")) { | } else if (strstr(e.what(), "non-canonical ReadCompactSize()")) { | ||||
// Allow exceptions from non-canonical encoding | // Allow exceptions from non-canonical encoding | ||||
LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, | LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught\n", | ||||
SanitizeString(strCommand), nMessageSize, e.what()); | __func__, SanitizeString(strCommand), nMessageSize, | ||||
e.what()); | |||||
} else { | } else { | ||||
PrintExceptionContinue(&e, "ProcessMessages()"); | PrintExceptionContinue(&e, "ProcessMessages()"); | ||||
} | } | ||||
} catch (const std::exception &e) { | } catch (const std::exception &e) { | ||||
PrintExceptionContinue(&e, "ProcessMessages()"); | PrintExceptionContinue(&e, "ProcessMessages()"); | ||||
} catch (...) { | } catch (...) { | ||||
PrintExceptionContinue(nullptr, "ProcessMessages()"); | PrintExceptionContinue(nullptr, "ProcessMessages()"); | ||||
} | } | ||||
if (!fRet) { | if (!fRet) { | ||||
LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, | LogPrint(BCLog::NET, "%s(%s, %u bytes) FAILED peer=%d\n", __func__, | ||||
SanitizeString(strCommand), nMessageSize, pfrom->GetId()); | SanitizeString(strCommand), nMessageSize, pfrom->GetId()); | ||||
} | } | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
SendRejectsAndCheckIfBanned(pfrom, connman); | SendRejectsAndCheckIfBanned(pfrom, connman); | ||||
return fMoreWork; | return fMoreWork; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 863 Lines • Show Last 20 Lines |