Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 771 Lines • ▼ Show 20 Lines | while (mapOrphanTransactions.size() > nMaxOrphans) { | ||||
it = mapOrphanTransactions.begin(); | it = mapOrphanTransactions.begin(); | ||||
EraseOrphanTx(it->first); | EraseOrphanTx(it->first); | ||||
++nEvicted; | ++nEvicted; | ||||
} | } | ||||
return nEvicted; | return nEvicted; | ||||
} | } | ||||
// Requires cs_main. | // Requires cs_main. | ||||
void Misbehaving(NodeId pnode, int howmuch) { | void Misbehaving(NodeId pnode, int howmuch, const std::string &reason) { | ||||
if (howmuch == 0) return; | if (howmuch == 0) { | ||||
return; | |||||
} | |||||
CNodeState *state = State(pnode); | CNodeState *state = State(pnode); | ||||
if (state == nullptr) return; | if (state == nullptr) { | ||||
return; | |||||
} | |||||
state->nMisbehavior += howmuch; | state->nMisbehavior += howmuch; | ||||
int banscore = GetArg("-banscore", DEFAULT_BANSCORE_THRESHOLD); | int banscore = GetArg("-banscore", DEFAULT_BANSCORE_THRESHOLD); | ||||
if (state->nMisbehavior >= banscore && | if (state->nMisbehavior >= banscore && | ||||
state->nMisbehavior - howmuch < banscore) { | state->nMisbehavior - howmuch < banscore) { | ||||
LogPrintf("%s: %s peer=%d (%d -> %d) BAN THRESHOLD EXCEEDED\n", | LogPrintf( | ||||
"%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); | state->nMisbehavior, reason.c_str()); | ||||
state->fShouldBan = true; | state->fShouldBan = true; | ||||
} else | } else { | ||||
LogPrintf("%s: %s peer=%d (%d -> %d)\n", __func__, state->name, pnode, | LogPrintf("%s: %s peer=%d (%d -> %d) reason: %s\n", __func__, | ||||
state->nMisbehavior - howmuch, state->nMisbehavior); | state->name, pnode, state->nMisbehavior - howmuch, | ||||
state->nMisbehavior, reason.c_str()); | |||||
} | |||||
} | } | ||||
////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////// | ||||
// | // | ||||
// blockchain -> download logic notification | // blockchain -> download logic notification | ||||
// | // | ||||
PeerLogicValidation::PeerLogicValidation(CConnman *connmanIn) | PeerLogicValidation::PeerLogicValidation(CConnman *connmanIn) | ||||
▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | if (state.IsInvalid(nDoS)) { | ||||
if (it != mapBlockSource.end() && State(it->second.first)) { | if (it != mapBlockSource.end() && State(it->second.first)) { | ||||
// Blocks are never rejected with internal reject codes. | // Blocks are never rejected with internal reject codes. | ||||
assert(state.GetRejectCode() < REJECT_INTERNAL); | assert(state.GetRejectCode() < REJECT_INTERNAL); | ||||
CBlockReject reject = { | CBlockReject reject = { | ||||
(unsigned char)state.GetRejectCode(), | (unsigned char)state.GetRejectCode(), | ||||
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), | state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), | ||||
hash}; | hash}; | ||||
State(it->second.first)->rejects.push_back(reject); | State(it->second.first)->rejects.push_back(reject); | ||||
if (nDoS > 0 && it->second.second) | if (nDoS > 0 && it->second.second) { | ||||
Misbehaving(it->second.first, nDoS); | Misbehaving(it->second.first, nDoS, state.GetRejectReason()); | ||||
} | |||||
} | } | ||||
} | } | ||||
// Check that: | // Check that: | ||||
// 1. The block is valid | // 1. The block is valid | ||||
// 2. We're not in initial block download | // 2. We're not in initial block download | ||||
// 3. This is currently the best block we're aware of. We haven't updated | // 3. This is currently the best block we're aware of. We haven't updated | ||||
// the tip yet so we have no way to check this directly here. Instead we | // the tip yet so we have no way to check this directly here. Instead we | ||||
// just check that there are currently no other blocks in flight. | // just check that there are currently no other blocks in flight. | ||||
▲ Show 20 Lines • Show All 321 Lines • ▼ Show 20 Lines | |||||
inline void static SendBlockTransactions(const CBlock &block, | inline void static 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.indexes.size(); i++) { | for (size_t i = 0; i < req.indexes.size(); i++) { | ||||
if (req.indexes[i] >= block.vtx.size()) { | if (req.indexes[i] >= block.vtx.size()) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom->GetId(), 100); | Misbehaving(pfrom->GetId(), 100, "out-of-bound-tx-index"); | ||||
LogPrintf( | LogPrintf( | ||||
"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->id); | pfrom->id); | ||||
return; | return; | ||||
} | } | ||||
resp.txn[i] = block.vtx[req.indexes[i]]; | resp.txn[i] = block.vtx[req.indexes[i]]; | ||||
} | } | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Show All 16 Lines | if (IsArgSet("-dropmessagestest") && | ||||
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); | ||||
Misbehaving(pfrom->GetId(), 100); | Misbehaving(pfrom->GetId(), 100, "no-bloom-version"); | ||||
return false; | return false; | ||||
} else { | } else { | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
if (strCommand == NetMsgType::REJECT) { | if (strCommand == NetMsgType::REJECT) { | ||||
Show All 27 Lines | else if (strCommand == NetMsgType::VERSION) { | ||||
// Each connection can only send one version message | // Each connection can only send one version message | ||||
if (pfrom->nVersion != 0) { | if (pfrom->nVersion != 0) { | ||||
connman.PushMessage( | connman.PushMessage( | ||||
pfrom, | pfrom, | ||||
CNetMsgMaker(INIT_PROTO_VERSION) | CNetMsgMaker(INIT_PROTO_VERSION) | ||||
.Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, | .Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, | ||||
std::string("Duplicate version message"))); | std::string("Duplicate version message"))); | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom->GetId(), 1); | Misbehaving(pfrom->GetId(), 1, "multiple-version"); | ||||
return false; | return false; | ||||
} | } | ||||
int64_t nTime; | int64_t nTime; | ||||
CAddress addrMe; | CAddress addrMe; | ||||
CAddress addrFrom; | CAddress addrFrom; | ||||
uint64_t nNonce = 1; | uint64_t nNonce = 1; | ||||
uint64_t nServiceInt; | uint64_t nServiceInt; | ||||
▲ Show 20 Lines • Show All 155 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::VERSION) { | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
else if (pfrom->nVersion == 0) { | else if (pfrom->nVersion == 0) { | ||||
// Must have a version message before anything else | // Must have a version message before anything else | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom->GetId(), 1); | Misbehaving(pfrom->GetId(), 1, "missing-version"); | ||||
return false; | return false; | ||||
} | } | ||||
// At this point, the outgoing message serialization version can't change. | // At this point, the outgoing message serialization version can't change. | ||||
const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); | const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); | ||||
if (strCommand == NetMsgType::VERACK) { | if (strCommand == NetMsgType::VERACK) { | ||||
pfrom->SetRecvVersion( | pfrom->SetRecvVersion( | ||||
Show All 25 Lines | if (strCommand == NetMsgType::VERACK) { | ||||
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->GetId(), 1); | Misbehaving(pfrom->GetId(), 1, "missing-verack"); | ||||
return false; | return false; | ||||
} | } | ||||
else if (strCommand == NetMsgType::ADDR) { | else if (strCommand == NetMsgType::ADDR) { | ||||
std::vector<CAddress> vAddr; | std::vector<CAddress> vAddr; | ||||
vRecv >> vAddr; | vRecv >> vAddr; | ||||
// Don't want addr from older versions unless seeding | // Don't want addr from older versions unless seeding | ||||
if (pfrom->nVersion < CADDR_TIME_VERSION && | if (pfrom->nVersion < CADDR_TIME_VERSION && | ||||
connman.GetAddressCount() > 1000) | connman.GetAddressCount() > 1000) { | ||||
return true; | return true; | ||||
} | |||||
if (vAddr.size() > 1000) { | if (vAddr.size() > 1000) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom->GetId(), 20); | Misbehaving(pfrom->GetId(), 20, "oversized-addr"); | ||||
return error("message addr size() = %u", vAddr.size()); | return error("message addr size() = %u", vAddr.size()); | ||||
} | } | ||||
// Store the new addresses | // Store the new addresses | ||||
std::vector<CAddress> vAddrOk; | std::vector<CAddress> vAddrOk; | ||||
int64_t nNow = GetAdjustedTime(); | int64_t nNow = GetAdjustedTime(); | ||||
int64_t nSince = nNow - 10 * 60; | int64_t nSince = nNow - 10 * 60; | ||||
for (CAddress &addr : vAddr) { | for (CAddress &addr : vAddr) { | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::SENDCMPCT) { | ||||
} | } | ||||
} | } | ||||
else if (strCommand == NetMsgType::INV) { | else if (strCommand == NetMsgType::INV) { | ||||
std::vector<CInv> vInv; | std::vector<CInv> vInv; | ||||
vRecv >> vInv; | vRecv >> vInv; | ||||
if (vInv.size() > MAX_INV_SZ) { | if (vInv.size() > MAX_INV_SZ) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom->GetId(), 20); | Misbehaving(pfrom->GetId(), 20, "oversized-inv"); | ||||
return error("message inv size() = %u", vInv.size()); | return error("message inv size() = %u", vInv.size()); | ||||
} | } | ||||
bool fBlocksOnly = !fRelayTxes; | bool fBlocksOnly = !fRelayTxes; | ||||
// Allow whitelisted peers to send data other than blocks in blocks only | // Allow whitelisted peers to send data other than blocks in blocks only | ||||
// mode if whitelistrelay is true | // mode if whitelistrelay is true | ||||
if (pfrom->fWhitelisted && | if (pfrom->fWhitelisted && | ||||
GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)) | GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)) { | ||||
fBlocksOnly = false; | fBlocksOnly = false; | ||||
} | |||||
LOCK(cs_main); | LOCK(cs_main); | ||||
uint32_t nFetchFlags = | uint32_t nFetchFlags = | ||||
GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()); | GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()); | ||||
std::vector<CInv> vToFetch; | std::vector<CInv> vToFetch; | ||||
for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) { | for (size_t nInv = 0; nInv < vInv.size(); nInv++) { | ||||
CInv &inv = vInv[nInv]; | CInv &inv = vInv[nInv]; | ||||
if (interruptMsgProc) return true; | if (interruptMsgProc) { | ||||
return true; | |||||
} | |||||
bool fAlreadyHave = AlreadyHave(inv); | bool fAlreadyHave = AlreadyHave(inv); | ||||
LogPrint("net", "got inv: %s %s peer=%d\n", inv.ToString(), | LogPrint("net", "got inv: %s %s peer=%d\n", inv.ToString(), | ||||
fAlreadyHave ? "have" : "new", pfrom->id); | fAlreadyHave ? "have" : "new", pfrom->id); | ||||
if (inv.type == MSG_TX) { | if (inv.type == MSG_TX) { | ||||
inv.type |= nFetchFlags; | inv.type |= nFetchFlags; | ||||
} | } | ||||
Show All 38 Lines | else if (strCommand == NetMsgType::INV) { | ||||
msgMaker.Make(NetMsgType::GETDATA, vToFetch)); | msgMaker.Make(NetMsgType::GETDATA, vToFetch)); | ||||
} | } | ||||
else if (strCommand == NetMsgType::GETDATA) { | else if (strCommand == NetMsgType::GETDATA) { | ||||
std::vector<CInv> vInv; | std::vector<CInv> vInv; | ||||
vRecv >> vInv; | vRecv >> vInv; | ||||
if (vInv.size() > MAX_INV_SZ) { | if (vInv.size() > MAX_INV_SZ) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom->GetId(), 20); | Misbehaving(pfrom->GetId(), 20, "too-many-inv"); | ||||
return error("message getdata size() = %u", vInv.size()); | return error("message getdata size() = %u", vInv.size()); | ||||
} | } | ||||
if (fDebug || (vInv.size() != 1)) | if (fDebug || (vInv.size() != 1)) { | ||||
LogPrint("net", "received getdata (%u invsz) peer=%d\n", | LogPrint("net", "received getdata (%u invsz) peer=%d\n", | ||||
vInv.size(), pfrom->id); | vInv.size(), pfrom->id); | ||||
} | |||||
if ((fDebug && vInv.size() > 0) || (vInv.size() == 1)) | if ((fDebug && vInv.size() > 0) || (vInv.size() == 1)) { | ||||
LogPrint("net", "received getdata for: %s peer=%d\n", | LogPrint("net", "received getdata for: %s peer=%d\n", | ||||
vInv[0].ToString(), pfrom->id); | vInv[0].ToString(), pfrom->id); | ||||
} | |||||
pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), | pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), | ||||
vInv.end()); | vInv.end()); | ||||
ProcessGetData(config, pfrom, chainparams.GetConsensus(), connman, | ProcessGetData(config, pfrom, chainparams.GetConsensus(), connman, | ||||
interruptMsgProc); | interruptMsgProc); | ||||
} | } | ||||
else if (strCommand == NetMsgType::GETBLOCKS) { | else if (strCommand == NetMsgType::GETBLOCKS) { | ||||
▲ Show 20 Lines • Show All 222 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::TX) { | ||||
// Recursively process any orphan transactions that depended on this | // Recursively process any orphan transactions that depended on this | ||||
// one | // one | ||||
std::set<NodeId> setMisbehaving; | std::set<NodeId> setMisbehaving; | ||||
while (!vWorkQueue.empty()) { | while (!vWorkQueue.empty()) { | ||||
auto itByPrev = | auto itByPrev = | ||||
mapOrphanTransactionsByPrev.find(vWorkQueue.front()); | mapOrphanTransactionsByPrev.find(vWorkQueue.front()); | ||||
vWorkQueue.pop_front(); | vWorkQueue.pop_front(); | ||||
if (itByPrev == mapOrphanTransactionsByPrev.end()) continue; | if (itByPrev == mapOrphanTransactionsByPrev.end()) { | ||||
continue; | |||||
} | |||||
for (auto mi = itByPrev->second.begin(); | for (auto mi = itByPrev->second.begin(); | ||||
mi != itByPrev->second.end(); ++mi) { | mi != itByPrev->second.end(); ++mi) { | ||||
const CTransactionRef &porphanTx = (*mi)->second.tx; | const CTransactionRef &porphanTx = (*mi)->second.tx; | ||||
const CTransaction &orphanTx = *porphanTx; | const CTransaction &orphanTx = *porphanTx; | ||||
const uint256 &orphanId = orphanTx.GetId(); | const uint256 &orphanId = orphanTx.GetId(); | ||||
NodeId fromPeer = (*mi)->second.fromPeer; | NodeId fromPeer = (*mi)->second.fromPeer; | ||||
bool fMissingInputs2 = false; | bool fMissingInputs2 = false; | ||||
// Use a dummy CValidationState so someone can't setup nodes | // Use a dummy CValidationState so someone can't setup nodes | ||||
// to counter-DoS based on orphan resolution (that is, | // to counter-DoS based on orphan resolution (that is, | ||||
// feeding people an invalid transaction based on LegitTxX | // feeding people an invalid transaction based on LegitTxX | ||||
// in order to get anyone relaying LegitTxX banned) | // in order to get anyone relaying LegitTxX banned) | ||||
CValidationState stateDummy; | CValidationState stateDummy; | ||||
if (setMisbehaving.count(fromPeer)) continue; | if (setMisbehaving.count(fromPeer)) { | ||||
continue; | |||||
} | |||||
if (AcceptToMemoryPool(config, mempool, stateDummy, | if (AcceptToMemoryPool(config, mempool, stateDummy, | ||||
porphanTx, true, &fMissingInputs2, | porphanTx, true, &fMissingInputs2, | ||||
&lRemovedTxn)) { | &lRemovedTxn)) { | ||||
LogPrint("mempool", " accepted orphan tx %s\n", | LogPrint("mempool", " accepted orphan tx %s\n", | ||||
orphanId.ToString()); | orphanId.ToString()); | ||||
RelayTransaction(orphanTx, connman); | RelayTransaction(orphanTx, connman); | ||||
for (unsigned int i = 0; i < orphanTx.vout.size(); | for (size_t i = 0; i < orphanTx.vout.size(); i++) { | ||||
i++) { | |||||
vWorkQueue.emplace_back(orphanId, i); | vWorkQueue.emplace_back(orphanId, i); | ||||
} | } | ||||
vEraseQueue.push_back(orphanId); | vEraseQueue.push_back(orphanId); | ||||
} else if (!fMissingInputs2) { | } else if (!fMissingInputs2) { | ||||
int nDos = 0; | int nDos = 0; | ||||
if (stateDummy.IsInvalid(nDos) && nDos > 0) { | if (stateDummy.IsInvalid(nDos) && nDos > 0) { | ||||
// Punish peer that gave us an invalid orphan tx | // Punish peer that gave us an invalid orphan tx | ||||
Misbehaving(fromPeer, nDos); | Misbehaving(fromPeer, nDos, "invalid-orphan-tx"); | ||||
setMisbehaving.insert(fromPeer); | setMisbehaving.insert(fromPeer); | ||||
LogPrint("mempool", " invalid orphan tx %s\n", | LogPrint("mempool", " invalid orphan tx %s\n", | ||||
orphanId.ToString()); | orphanId.ToString()); | ||||
} | } | ||||
// Has inputs but not accepted to mempool | // Has inputs but not accepted to mempool | ||||
// Probably non-standard or insufficient fee/priority | // Probably non-standard or insufficient fee/priority | ||||
LogPrint("mempool", " removed orphan tx %s\n", | LogPrint("mempool", " removed orphan tx %s\n", | ||||
orphanId.ToString()); | orphanId.ToString()); | ||||
▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::TX) { | ||||
AddToCompactExtraTransactions(removedTx); | AddToCompactExtraTransactions(removedTx); | ||||
int nDoS = 0; | int nDoS = 0; | ||||
if (state.IsInvalid(nDoS)) { | if (state.IsInvalid(nDoS)) { | ||||
LogPrint("mempoolrej", "%s from peer=%d was not accepted: %s\n", | LogPrint("mempoolrej", "%s from peer=%d was not accepted: %s\n", | ||||
tx.GetId().ToString(), pfrom->id, | tx.GetId().ToString(), pfrom->id, | ||||
FormatStateMessage(state)); | 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, | ||||
(unsigned char)state.GetRejectCode(), | (unsigned char)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->GetId(), nDoS); | Misbehaving(pfrom->GetId(), nDoS, state.GetRejectReason()); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && | // Ignore blocks received while importing | ||||
!fReindex) // Ignore blocks received while importing | else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) { | ||||
{ | |||||
CBlockHeaderAndShortTxIDs cmpctblock; | CBlockHeaderAndShortTxIDs cmpctblock; | ||||
vRecv >> cmpctblock; | vRecv >> cmpctblock; | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
if (mapBlockIndex.find(cmpctblock.header.hashPrevBlock) == | if (mapBlockIndex.find(cmpctblock.header.hashPrevBlock) == | ||||
mapBlockIndex.end()) { | mapBlockIndex.end()) { | ||||
// Doesn't connect (or is genesis), instead of DoSing in | // Doesn't connect (or is genesis), instead of DoSing in | ||||
// AcceptBlockHeader, request deeper headers | // AcceptBlockHeader, request deeper headers | ||||
if (!IsInitialBlockDownload()) | if (!IsInitialBlockDownload()) { | ||||
connman.PushMessage( | connman.PushMessage( | ||||
pfrom, | pfrom, | ||||
msgMaker.Make(NetMsgType::GETHEADERS, | msgMaker.Make(NetMsgType::GETHEADERS, | ||||
chainActive.GetLocator(pindexBestHeader), | chainActive.GetLocator(pindexBestHeader), | ||||
uint256())); | uint256())); | ||||
} | |||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
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) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom->GetId(), nDoS); | Misbehaving(pfrom->GetId(), nDoS, state.GetRejectReason()); | ||||
} | } | ||||
LogPrintf("Peer %d sent us invalid header via cmpctblock\n", | LogPrintf("Peer %d sent us invalid header via cmpctblock\n", | ||||
pfrom->id); | pfrom->id); | ||||
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 | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) { | ||||
MAX_BLOCKS_IN_TRANSIT_PER_PEER) || | MAX_BLOCKS_IN_TRANSIT_PER_PEER) || | ||||
(fAlreadyInFlight && | (fAlreadyInFlight && | ||||
blockInFlightIt->second.first == pfrom->GetId())) { | blockInFlightIt->second.first == pfrom->GetId())) { | ||||
std::list<QueuedBlock>::iterator *queuedBlockIt = nullptr; | std::list<QueuedBlock>::iterator *queuedBlockIt = nullptr; | ||||
if (!MarkBlockAsInFlight(config, pfrom->GetId(), | if (!MarkBlockAsInFlight(config, pfrom->GetId(), | ||||
pindex->GetBlockHash(), | pindex->GetBlockHash(), | ||||
chainparams.GetConsensus(), pindex, | chainparams.GetConsensus(), pindex, | ||||
&queuedBlockIt)) { | &queuedBlockIt)) { | ||||
if (!(*queuedBlockIt)->partialBlock) | if (!(*queuedBlockIt)->partialBlock) { | ||||
(*queuedBlockIt) | (*queuedBlockIt) | ||||
->partialBlock.reset( | ->partialBlock.reset( | ||||
new PartiallyDownloadedBlock(config, | new PartiallyDownloadedBlock(config, | ||||
&mempool)); | &mempool)); | ||||
else { | } else { | ||||
// The block was already in flight using compact | // The block was already in flight using compact | ||||
// blocks from the same peer. | // blocks from the same peer. | ||||
LogPrint("net", "Peer sent us compact block we " | LogPrint("net", "Peer sent us compact block we " | ||||
"were already syncing!\n"); | "were already syncing!\n"); | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
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) { | ||||
MarkBlockAsReceived( | // Reset in-flight state in case of whitelist | ||||
pindex->GetBlockHash()); // Reset in-flight state in | MarkBlockAsReceived(pindex->GetBlockHash()); | ||||
// case of whitelist | Misbehaving(pfrom->GetId(), 100, "invalid-cmpctblk"); | ||||
Misbehaving(pfrom->GetId(), 100); | |||||
LogPrintf("Peer %d sent us invalid compact block\n", | LogPrintf("Peer %d sent us invalid compact block\n", | ||||
pfrom->id); | pfrom->id); | ||||
return true; | return true; | ||||
} else if (status == READ_STATUS_FAILED) { | } else if (status == READ_STATUS_FAILED) { | ||||
// Duplicate txindexes, the block is now in-flight, so | // Duplicate txindexes, 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] = | vInv[0] = | ||||
▲ Show 20 Lines • Show All 126 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->GetId(), 100); | Misbehaving(pfrom->GetId(), 100, "invalid-cmpctblk-txns"); | ||||
LogPrintf("Peer %d sent us invalid compact block/non-matching " | LogPrintf("Peer %d sent us invalid compact block/non-matching " | ||||
"block transactions\n", | "block transactions\n", | ||||
pfrom->id); | pfrom->id); | ||||
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( | invs.push_back( | ||||
Show All 38 Lines | else if (strCommand == NetMsgType::BLOCKTXN && !fImporting && | ||||
// Since we requested this block (it was in mapBlocksInFlight), | // Since we requested this block (it was in mapBlocksInFlight), | ||||
// force it to be processed, even if it would not be a candidate for | // force it to be processed, even if it would not be a candidate for | ||||
// new tip (missing previous block, chain not long enough, etc) | // new tip (missing previous block, chain not long enough, etc) | ||||
ProcessNewBlock(config, pblock, true, &fNewBlock); | ProcessNewBlock(config, pblock, true, &fNewBlock); | ||||
if (fNewBlock) pfrom->nLastBlockTime = GetTime(); | if (fNewBlock) pfrom->nLastBlockTime = GetTime(); | ||||
} | } | ||||
} | } | ||||
else if (strCommand == NetMsgType::HEADERS && !fImporting && | // Ignore headers received while importing | ||||
!fReindex) // Ignore headers received while importing | else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) { | ||||
{ | |||||
std::vector<CBlockHeader> headers; | std::vector<CBlockHeader> headers; | ||||
// Bypass the normal CBlock deserialization, as we don't want to risk | // Bypass the normal CBlock deserialization, as we don't want to risk | ||||
// deserializing 2000 full blocks. | // deserializing 2000 full blocks. | ||||
unsigned int nCount = ReadCompactSize(vRecv); | unsigned int nCount = ReadCompactSize(vRecv); | ||||
if (nCount > MAX_HEADERS_RESULTS) { | if (nCount > MAX_HEADERS_RESULTS) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom->GetId(), 20); | Misbehaving(pfrom->GetId(), 20, "too-many-headers"); | ||||
return error("headers message size = %u", nCount); | return error("headers message size = %u", nCount); | ||||
} | } | ||||
headers.resize(nCount); | headers.resize(nCount); | ||||
for (unsigned int n = 0; n < nCount; n++) { | for (unsigned int n = 0; n < nCount; n++) { | ||||
vRecv >> headers[n]; | vRecv >> headers[n]; | ||||
// ignore tx count; assume it is 0. | // Ignore tx count; assume it is 0. | ||||
ReadCompactSize(vRecv); | ReadCompactSize(vRecv); | ||||
} | } | ||||
if (nCount == 0) { | if (nCount == 0) { | ||||
// Nothing interesting. Stop asking this peers for more headers. | // Nothing interesting. Stop asking this peers for more headers. | ||||
return true; | return true; | ||||
} | } | ||||
Show All 32 Lines | else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) { | ||||
// eventually get the headers - even from a different peer - | // eventually get the headers - even from a different peer - | ||||
// we can use this peer to download. | // we can use this peer to download. | ||||
UpdateBlockAvailability(pfrom->GetId(), | UpdateBlockAvailability(pfrom->GetId(), | ||||
headers.back().GetHash()); | headers.back().GetHash()); | ||||
if (nodestate->nUnconnectingHeaders % | if (nodestate->nUnconnectingHeaders % | ||||
MAX_UNCONNECTING_HEADERS == | MAX_UNCONNECTING_HEADERS == | ||||
0) { | 0) { | ||||
Misbehaving(pfrom->GetId(), 20); | // The peer is sending us many headers we can't connect. | ||||
Misbehaving(pfrom->GetId(), 20, | |||||
"too-many-unconnected-headers"); | |||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
uint256 hashLastBlock; | uint256 hashLastBlock; | ||||
for (const CBlockHeader &header : headers) { | for (const CBlockHeader &header : headers) { | ||||
if (!hashLastBlock.IsNull() && | if (!hashLastBlock.IsNull() && | ||||
header.hashPrevBlock != hashLastBlock) { | header.hashPrevBlock != hashLastBlock) { | ||||
Misbehaving(pfrom->GetId(), 20); | Misbehaving(pfrom->GetId(), 20, "disconnected-header"); | ||||
return error("non-continuous headers sequence"); | return error("non-continuous headers sequence"); | ||||
} | } | ||||
hashLastBlock = header.GetHash(); | hashLastBlock = header.GetHash(); | ||||
} | } | ||||
} | } | ||||
CValidationState state; | CValidationState state; | ||||
if (!ProcessNewBlockHeaders(config, headers, state, &pindexLast)) { | if (!ProcessNewBlockHeaders(config, headers, state, &pindexLast)) { | ||||
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->GetId(), nDoS); | Misbehaving(pfrom->GetId(), nDoS, state.GetRejectReason()); | ||||
} | } | ||||
return error("invalid header received"); | return error("invalid header received"); | ||||
} | } | ||||
} | } | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
CNodeState *nodestate = State(pfrom->GetId()); | CNodeState *nodestate = State(pfrom->GetId()); | ||||
▲ Show 20 Lines • Show All 259 Lines • ▼ Show 20 Lines | |||||
else if (strCommand == NetMsgType::FILTERLOAD) { | else if (strCommand == NetMsgType::FILTERLOAD) { | ||||
CBloomFilter filter; | CBloomFilter filter; | ||||
vRecv >> filter; | vRecv >> filter; | ||||
if (!filter.IsWithinSizeConstraints()) { | if (!filter.IsWithinSizeConstraints()) { | ||||
// There is no excuse for sending a too-large filter | // There is no excuse for sending a too-large filter | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom->GetId(), 100); | Misbehaving(pfrom->GetId(), 100, "oversized-bloom-filter"); | ||||
} else { | } else { | ||||
LOCK(pfrom->cs_filter); | LOCK(pfrom->cs_filter); | ||||
delete pfrom->pfilter; | delete pfrom->pfilter; | ||||
pfrom->pfilter = new CBloomFilter(filter); | pfrom->pfilter = new CBloomFilter(filter); | ||||
pfrom->pfilter->UpdateEmptyFull(); | pfrom->pfilter->UpdateEmptyFull(); | ||||
pfrom->fRelayTxes = true; | pfrom->fRelayTxes = true; | ||||
} | } | ||||
} | } | ||||
Show All 13 Lines | else if (strCommand == NetMsgType::FILTERADD) { | ||||
if (pfrom->pfilter) { | if (pfrom->pfilter) { | ||||
pfrom->pfilter->insert(vData); | pfrom->pfilter->insert(vData); | ||||
} else { | } else { | ||||
bad = true; | bad = true; | ||||
} | } | ||||
} | } | ||||
if (bad) { | if (bad) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom->GetId(), 100); | // The structure of this code doesn't really allow for a good error | ||||
// code. We'll go generic. | |||||
Misbehaving(pfrom->GetId(), 100, "invalid-filteradd"); | |||||
} | } | ||||
} | } | ||||
else if (strCommand == NetMsgType::FILTERCLEAR) { | else if (strCommand == NetMsgType::FILTERCLEAR) { | ||||
LOCK(pfrom->cs_filter); | LOCK(pfrom->cs_filter); | ||||
if (pfrom->GetLocalServices() & NODE_BLOOM) { | if (pfrom->GetLocalServices() & NODE_BLOOM) { | ||||
delete pfrom->pfilter; | delete pfrom->pfilter; | ||||
pfrom->pfilter = new CBloomFilter(); | pfrom->pfilter = new CBloomFilter(); | ||||
Show All 38 Lines | for (const CBlockReject &reject : state.rejects) { | ||||
.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()); | ||||
else if (pnode->fAddnode) | } else if (pnode->fAddnode) { | ||||
LogPrintf("Warning: not punishing addnoded peer %s!\n", | LogPrintf("Warning: not punishing addnoded 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", | LogPrintf("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 733 Lines • Show Last 20 Lines |