Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 320 Lines • ▼ Show 20 Lines | static void PushNodeVersion(const Config &config, CNode *pnode, | ||||
connman->PushMessage(pnode, | connman->PushMessage(pnode, | ||||
CNetMsgMaker(INIT_PROTO_VERSION) | CNetMsgMaker(INIT_PROTO_VERSION) | ||||
.Make(NetMsgType::VERSION, PROTOCOL_VERSION, | .Make(NetMsgType::VERSION, PROTOCOL_VERSION, | ||||
uint64_t(nLocalNodeServices), nTime, addrYou, | uint64_t(nLocalNodeServices), nTime, addrYou, | ||||
addrMe, nonce, userAgent(config), | addrMe, nonce, userAgent(config), | ||||
nNodeStartingHeight, ::fRelayTxes)); | nNodeStartingHeight, ::fRelayTxes)); | ||||
if (fLogIPs) { | if (fLogIPs) { | ||||
LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, " | LogPrint(BCLog::NET, | ||||
"us=%s, them=%s, peer=%d\n", | "send version message: version %d, blocks=%d, us=%s, them=%s, " | ||||
"peer=%d\n", | |||||
PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), | PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), | ||||
addrYou.ToString(), nodeid); | addrYou.ToString(), nodeid); | ||||
} else { | } else { | ||||
LogPrint( | LogPrint( | ||||
BCLog::NET, | BCLog::NET, | ||||
"send version message: version %d, blocks=%d, us=%s, peer=%d\n", | "send version message: version %d, blocks=%d, us=%s, peer=%d\n", | ||||
PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), nodeid); | PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), nodeid); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 171 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, | connman->PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()) | ||||
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; | ||||
}); | }); | ||||
} | } | ||||
static bool TipMayBeStale(const Consensus::Params &consensusParams) | static bool TipMayBeStale(const Consensus::Params &consensusParams) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
▲ Show 20 Lines • Show All 760 Lines • ▼ Show 20 Lines | while (it != pfrom->vRecvGetData.end()) { | ||||
// Never disconnect whitelisted nodes. | // Never disconnect whitelisted nodes. | ||||
if (send && connman->OutboundTargetReached(true) && | if (send && connman->OutboundTargetReached(true) && | ||||
(((pindexBestHeader != nullptr) && | (((pindexBestHeader != nullptr) && | ||||
(pindexBestHeader->GetBlockTime() - | (pindexBestHeader->GetBlockTime() - | ||||
mi->second->GetBlockTime() > | mi->second->GetBlockTime() > | ||||
HISTORICAL_BLOCK_AGE)) || | HISTORICAL_BLOCK_AGE)) || | ||||
inv.type == MSG_FILTERED_BLOCK) && | inv.type == MSG_FILTERED_BLOCK) && | ||||
!pfrom->fWhitelisted) { | !pfrom->fWhitelisted) { | ||||
LogPrint(BCLog::NET, "historical block serving limit " | LogPrint(BCLog::NET, | ||||
"reached, disconnect peer=%d\n", | "historical block serving limit reached, " | ||||
"disconnect peer=%d\n", | |||||
pfrom->GetId()); | pfrom->GetId()); | ||||
// disconnect node | // disconnect node | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
send = false; | send = false; | ||||
} | } | ||||
// Pruned nodes may have deleted the block, so check whether | // Pruned nodes may have deleted the block, so check whether | ||||
// it's available before trying to send. | // it's available before trying to send. | ||||
Show All 15 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, | pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, | ||||
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, | pfrom, msgMaker.Make(nSendFlags, | ||||
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, | NetMsgType::BLOCK, 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 = g_mempool.info(inv.hash); | auto txinfo = g_mempool.info(inv.hash); | ||||
// To protect privacy, do not answer getdata using the | // To protect privacy, do not answer getdata using the | ||||
// mempool 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, | connman->PushMessage( | ||||
msgMaker.Make(nSendFlags, | 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 72 Lines • ▼ Show 20 Lines | const CBlockIndex *pindexLast = nullptr; | ||||
// 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 connect, | // - Once a headers message is received that is valid and does 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( | connman->PushMessage( | ||||
pfrom, | pfrom, msgMaker.Make(NetMsgType::GETHEADERS, | ||||
msgMaker.Make(NetMsgType::GETHEADERS, | |||||
chainActive.GetLocator(pindexBestHeader), | chainActive.GetLocator(pindexBestHeader), | ||||
uint256())); | uint256())); | ||||
LogPrint(BCLog::NET, "received header %s: missing prev block %s, " | LogPrint( | ||||
"sending getheaders (%d) to end (peer=%d, " | BCLog::NET, | ||||
"nUnconnectingHeaders=%d)\n", | "received header %s: missing prev block %s, sending getheaders " | ||||
"(%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", | |||||
headers[0].GetHash().ToString(), | headers[0].GetHash().ToString(), | ||||
headers[0].hashPrevBlock.ToString(), | headers[0].hashPrevBlock.ToString(), pindexBestHeader->nHeight, | ||||
pindexBestHeader->nHeight, pfrom->GetId(), | pfrom->GetId(), nodestate->nUnconnectingHeaders); | ||||
nodestate->nUnconnectingHeaders); | |||||
// Set hashLastUnknownBlock for this peer, so that if we eventually | // Set hashLastUnknownBlock for this peer, so that if we eventually | ||||
// get the headers - even from a different peer - we can use this | // get the headers - even from a different peer - we can use this | ||||
// peer to download. | // peer to download. | ||||
UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHash()); | UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHash()); | ||||
if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == | if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == | ||||
0) { | 0) { | ||||
// The peer is sending us many headers we can't connect. | // The peer is sending us many headers we can't connect. | ||||
▲ Show 20 Lines • Show All 144 Lines • ▼ Show 20 Lines | if (!ProcessNewBlockHeaders(config, headers, state, &pindexLast, | ||||
vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash())); | vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash())); | ||||
MarkBlockAsInFlight(config, pfrom->GetId(), | MarkBlockAsInFlight(config, pfrom->GetId(), | ||||
pindex->GetBlockHash(), | pindex->GetBlockHash(), | ||||
chainparams.GetConsensus(), pindex); | chainparams.GetConsensus(), pindex); | ||||
LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n", | LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n", | ||||
pindex->GetBlockHash().ToString(), pfrom->GetId()); | pindex->GetBlockHash().ToString(), pfrom->GetId()); | ||||
} | } | ||||
if (vGetData.size() > 1) { | if (vGetData.size() > 1) { | ||||
LogPrint(BCLog::NET, "Downloading blocks toward %s " | LogPrint(BCLog::NET, | ||||
"(%d) via headers direct fetch\n", | "Downloading blocks toward %s (%d) via headers " | ||||
"direct fetch\n", | |||||
pindexLast->GetBlockHash().ToString(), | pindexLast->GetBlockHash().ToString(), | ||||
pindexLast->nHeight); | pindexLast->nHeight); | ||||
} | } | ||||
if (vGetData.size() > 0) { | if (vGetData.size() > 0) { | ||||
if (nodestate->fSupportsDesiredCmpctVersion && | if (nodestate->fSupportsDesiredCmpctVersion && | ||||
vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && | vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && | ||||
pindexLast->pprev->IsValid(BlockValidity::CHAIN)) { | pindexLast->pprev->IsValid(BlockValidity::CHAIN)) { | ||||
// In any case, we want to download using a compact | // In any case, we want to download using a compact | ||||
▲ Show 20 Lines • Show All 134 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::VERSION) { | ||||
nSendVersion = std::min(nVersion, PROTOCOL_VERSION); | nSendVersion = std::min(nVersion, PROTOCOL_VERSION); | ||||
nServices = ServiceFlags(nServiceInt); | nServices = ServiceFlags(nServiceInt); | ||||
if (!pfrom->fInbound) { | if (!pfrom->fInbound) { | ||||
connman->SetServices(pfrom->addr, nServices); | connman->SetServices(pfrom->addr, nServices); | ||||
} | } | ||||
if (!pfrom->fInbound && !pfrom->fFeeler && | if (!pfrom->fInbound && !pfrom->fFeeler && | ||||
!pfrom->m_manual_connection && | !pfrom->m_manual_connection && | ||||
!HasAllDesirableServiceFlags(nServices)) { | !HasAllDesirableServiceFlags(nServices)) { | ||||
LogPrint( | LogPrint(BCLog::NET, | ||||
BCLog::NET, "peer=%d does not offer the expected services " | "peer=%d does not offer the expected services " | ||||
"(%08x offered, %08x expected); disconnecting\n", | "(%08x offered, %08x expected); disconnecting\n", | ||||
pfrom->GetId(), nServices, GetDesirableServiceFlags(nServices)); | pfrom->GetId(), nServices, | ||||
GetDesirableServiceFlags(nServices)); | |||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, | pfrom, | ||||
CNetMsgMaker(INIT_PROTO_VERSION) | CNetMsgMaker(INIT_PROTO_VERSION) | ||||
.Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD, | .Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD, | ||||
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; | ||||
▲ Show 20 Lines • Show All 171 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, | connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, | ||||
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 130 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::INV) { | ||||
inv.hash)); | inv.hash)); | ||||
LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", | LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", | ||||
pindexBestHeader->nHeight, inv.hash.ToString(), | pindexBestHeader->nHeight, inv.hash.ToString(), | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
} | } | ||||
} else { | } else { | ||||
pfrom->AddInventoryKnown(inv); | pfrom->AddInventoryKnown(inv); | ||||
if (fBlocksOnly) { | if (fBlocksOnly) { | ||||
LogPrint(BCLog::NET, "transaction (%s) inv sent in " | LogPrint(BCLog::NET, | ||||
"violation of protocol peer=%d\n", | "transaction (%s) inv sent in violation of " | ||||
"protocol peer=%d\n", | |||||
inv.hash.ToString(), pfrom->GetId()); | inv.hash.ToString(), pfrom->GetId()); | ||||
} else if (!fAlreadyHave && !fImporting && !fReindex && | } else if (!fAlreadyHave && !fImporting && !fReindex && | ||||
!IsInitialBlockDownload()) { | !IsInitialBlockDownload()) { | ||||
pfrom->AskFor(inv); | pfrom->AskFor(inv); | ||||
} | } | ||||
} | } | ||||
// Track requests for our stuff | // Track requests for our stuff | ||||
▲ Show 20 Lines • Show All 152 Lines • ▼ Show 20 Lines | static bool ProcessMessage(const Config &config, CNode *pfrom, | ||||
else if (strCommand == NetMsgType::GETHEADERS) { | else if (strCommand == NetMsgType::GETHEADERS) { | ||||
CBlockLocator locator; | CBlockLocator locator; | ||||
uint256 hashStop; | uint256 hashStop; | ||||
vRecv >> locator >> hashStop; | vRecv >> locator >> hashStop; | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
if (IsInitialBlockDownload() && !pfrom->fWhitelisted) { | if (IsInitialBlockDownload() && !pfrom->fWhitelisted) { | ||||
LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because " | LogPrint(BCLog::NET, | ||||
"node is in initial block download\n", | "Ignoring getheaders from peer=%d because node is in " | ||||
"initial block download\n", | |||||
pfrom->GetId()); | pfrom->GetId()); | ||||
return true; | return true; | ||||
} | } | ||||
CNodeState *nodestate = State(pfrom->GetId()); | CNodeState *nodestate = State(pfrom->GetId()); | ||||
const CBlockIndex *pindex = nullptr; | const CBlockIndex *pindex = nullptr; | ||||
if (locator.IsNull()) { | if (locator.IsNull()) { | ||||
// If locator is null, return the hashStop block | // If locator is null, return the hashStop block | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::TX) { | ||||
g_mempool.check(pcoinsTip.get()); | g_mempool.check(pcoinsTip.get()); | ||||
RelayTransaction(tx, connman); | RelayTransaction(tx, connman); | ||||
for (size_t i = 0; i < tx.vout.size(); i++) { | for (size_t i = 0; i < tx.vout.size(); i++) { | ||||
vWorkQueue.emplace_back(inv.hash, i); | vWorkQueue.emplace_back(inv.hash, i); | ||||
} | } | ||||
pfrom->nLastTXTime = GetTime(); | pfrom->nLastTXTime = GetTime(); | ||||
LogPrint(BCLog::MEMPOOL, "AcceptToMemoryPool: peer=%d: accepted %s " | LogPrint(BCLog::MEMPOOL, | ||||
"AcceptToMemoryPool: peer=%d: accepted %s " | |||||
"(poolsz %u txn, %u kB)\n", | "(poolsz %u txn, %u kB)\n", | ||||
pfrom->GetId(), tx.GetId().ToString(), g_mempool.size(), | pfrom->GetId(), tx.GetId().ToString(), g_mempool.size(), | ||||
g_mempool.DynamicMemoryUsage() / 1000); | g_mempool.DynamicMemoryUsage() / 1000); | ||||
// 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 = | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::TX) { | ||||
pfrom->AskFor(_inv); | pfrom->AskFor(_inv); | ||||
} | } | ||||
} | } | ||||
AddOrphanTx(ptx, pfrom->GetId()); | AddOrphanTx(ptx, pfrom->GetId()); | ||||
// DoS prevention: do not allow mapOrphanTransactions to grow | // DoS prevention: do not allow mapOrphanTransactions to grow | ||||
// unbounded | // unbounded | ||||
unsigned int nMaxOrphanTx = (unsigned int)std::max( | unsigned int nMaxOrphanTx = (unsigned int)std::max( | ||||
int64_t(0), | int64_t(0), gArgs.GetArg("-maxorphantx", | ||||
gArgs.GetArg("-maxorphantx", | |||||
DEFAULT_MAX_ORPHAN_TRANSACTIONS)); | DEFAULT_MAX_ORPHAN_TRANSACTIONS)); | ||||
unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx); | unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx); | ||||
if (nEvicted > 0) { | if (nEvicted > 0) { | ||||
LogPrint(BCLog::MEMPOOL, | LogPrint(BCLog::MEMPOOL, | ||||
"mapOrphan overflow, removed %u tx\n", nEvicted); | "mapOrphan overflow, removed %u tx\n", nEvicted); | ||||
} | } | ||||
} else { | } else { | ||||
LogPrint(BCLog::MEMPOOL, | LogPrint(BCLog::MEMPOOL, | ||||
"not keeping orphan with rejected parents %s\n", | "not keeping orphan with rejected parents %s\n", | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::TX) { | ||||
LogPrint(BCLog::MEMPOOLREJ, | LogPrint(BCLog::MEMPOOLREJ, | ||||
"%s from peer=%d was not accepted: %s\n", | "%s from peer=%d was not accepted: %s\n", | ||||
tx.GetHash().ToString(), pfrom->GetId(), | tx.GetHash().ToString(), pfrom->GetId(), | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
// Never send AcceptToMemoryPool's internal codes over P2P. | // Never send AcceptToMemoryPool's internal codes over P2P. | ||||
if (state.GetRejectCode() > 0 && | if (state.GetRejectCode() > 0 && | ||||
state.GetRejectCode() < REJECT_INTERNAL) { | state.GetRejectCode() < REJECT_INTERNAL) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, | pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, | ||||
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 106 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) { | ||||
if (!fAlreadyInFlight && | if (!fAlreadyInFlight && | ||||
!CanDirectFetch(chainparams.GetConsensus())) { | !CanDirectFetch(chainparams.GetConsensus())) { | ||||
return true; | return true; | ||||
} | } | ||||
// We want to be a bit conservative just to be extra careful about | // We want to be a bit conservative just to be extra careful about | ||||
// DoS possibilities in compact block processing... | // DoS possibilities in compact block processing... | ||||
if (pindex->nHeight <= chainActive.Height() + 2) { | if (pindex->nHeight <= chainActive.Height() + 2) { | ||||
if ((!fAlreadyInFlight && | if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < | ||||
nodestate->nBlocksInFlight < | |||||
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) { | ||||
▲ Show 20 Lines • Show All 316 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::GETADDR) { | ||||
FastRandomContext insecure_rand; | FastRandomContext insecure_rand; | ||||
for (const CAddress &addr : vAddr) { | for (const CAddress &addr : vAddr) { | ||||
pfrom->PushAddress(addr, insecure_rand); | pfrom->PushAddress(addr, insecure_rand); | ||||
} | } | ||||
} | } | ||||
else if (strCommand == NetMsgType::MEMPOOL) { | else if (strCommand == NetMsgType::MEMPOOL) { | ||||
if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->fWhitelisted) { | if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->fWhitelisted) { | ||||
LogPrint(BCLog::NET, "mempool request with bloom filters disabled, " | LogPrint(BCLog::NET, | ||||
"disconnect peer=%d\n", | "mempool request with bloom filters disabled, disconnect " | ||||
"peer=%d\n", | |||||
pfrom->GetId()); | pfrom->GetId()); | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
return true; | return true; | ||||
} | } | ||||
if (connman->OutboundTargetReached(false) && !pfrom->fWhitelisted) { | if (connman->OutboundTargetReached(false) && !pfrom->fWhitelisted) { | ||||
LogPrint(BCLog::NET, "mempool request with bandwidth limit " | LogPrint(BCLog::NET, | ||||
"reached, disconnect peer=%d\n", | "mempool request with bandwidth limit reached, disconnect " | ||||
"peer=%d\n", | |||||
pfrom->GetId()); | pfrom->GetId()); | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
return true; | return true; | ||||
} | } | ||||
LOCK(pfrom->cs_inventory); | LOCK(pfrom->cs_inventory); | ||||
pfrom->fSendMempool = true; | pfrom->fSendMempool = true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 156 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, | pnode, CNetMsgMaker(INIT_PROTO_VERSION) | ||||
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 111 Lines • ▼ Show 20 Lines | try { | ||||
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(pfrom, | connman->PushMessage( | ||||
CNetMsgMaker(INIT_PROTO_VERSION) | pfrom, 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( | 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 71 Lines • ▼ Show 20 Lines | if (!state.m_chain_sync.m_protect && | ||||
"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 { | ||||
LogPrint( | LogPrint( | ||||
BCLog::NET, "sending getheaders to outbound peer=%d to " | BCLog::NET, | ||||
"verify chain work (current best known " | "sending getheaders to outbound peer=%d to verify chain " | ||||
"block:%s, benchmark blockhash: %s)\n", | "work (current best known block:%s, benchmark blockhash: " | ||||
"%s)\n", | |||||
pto->GetId(), | pto->GetId(), | ||||
state.pindexBestKnownBlock != nullptr | state.pindexBestKnownBlock != nullptr | ||||
? state.pindexBestKnownBlock->GetBlockHash().ToString() | ? state.pindexBestKnownBlock->GetBlockHash().ToString() | ||||
: "<none>", | : "<none>", | ||||
state.m_chain_sync.m_work_header->GetBlockHash() | state.m_chain_sync.m_work_header->GetBlockHash() | ||||
.ToString()); | .ToString()); | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pto, | pto, | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | bool disconnected = connman->ForNode(worst_peer, [&](CNode *pnode) { | ||||
// Only disconnect a peer that has been connected to us for some | // Only disconnect a peer that has been connected to us for some | ||||
// reasonable fraction of our check-frequency, to give it time for new | // reasonable fraction of our check-frequency, to give it time for new | ||||
// information to have arrived. | // information to have arrived. | ||||
// Also don't disconnect any peer we're trying to download a block from. | // Also don't disconnect any peer we're trying to download a block from. | ||||
CNodeState &state = *State(pnode->GetId()); | CNodeState &state = *State(pnode->GetId()); | ||||
if (time_in_seconds - pnode->nTimeConnected > MINIMUM_CONNECT_TIME && | if (time_in_seconds - pnode->nTimeConnected > MINIMUM_CONNECT_TIME && | ||||
state.nBlocksInFlight == 0) { | state.nBlocksInFlight == 0) { | ||||
LogPrint(BCLog::NET, "disconnecting extra outbound peer=%d (last " | LogPrint(BCLog::NET, | ||||
"block announcement received at time %d)\n", | "disconnecting extra outbound peer=%d (last block " | ||||
"announcement received at time %d)\n", | |||||
pnode->GetId(), oldest_block_announcement); | pnode->GetId(), oldest_block_announcement); | ||||
pnode->fDisconnect = true; | pnode->fDisconnect = true; | ||||
return true; | return true; | ||||
} else { | } else { | ||||
LogPrint(BCLog::NET, "keeping outbound peer=%d chosen for eviction " | LogPrint(BCLog::NET, | ||||
"keeping outbound peer=%d chosen for eviction " | |||||
"(connect time: %d, blocks_in_flight: %d)\n", | "(connect time: %d, blocks_in_flight: %d)\n", | ||||
pnode->GetId(), pnode->nTimeConnected, | pnode->GetId(), pnode->nTimeConnected, | ||||
state.nBlocksInFlight); | state.nBlocksInFlight); | ||||
return false; | return false; | ||||
} | } | ||||
}); | }); | ||||
if (disconnected) { | if (disconnected) { | ||||
// If we disconnected an extra peer, that means we successfully | // If we disconnected an extra peer, that means we successfully | ||||
▲ Show 20 Lines • Show All 291 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(pto, | connman->PushMessage( | ||||
msgMaker.Make(nSendFlags, | pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, | ||||
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 337 Lines • ▼ Show 20 Lines | bool PeerLogicValidation::SendMessages(const Config &config, CNode *pto, | ||||
// | // | ||||
// Message: feefilter | // Message: feefilter | ||||
// | // | ||||
// We don't want white listed peers to filter txs to us if we have | // We don't want white listed peers to filter txs to us if we have | ||||
// -whitelistforcerelay | // -whitelistforcerelay | ||||
if (pto->nVersion >= FEEFILTER_VERSION && | if (pto->nVersion >= FEEFILTER_VERSION && | ||||
gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) && | gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) && | ||||
!(pto->fWhitelisted && | !(pto->fWhitelisted && gArgs.GetBoolArg("-whitelistforcerelay", | ||||
gArgs.GetBoolArg("-whitelistforcerelay", | |||||
DEFAULT_WHITELISTFORCERELAY))) { | DEFAULT_WHITELISTFORCERELAY))) { | ||||
Amount currentFilter = | Amount currentFilter = | ||||
g_mempool | g_mempool | ||||
.GetMinFee( | .GetMinFee( | ||||
gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * | gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * | ||||
1000000) | 1000000) | ||||
.GetFeePerK(); | .GetFeePerK(); | ||||
int64_t timeNow = GetTimeMicros(); | int64_t timeNow = GetTimeMicros(); | ||||
if (timeNow > pto->nextSendTimeFeeFilter) { | if (timeNow > pto->nextSendTimeFeeFilter) { | ||||
▲ Show 20 Lines • Show All 42 Lines • Show Last 20 Lines |