Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 895 Lines • ▼ Show 20 Lines | void Misbehaving(NodeId pnode, int howmuch, const std::string &reason) | ||||
if (state == nullptr) { | if (state == nullptr) { | ||||
return; | return; | ||||
} | } | ||||
state->nMisbehavior += howmuch; | state->nMisbehavior += howmuch; | ||||
int banscore = gArgs.GetArg("-banscore", DEFAULT_BANSCORE_THRESHOLD); | int banscore = gArgs.GetArg("-banscore", DEFAULT_BANSCORE_THRESHOLD); | ||||
if (state->nMisbehavior >= banscore && | if (state->nMisbehavior >= banscore && | ||||
state->nMisbehavior - howmuch < banscore) { | state->nMisbehavior - howmuch < banscore) { | ||||
LogPrintf( | LogPrint( | ||||
BCLog::NET, | |||||
"%s: %s peer=%d (%d -> %d) reason: %s BAN THRESHOLD EXCEEDED\n", | "%s: %s peer=%d (%d -> %d) reason: %s BAN THRESHOLD EXCEEDED\n", | ||||
__func__, state->name, pnode, state->nMisbehavior - howmuch, | __func__, state->name, pnode, state->nMisbehavior - howmuch, | ||||
state->nMisbehavior, reason.c_str()); | state->nMisbehavior, reason.c_str()); | ||||
state->fShouldBan = true; | state->fShouldBan = true; | ||||
} else { | } else { | ||||
LogPrintf("%s: %s peer=%d (%d -> %d) reason: %s\n", __func__, | LogPrint(BCLog::NET, "%s: %s peer=%d (%d -> %d) reason: %s\n", __func__, | ||||
state->name, pnode, state->nMisbehavior - howmuch, | state->name, pnode, state->nMisbehavior - howmuch, | ||||
state->nMisbehavior, reason.c_str()); | state->nMisbehavior, reason.c_str()); | ||||
} | } | ||||
} | } | ||||
// overloaded variant of above to operate on CNode*s | // overloaded variant of above to operate on CNode*s | ||||
static void Misbehaving(CNode *node, int howmuch, const std::string &reason) { | static void Misbehaving(CNode *node, int howmuch, const std::string &reason) { | ||||
Misbehaving(node->GetId(), howmuch, reason); | Misbehaving(node->GetId(), howmuch, reason); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 343 Lines • ▼ Show 20 Lines | while (it != pfrom->vRecvGetData.end()) { | ||||
(pindexBestHeader->GetBlockTime() - | (pindexBestHeader->GetBlockTime() - | ||||
mi->second->GetBlockTime() < | mi->second->GetBlockTime() < | ||||
nOneMonth) && | nOneMonth) && | ||||
(GetBlockProofEquivalentTime( | (GetBlockProofEquivalentTime( | ||||
*pindexBestHeader, *mi->second, | *pindexBestHeader, *mi->second, | ||||
*pindexBestHeader, | *pindexBestHeader, | ||||
consensusParams) < nOneMonth); | consensusParams) < nOneMonth); | ||||
if (!send) { | if (!send) { | ||||
LogPrintf("%s: ignoring request from peer=%i for " | LogPrint(BCLog::NET, | ||||
"%s: ignoring request from peer=%i for " | |||||
"old block that isn't in the main " | "old block that isn't in the main " | ||||
"chain\n", | "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 never disconnect whitelisted | // for serving historical blocks never disconnect whitelisted | ||||
// nodes. | // nodes. | ||||
// assume > 1 week = historical | // assume > 1 week = historical | ||||
▲ Show 20 Lines • Show All 158 Lines • ▼ Show 20 Lines | |||||
inline static void SendBlockTransactions(const CBlock &block, | inline static void SendBlockTransactions(const CBlock &block, | ||||
const BlockTransactionsRequest &req, | const BlockTransactionsRequest &req, | ||||
CNode *pfrom, CConnman *connman) { | CNode *pfrom, CConnman *connman) { | ||||
BlockTransactions resp(req); | BlockTransactions resp(req); | ||||
for (size_t i = 0; i < req.indices.size(); i++) { | for (size_t i = 0; i < req.indices.size(); i++) { | ||||
if (req.indices[i] >= block.vtx.size()) { | if (req.indices[i] >= block.vtx.size()) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom, 100, "out-of-bound-tx-index"); | Misbehaving(pfrom, 100, "out-of-bound-tx-index"); | ||||
LogPrintf( | LogPrint( | ||||
BCLog::NET, | |||||
"Peer %d sent us a getblocktxn with out-of-bounds tx indices", | "Peer %d sent us a getblocktxn with out-of-bounds tx indices", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
return; | return; | ||||
} | } | ||||
resp.txn[i] = block.vtx[req.indices[i]]; | resp.txn[i] = block.vtx[req.indices[i]]; | ||||
} | } | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); | const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); | ||||
▲ Show 20 Lines • Show All 236 Lines • ▼ Show 20 Lines | if (!ProcessNewBlockHeaders(config, headers, state, &pindexLast, | ||||
// us sync -- disconnect if using an outbound slot (unless | // us sync -- disconnect if using an outbound slot (unless | ||||
// whitelisted or addnode). | // whitelisted or addnode). | ||||
// Note: We compare their tip to nMinimumChainWork (rather than | // Note: We compare their tip to nMinimumChainWork (rather than | ||||
// chainActive.Tip()) because we won't start block download | // chainActive.Tip()) because we won't start block download | ||||
// until we have a headers chain that has at least | // until we have a headers chain that has at least | ||||
// nMinimumChainWork, even if a peer has a chain past our tip, | // nMinimumChainWork, even if a peer has a chain past our tip, | ||||
// as an anti-DoS measure. | // as an anti-DoS measure. | ||||
if (IsOutboundDisconnectionCandidate(pfrom)) { | if (IsOutboundDisconnectionCandidate(pfrom)) { | ||||
LogPrintf("Disconnecting outbound peer %d -- headers " | LogPrint(BCLog::NET, | ||||
"Disconnecting outbound peer %d -- headers " | |||||
"chain has insufficient work\n", | "chain has insufficient work\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && | if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && | ||||
nodestate->pindexBestKnownBlock != nullptr) { | nodestate->pindexBestKnownBlock != nullptr) { | ||||
// If this is an outbound peer, check to see if we should protect it | // If this is an outbound peer, check to see if we should protect it | ||||
Show All 19 Lines | static bool ProcessMessage(const Config &config, CNode *pfrom, | ||||
const std::string &strCommand, CDataStream &vRecv, | const std::string &strCommand, CDataStream &vRecv, | ||||
int64_t nTimeReceived, CConnman *connman, | int64_t nTimeReceived, CConnman *connman, | ||||
const std::atomic<bool> &interruptMsgProc) { | const std::atomic<bool> &interruptMsgProc) { | ||||
const CChainParams &chainparams = config.GetChainParams(); | const CChainParams &chainparams = config.GetChainParams(); | ||||
LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", | LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", | ||||
SanitizeString(strCommand), vRecv.size(), pfrom->GetId()); | SanitizeString(strCommand), vRecv.size(), pfrom->GetId()); | ||||
if (gArgs.IsArgSet("-dropmessagestest") && | if (gArgs.IsArgSet("-dropmessagestest") && | ||||
GetRand(gArgs.GetArg("-dropmessagestest", 0)) == 0) { | GetRand(gArgs.GetArg("-dropmessagestest", 0)) == 0) { | ||||
LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n"); | LogPrint(BCLog::NET, "dropmessagestest DROPPING RECV MESSAGE\n"); | ||||
return true; | return true; | ||||
} | } | ||||
if (!(pfrom->GetLocalServices() & NODE_BLOOM) && | if (!(pfrom->GetLocalServices() & NODE_BLOOM) && | ||||
(strCommand == NetMsgType::FILTERLOAD || | (strCommand == NetMsgType::FILTERLOAD || | ||||
strCommand == NetMsgType::FILTERADD)) { | strCommand == NetMsgType::FILTERADD)) { | ||||
if (pfrom->nVersion >= NO_BLOOM_VERSION) { | if (pfrom->nVersion >= NO_BLOOM_VERSION) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
▲ Show 20 Lines • Show All 78 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 All 9 Lines | else if (strCommand == NetMsgType::VERSION) { | ||||
if (!vRecv.empty()) { | if (!vRecv.empty()) { | ||||
vRecv >> nStartingHeight; | vRecv >> nStartingHeight; | ||||
} | } | ||||
if (!vRecv.empty()) { | if (!vRecv.empty()) { | ||||
vRecv >> fRelay; | vRecv >> fRelay; | ||||
} | } | ||||
// Disconnect if we connected to ourself | // Disconnect if we connected to ourself | ||||
if (pfrom->fInbound && !connman->CheckIncomingNonce(nNonce)) { | if (pfrom->fInbound && !connman->CheckIncomingNonce(nNonce)) { | ||||
LogPrintf("connected to self at %s, disconnecting\n", | LogPrint(BCLog::NET, "connected to self at %s, disconnecting\n", | ||||
pfrom->addr.ToString()); | pfrom->addr.ToString()); | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
return true; | return true; | ||||
} | } | ||||
if (pfrom->fInbound && addrMe.IsRoutable()) { | if (pfrom->fInbound && addrMe.IsRoutable()) { | ||||
SeenLocal(addrMe); | SeenLocal(addrMe); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 61 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 20 Lines • Show All 330 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 20 Lines • Show All 252 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::TX) { | ||||
// due to policy, allowing the node to function as a gateway for | // due to policy, allowing the node to function as a gateway for | ||||
// nodes hidden behind it. | // nodes hidden behind it. | ||||
// | // | ||||
// Never relay transactions that we would assign a non-zero DoS | // Never relay transactions that we would assign a non-zero DoS | ||||
// score for, as we expect peers to do the same with us in that | // score for, as we expect peers to do the same with us in that | ||||
// case. | // case. | ||||
int nDoS = 0; | int nDoS = 0; | ||||
if (!state.IsInvalid(nDoS) || nDoS == 0) { | if (!state.IsInvalid(nDoS) || nDoS == 0) { | ||||
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", | LogPrint(BCLog::NET, | ||||
"Force relaying tx %s from whitelisted peer=%d\n", | |||||
tx.GetId().ToString(), pfrom->GetId()); | tx.GetId().ToString(), pfrom->GetId()); | ||||
RelayTransaction(tx, connman); | RelayTransaction(tx, connman); | ||||
} else { | } else { | ||||
LogPrintf("Not relaying invalid transaction %s from " | LogPrint(BCLog::NET, | ||||
"Not relaying invalid transaction %s from " | |||||
"whitelisted peer=%d (%s)\n", | "whitelisted peer=%d (%s)\n", | ||||
tx.GetId().ToString(), pfrom->GetId(), | tx.GetId().ToString(), pfrom->GetId(), | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
int nDoS = 0; | int nDoS = 0; | ||||
if (state.IsInvalid(nDoS)) { | if (state.IsInvalid(nDoS)) { | ||||
LogPrint(BCLog::MEMPOOLREJ, | LogPrint(BCLog::MEMPOOLREJ, | ||||
"%s from peer=%d was not accepted: %s\n", | "%s from peer=%d was not accepted: %s\n", | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) { | ||||
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) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom, nDoS, state.GetRejectReason()); | Misbehaving(pfrom, nDoS, state.GetRejectReason()); | ||||
} | } | ||||
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 89 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) { | ||||
PartiallyDownloadedBlock &partialBlock = | PartiallyDownloadedBlock &partialBlock = | ||||
*(*queuedBlockIt)->partialBlock; | *(*queuedBlockIt)->partialBlock; | ||||
ReadStatus status = | ReadStatus status = | ||||
partialBlock.InitData(cmpctblock, vExtraTxnForCompact); | partialBlock.InitData(cmpctblock, vExtraTxnForCompact); | ||||
if (status == READ_STATUS_INVALID) { | if (status == READ_STATUS_INVALID) { | ||||
// Reset in-flight state in case of whitelist | // Reset in-flight state in case of whitelist | ||||
MarkBlockAsReceived(pindex->GetBlockHash()); | MarkBlockAsReceived(pindex->GetBlockHash()); | ||||
Misbehaving(pfrom, 100, "invalid-cmpctblk"); | Misbehaving(pfrom, 100, "invalid-cmpctblk"); | ||||
LogPrintf("Peer %d sent us invalid compact block\n", | LogPrint(BCLog::NET, | ||||
"Peer %d sent us invalid compact block\n", | |||||
pfrom->GetId()); | pfrom->GetId()); | ||||
return true; | return true; | ||||
} else if (status == READ_STATUS_FAILED) { | } else if (status == READ_STATUS_FAILED) { | ||||
// Duplicate txindices, the block is now in-flight, so | // Duplicate txindices, the block is now in-flight, so | ||||
// just request it. | // just request it. | ||||
std::vector<CInv> vInv(1); | std::vector<CInv> vInv(1); | ||||
vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); | vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); | pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); | ||||
▲ Show 20 Lines • Show All 135 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::BLOCKTXN && !fImporting && | ||||
PartiallyDownloadedBlock &partialBlock = | PartiallyDownloadedBlock &partialBlock = | ||||
*it->second.second->partialBlock; | *it->second.second->partialBlock; | ||||
ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn); | ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn); | ||||
if (status == READ_STATUS_INVALID) { | if (status == READ_STATUS_INVALID) { | ||||
// Reset in-flight state in case of whitelist. | // Reset in-flight state in case of whitelist. | ||||
MarkBlockAsReceived(resp.blockhash); | MarkBlockAsReceived(resp.blockhash); | ||||
Misbehaving(pfrom, 100, "invalid-cmpctblk-txns"); | Misbehaving(pfrom, 100, "invalid-cmpctblk-txns"); | ||||
LogPrintf("Peer %d sent us invalid compact block/non-matching " | LogPrint(BCLog::NET, | ||||
"Peer %d sent us invalid compact block/non-matching " | |||||
"block transactions\n", | "block transactions\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
return true; | return true; | ||||
} else if (status == READ_STATUS_FAILED) { | } else if (status == READ_STATUS_FAILED) { | ||||
// Might have collided, fall back to getdata now :( | // Might have collided, fall back to getdata now :( | ||||
std::vector<CInv> invs; | std::vector<CInv> invs; | ||||
invs.push_back(CInv(MSG_BLOCK, resp.blockhash)); | invs.push_back(CInv(MSG_BLOCK, resp.blockhash)); | ||||
connman->PushMessage(pfrom, | connman->PushMessage(pfrom, | ||||
msgMaker.Make(NetMsgType::GETDATA, invs)); | msgMaker.Make(NetMsgType::GETDATA, invs)); | ||||
} else { | } else { | ||||
▲ Show 20 Lines • Show All 324 Lines • ▼ Show 20 Lines | for (const CBlockReject &reject : state.rejects) { | ||||
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", | LogPrint(BCLog::NET, | ||||
"Warning: not punishing whitelisted peer %s!\n", | |||||
pnode->addr.ToString()); | pnode->addr.ToString()); | ||||
} else if (pnode->m_manual_connection) { | } else if (pnode->m_manual_connection) { | ||||
LogPrintf("Warning: not punishing manually-connected peer %s!\n", | LogPrint(BCLog::NET, | ||||
"Warning: not punishing manually-connected peer %s!\n", | |||||
pnode->addr.ToString()); | pnode->addr.ToString()); | ||||
} else { | } else { | ||||
pnode->fDisconnect = true; | pnode->fDisconnect = true; | ||||
if (pnode->addr.IsLocal()) { | if (pnode->addr.IsLocal()) { | ||||
LogPrintf("Warning: not banning local peer %s!\n", | LogPrint(BCLog::NET, "Warning: not banning local peer %s!\n", | ||||
pnode->addr.ToString()); | pnode->addr.ToString()); | ||||
} else { | } else { | ||||
connman->Ban(pnode->addr, BanReasonNodeMisbehaving); | connman->Ban(pnode->addr, BanReasonNodeMisbehaving); | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 47 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; | ||||
Show All 9 Lines | bool PeerLogicValidation::ProcessMessages(const Config &config, CNode *pfrom, | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
connman->PushMessage(pfrom, | connman->PushMessage(pfrom, | ||||
CNetMsgMaker(INIT_PROTO_VERSION) | CNetMsgMaker(INIT_PROTO_VERSION) | ||||
.Make(NetMsgType::REJECT, strCommand, | .Make(NetMsgType::REJECT, strCommand, | ||||
REJECT_MALFORMED, | 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 All 35 Lines | if (!state.m_chain_sync.m_protect && | ||||
} else if (state.m_chain_sync.m_timeout > 0 && | } else if (state.m_chain_sync.m_timeout > 0 && | ||||
time_in_seconds > state.m_chain_sync.m_timeout) { | time_in_seconds > state.m_chain_sync.m_timeout) { | ||||
// No evidence yet that our peer has synced to a chain with work | // No evidence yet that our peer has synced to a chain with work | ||||
// equal to that of our tip, when we first detected it was behind. | // equal to that of our tip, when we first detected it was behind. | ||||
// Send a single getheaders message to give the peer a chance to | // Send a single getheaders message to give the peer a chance to | ||||
// update us. | // update us. | ||||
if (state.m_chain_sync.m_sent_getheaders) { | if (state.m_chain_sync.m_sent_getheaders) { | ||||
// They've run out of time to catch up! | // They've run out of time to catch up! | ||||
LogPrintf( | LogPrint( | ||||
BCLog::NET, | |||||
"Disconnecting outbound peer %d for old chain, best known " | "Disconnecting outbound peer %d for old chain, best known " | ||||
"block = %s\n", | "block = %s\n", | ||||
pto->GetId(), | pto->GetId(), | ||||
state.pindexBestKnownBlock != nullptr | state.pindexBestKnownBlock != nullptr | ||||
? state.pindexBestKnownBlock->GetBlockHash().ToString() | ? state.pindexBestKnownBlock->GetBlockHash().ToString() | ||||
: "<none>"); | : "<none>"); | ||||
pto->fDisconnect = true; | pto->fDisconnect = true; | ||||
} else { | } else { | ||||
▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | void PeerLogicValidation::CheckForStaleTipAndEvictPeers( | ||||
if (time_in_seconds <= m_stale_tip_check_time) { | if (time_in_seconds <= m_stale_tip_check_time) { | ||||
return; | return; | ||||
} | } | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
// Check whether our tip is stale, and if so, allow using an extra outbound | // Check whether our tip is stale, and if so, allow using an extra outbound | ||||
// peer. | // peer. | ||||
if (TipMayBeStale(consensusParams)) { | if (TipMayBeStale(consensusParams)) { | ||||
LogPrintf("Potential stale tip detected, will try using extra outbound " | LogPrint(BCLog::NET, | ||||
"Potential stale tip detected, will try using extra outbound " | |||||
"peer (last tip update: %d seconds ago)\n", | "peer (last tip update: %d seconds ago)\n", | ||||
time_in_seconds - g_last_tip_update); | time_in_seconds - g_last_tip_update); | ||||
connman->SetTryNewOutboundPeer(true); | connman->SetTryNewOutboundPeer(true); | ||||
} else if (connman->GetTryNewOutboundPeer()) { | } else if (connman->GetTryNewOutboundPeer()) { | ||||
connman->SetTryNewOutboundPeer(false); | connman->SetTryNewOutboundPeer(false); | ||||
} | } | ||||
m_stale_tip_check_time = time_in_seconds + STALE_CHECK_INTERVAL; | m_stale_tip_check_time = time_in_seconds + STALE_CHECK_INTERVAL; | ||||
} | } | ||||
namespace { | namespace { | ||||
▲ Show 20 Lines • Show All 479 Lines • ▼ Show 20 Lines | bool PeerLogicValidation::SendMessages(const Config &config, CNode *pto, | ||||
// Detect whether we're stalling | // Detect whether we're stalling | ||||
nNow = GetTimeMicros(); | nNow = GetTimeMicros(); | ||||
if (state.nStallingSince && | if (state.nStallingSince && | ||||
state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) { | state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) { | ||||
// Stalling only triggers when the block download window cannot move. | // Stalling only triggers when the block download window cannot move. | ||||
// During normal steady state, the download window should be much larger | // During normal steady state, the download window should be much larger | ||||
// than the to-be-downloaded set of blocks, so disconnection should only | // than the to-be-downloaded set of blocks, so disconnection should only | ||||
// happen during initial block download. | // happen during initial block download. | ||||
LogPrintf("Peer=%d is stalling block download, disconnecting\n", | LogPrint(BCLog::NET, | ||||
"Peer=%d is stalling block download, disconnecting\n", | |||||
pto->GetId()); | pto->GetId()); | ||||
pto->fDisconnect = true; | pto->fDisconnect = true; | ||||
return true; | return true; | ||||
} | } | ||||
// In case there is a block that has been in flight from this peer for 2 + | // In case there is a block that has been in flight from this peer for 2 + | ||||
// 0.5 * N times the block interval (with N the number of peers from which | // 0.5 * N times the block interval (with N the number of peers from which | ||||
// we're downloading validated blocks), disconnect due to timeout. We | // we're downloading validated blocks), disconnect due to timeout. We | ||||
// compensate for other peers to prevent killing off peers due to our own | // compensate for other peers to prevent killing off peers due to our own | ||||
// downstream link being saturated. We only count validated in-flight blocks | // downstream link being saturated. We only count validated in-flight blocks | ||||
// so peers can't advertise non-existing block hashes to unreasonably | // so peers can't advertise non-existing block hashes to unreasonably | ||||
// increase our timeout. | // increase our timeout. | ||||
if (state.vBlocksInFlight.size() > 0) { | if (state.vBlocksInFlight.size() > 0) { | ||||
QueuedBlock &queuedBlock = state.vBlocksInFlight.front(); | QueuedBlock &queuedBlock = state.vBlocksInFlight.front(); | ||||
int nOtherPeersWithValidatedDownloads = | int nOtherPeersWithValidatedDownloads = | ||||
nPeersWithValidatedDownloads - | nPeersWithValidatedDownloads - | ||||
(state.nBlocksInFlightValidHeaders > 0); | (state.nBlocksInFlightValidHeaders > 0); | ||||
if (nNow > state.nDownloadingSince + | if (nNow > state.nDownloadingSince + | ||||
consensusParams.nPowTargetSpacing * | consensusParams.nPowTargetSpacing * | ||||
(BLOCK_DOWNLOAD_TIMEOUT_BASE + | (BLOCK_DOWNLOAD_TIMEOUT_BASE + | ||||
BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * | BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * | ||||
nOtherPeersWithValidatedDownloads)) { | nOtherPeersWithValidatedDownloads)) { | ||||
LogPrintf("Timeout downloading block %s from peer=%d, " | LogPrint(BCLog::NET, "Timeout downloading block %s from peer=%d, " | ||||
"disconnecting\n", | "disconnecting\n", | ||||
queuedBlock.hash.ToString(), pto->GetId()); | queuedBlock.hash.ToString(), pto->GetId()); | ||||
pto->fDisconnect = true; | pto->fDisconnect = true; | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
// Check for headers sync timeouts | // Check for headers sync timeouts | ||||
if (state.fSyncStarted && | if (state.fSyncStarted && | ||||
state.nHeadersSyncTimeout < std::numeric_limits<int64_t>::max()) { | state.nHeadersSyncTimeout < std::numeric_limits<int64_t>::max()) { | ||||
// Detect whether this is a stalling initial-headers-sync peer | // Detect whether this is a stalling initial-headers-sync peer | ||||
if (pindexBestHeader->GetBlockTime() <= | if (pindexBestHeader->GetBlockTime() <= | ||||
GetAdjustedTime() - 24 * 60 * 60) { | GetAdjustedTime() - 24 * 60 * 60) { | ||||
if (nNow > state.nHeadersSyncTimeout && nSyncStarted == 1 && | if (nNow > state.nHeadersSyncTimeout && nSyncStarted == 1 && | ||||
(nPreferredDownload - state.fPreferredDownload >= 1)) { | (nPreferredDownload - state.fPreferredDownload >= 1)) { | ||||
// Disconnect a (non-whitelisted) peer if it is our only sync | // Disconnect a (non-whitelisted) peer if it is our only sync | ||||
// peer, and we have others we could be using instead. | // peer, and we have others we could be using instead. | ||||
// Note: If all our peers are inbound, then we won't disconnect | // Note: If all our peers are inbound, then we won't disconnect | ||||
// our sync peer for stalling; we have bigger problems if we | // our sync peer for stalling; we have bigger problems if we | ||||
// can't get any outbound peers. | // can't get any outbound peers. | ||||
if (!pto->fWhitelisted) { | if (!pto->fWhitelisted) { | ||||
LogPrintf("Timeout downloading headers from peer=%d, " | LogPrint(BCLog::NET, | ||||
"Timeout downloading headers from peer=%d, " | |||||
"disconnecting\n", | "disconnecting\n", | ||||
pto->GetId()); | pto->GetId()); | ||||
pto->fDisconnect = true; | pto->fDisconnect = true; | ||||
return true; | return true; | ||||
} else { | } else { | ||||
LogPrintf("Timeout downloading headers from whitelisted " | LogPrint(BCLog::NET, | ||||
"Timeout downloading headers from whitelisted " | |||||
"peer=%d, not disconnecting\n", | "peer=%d, not disconnecting\n", | ||||
pto->GetId()); | pto->GetId()); | ||||
// Reset the headers sync state so that we have a chance to | // Reset the headers sync state so that we have a chance to | ||||
// try downloading from a different peer. | // try downloading from a different peer. | ||||
// Note: this will also result in at least one more | // Note: this will also result in at least one more | ||||
// getheaders message to be sent to this peer (eventually). | // getheaders message to be sent to this peer (eventually). | ||||
state.fSyncStarted = false; | state.fSyncStarted = false; | ||||
nSyncStarted--; | nSyncStarted--; | ||||
state.nHeadersSyncTimeout = 0; | state.nHeadersSyncTimeout = 0; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 124 Lines • Show Last 20 Lines |