Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 2,226 Lines • ▼ Show 20 Lines | while (!done && !orphan_work_set.empty()) { | ||||
EraseOrphanTx(orphanTxId); | EraseOrphanTx(orphanTxId); | ||||
done = true; | done = true; | ||||
} | } | ||||
g_mempool.check(&::ChainstateActive().CoinsTip()); | g_mempool.check(&::ChainstateActive().CoinsTip()); | ||||
} | } | ||||
} | } | ||||
bool ProcessMessage(const Config &config, CNode *pfrom, | bool ProcessMessage(const Config &config, CNode *pfrom, | ||||
const std::string &strCommand, CDataStream &vRecv, | const std::string &msg_type, CDataStream &vRecv, | ||||
int64_t nTimeReceived, CConnman *connman, BanMan *banman, | int64_t nTimeReceived, CConnman *connman, BanMan *banman, | ||||
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(msg_type), 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"); | LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n"); | ||||
return true; | return true; | ||||
} | } | ||||
if (!(pfrom->GetLocalServices() & NODE_BLOOM) && | if (!(pfrom->GetLocalServices() & NODE_BLOOM) && | ||||
(strCommand == NetMsgType::FILTERLOAD || | (msg_type == NetMsgType::FILTERLOAD || | ||||
strCommand == NetMsgType::FILTERADD)) { | msg_type == NetMsgType::FILTERADD)) { | ||||
if (pfrom->nVersion >= NO_BLOOM_VERSION) { | if (pfrom->nVersion >= NO_BLOOM_VERSION) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom, 100, "no-bloom-version"); | Misbehaving(pfrom, 100, "no-bloom-version"); | ||||
return false; | return false; | ||||
} else { | } else { | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
if (strCommand == NetMsgType::VERSION) { | if (msg_type == 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) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom, 1, "multiple-version"); | Misbehaving(pfrom, 1, "multiple-version"); | ||||
return false; | return false; | ||||
} | } | ||||
int64_t nTime; | int64_t nTime; | ||||
▲ Show 20 Lines • Show All 172 Lines • ▼ Show 20 Lines | if (pfrom->nVersion == 0) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom, 10, "missing-version"); | Misbehaving(pfrom, 10, "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 (msg_type == NetMsgType::VERACK) { | ||||
pfrom->SetRecvVersion( | pfrom->SetRecvVersion( | ||||
std::min(pfrom->nVersion.load(), PROTOCOL_VERSION)); | std::min(pfrom->nVersion.load(), PROTOCOL_VERSION)); | ||||
if (!pfrom->fInbound) { | if (!pfrom->fInbound) { | ||||
// Mark this node as currently connected, so we update its timestamp | // Mark this node as currently connected, so we update its timestamp | ||||
// later. | // later. | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
State(pfrom->GetId())->fCurrentlyConnected = true; | State(pfrom->GetId())->fCurrentlyConnected = true; | ||||
Show All 30 Lines | bool ProcessMessage(const Config &config, CNode *pfrom, | ||||
if (!pfrom->fSuccessfullyConnected) { | 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, 10, "missing-verack"); | Misbehaving(pfrom, 10, "missing-verack"); | ||||
return false; | return false; | ||||
} | } | ||||
if (strCommand == NetMsgType::ADDR) { | if (msg_type == 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; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::ADDR) { | ||||
pfrom->fGetAddr = false; | pfrom->fGetAddr = false; | ||||
} | } | ||||
if (pfrom->fOneShot) { | if (pfrom->fOneShot) { | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::SENDHEADERS) { | if (msg_type == NetMsgType::SENDHEADERS) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
State(pfrom->GetId())->fPreferHeaders = true; | State(pfrom->GetId())->fPreferHeaders = true; | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::SENDCMPCT) { | if (msg_type == NetMsgType::SENDCMPCT) { | ||||
bool fAnnounceUsingCMPCTBLOCK = false; | bool fAnnounceUsingCMPCTBLOCK = false; | ||||
uint64_t nCMPCTBLOCKVersion = 0; | uint64_t nCMPCTBLOCKVersion = 0; | ||||
vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion; | vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion; | ||||
if (nCMPCTBLOCKVersion == 1) { | if (nCMPCTBLOCKVersion == 1) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
// fProvidesHeaderAndIDs is used to "lock in" version of compact | // fProvidesHeaderAndIDs is used to "lock in" version of compact | ||||
// blocks we send. | // blocks we send. | ||||
if (!State(pfrom->GetId())->fProvidesHeaderAndIDs) { | if (!State(pfrom->GetId())->fProvidesHeaderAndIDs) { | ||||
State(pfrom->GetId())->fProvidesHeaderAndIDs = true; | State(pfrom->GetId())->fProvidesHeaderAndIDs = true; | ||||
} | } | ||||
State(pfrom->GetId())->fPreferHeaderAndIDs = | State(pfrom->GetId())->fPreferHeaderAndIDs = | ||||
fAnnounceUsingCMPCTBLOCK; | fAnnounceUsingCMPCTBLOCK; | ||||
if (!State(pfrom->GetId())->fSupportsDesiredCmpctVersion) { | if (!State(pfrom->GetId())->fSupportsDesiredCmpctVersion) { | ||||
State(pfrom->GetId())->fSupportsDesiredCmpctVersion = true; | State(pfrom->GetId())->fSupportsDesiredCmpctVersion = true; | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::INV) { | if (msg_type == 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, 20, "oversized-inv"); | Misbehaving(pfrom, 20, "oversized-inv"); | ||||
return error("message inv size() = %u", vInv.size()); | return error("message inv size() = %u", vInv.size()); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::INV) { | ||||
RequestTx(State(pfrom->GetId()), TxId(inv.hash), | RequestTx(State(pfrom->GetId()), TxId(inv.hash), | ||||
current_time); | current_time); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::GETDATA) { | if (msg_type == 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, 20, "too-many-inv"); | Misbehaving(pfrom, 20, "too-many-inv"); | ||||
return error("message getdata size() = %u", vInv.size()); | return error("message getdata size() = %u", vInv.size()); | ||||
} | } | ||||
LogPrint(BCLog::NET, "received getdata (%u invsz) peer=%d\n", | LogPrint(BCLog::NET, "received getdata (%u invsz) peer=%d\n", | ||||
vInv.size(), pfrom->GetId()); | vInv.size(), pfrom->GetId()); | ||||
if (vInv.size() > 0) { | if (vInv.size() > 0) { | ||||
LogPrint(BCLog::NET, "received getdata for: %s peer=%d\n", | LogPrint(BCLog::NET, "received getdata for: %s peer=%d\n", | ||||
vInv[0].ToString(), pfrom->GetId()); | vInv[0].ToString(), pfrom->GetId()); | ||||
} | } | ||||
pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), | pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), | ||||
vInv.end()); | vInv.end()); | ||||
ProcessGetData(config, pfrom, connman, interruptMsgProc); | ProcessGetData(config, pfrom, connman, interruptMsgProc); | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::GETBLOCKS) { | if (msg_type == NetMsgType::GETBLOCKS) { | ||||
CBlockLocator locator; | CBlockLocator locator; | ||||
uint256 hashStop; | uint256 hashStop; | ||||
vRecv >> locator >> hashStop; | vRecv >> locator >> hashStop; | ||||
if (locator.vHave.size() > MAX_LOCATOR_SZ) { | if (locator.vHave.size() > MAX_LOCATOR_SZ) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"getblocks locator size %lld > %d, disconnect peer=%d\n", | "getblocks locator size %lld > %d, disconnect peer=%d\n", | ||||
locator.vHave.size(), MAX_LOCATOR_SZ, pfrom->GetId()); | locator.vHave.size(), MAX_LOCATOR_SZ, pfrom->GetId()); | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::GETBLOCKS) { | ||||
pindex->nHeight, pindex->GetBlockHash().ToString()); | pindex->nHeight, pindex->GetBlockHash().ToString()); | ||||
pfrom->hashContinue = pindex->GetBlockHash(); | pfrom->hashContinue = pindex->GetBlockHash(); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::GETBLOCKTXN) { | if (msg_type == NetMsgType::GETBLOCKTXN) { | ||||
BlockTransactionsRequest req; | BlockTransactionsRequest req; | ||||
vRecv >> req; | vRecv >> req; | ||||
std::shared_ptr<const CBlock> recent_block; | std::shared_ptr<const CBlock> recent_block; | ||||
{ | { | ||||
LOCK(cs_most_recent_block); | LOCK(cs_most_recent_block); | ||||
if (most_recent_block_hash == req.blockhash) { | if (most_recent_block_hash == req.blockhash) { | ||||
recent_block = most_recent_block; | recent_block = most_recent_block; | ||||
Show All 39 Lines | if (msg_type == NetMsgType::GETBLOCKTXN) { | ||||
CBlock block; | CBlock block; | ||||
bool ret = ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()); | bool ret = ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()); | ||||
assert(ret); | assert(ret); | ||||
SendBlockTransactions(block, req, pfrom, connman); | SendBlockTransactions(block, req, pfrom, connman); | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::GETHEADERS) { | if (msg_type == NetMsgType::GETHEADERS) { | ||||
CBlockLocator locator; | CBlockLocator locator; | ||||
BlockHash hashStop; | BlockHash hashStop; | ||||
vRecv >> locator >> hashStop; | vRecv >> locator >> hashStop; | ||||
if (locator.vHave.size() > MAX_LOCATOR_SZ) { | if (locator.vHave.size() > MAX_LOCATOR_SZ) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"getheaders locator size %lld > %d, disconnect peer=%d\n", | "getheaders locator size %lld > %d, disconnect peer=%d\n", | ||||
locator.vHave.size(), MAX_LOCATOR_SZ, pfrom->GetId()); | locator.vHave.size(), MAX_LOCATOR_SZ, pfrom->GetId()); | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::GETHEADERS) { | ||||
// in the SendMessages logic. | // in the SendMessages logic. | ||||
nodestate->pindexBestHeaderSent = | nodestate->pindexBestHeaderSent = | ||||
pindex ? pindex : ::ChainActive().Tip(); | pindex ? pindex : ::ChainActive().Tip(); | ||||
connman->PushMessage(pfrom, | connman->PushMessage(pfrom, | ||||
msgMaker.Make(NetMsgType::HEADERS, vHeaders)); | msgMaker.Make(NetMsgType::HEADERS, vHeaders)); | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::TX) { | if (msg_type == NetMsgType::TX) { | ||||
// Stop processing the transaction early if | // Stop processing the transaction early if | ||||
// We are in blocks only mode and peer is either not whitelisted or | // We are in blocks only mode and peer is either not whitelisted or | ||||
// whitelistrelay is off or if this peer is supposed to be a | // whitelistrelay is off or if this peer is supposed to be a | ||||
// block-relay-only peer | // block-relay-only peer | ||||
if ((!g_relay_txes && !pfrom->HasPermission(PF_RELAY)) || | if ((!g_relay_txes && !pfrom->HasPermission(PF_RELAY)) || | ||||
(pfrom->m_tx_relay == nullptr)) { | (pfrom->m_tx_relay == nullptr)) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"transaction sent in violation of protocol peer=%d\n", | "transaction sent in violation of protocol peer=%d\n", | ||||
▲ Show 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | if (msg_type == 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(), state.ToString()); | tx.GetHash().ToString(), pfrom->GetId(), state.ToString()); | ||||
MaybePunishNodeForTx(pfrom->GetId(), state); | MaybePunishNodeForTx(pfrom->GetId(), state); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::CMPCTBLOCK) { | if (msg_type == NetMsgType::CMPCTBLOCK) { | ||||
// Ignore cmpctblock received while importing | // Ignore cmpctblock received while importing | ||||
if (fImporting || fReindex) { | if (fImporting || fReindex) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"Unexpected cmpctblock message received from peer %d\n", | "Unexpected cmpctblock message received from peer %d\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 256 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::CMPCTBLOCK) { | ||||
// that a malleated cmpctblock announcement can't be used to | // that a malleated cmpctblock announcement can't be used to | ||||
// interfere with block relay. | // interfere with block relay. | ||||
MarkBlockAsReceived(pblock->GetHash()); | MarkBlockAsReceived(pblock->GetHash()); | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::BLOCKTXN) { | if (msg_type == NetMsgType::BLOCKTXN) { | ||||
// Ignore blocktxn received while importing | // Ignore blocktxn received while importing | ||||
if (fImporting || fReindex) { | if (fImporting || fReindex) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"Unexpected blocktxn message received from peer %d\n", | "Unexpected blocktxn message received from peer %d\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::BLOCKTXN) { | ||||
} else { | } else { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
mapBlockSource.erase(pblock->GetHash()); | mapBlockSource.erase(pblock->GetHash()); | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::HEADERS) { | if (msg_type == NetMsgType::HEADERS) { | ||||
// Ignore headers received while importing | // Ignore headers received while importing | ||||
if (fImporting || fReindex) { | if (fImporting || fReindex) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"Unexpected headers message received from peer %d\n", | "Unexpected headers message received from peer %d\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
return true; | return true; | ||||
} | } | ||||
Show All 13 Lines | if (msg_type == NetMsgType::HEADERS) { | ||||
// Ignore tx count; assume it is 0. | // Ignore tx count; assume it is 0. | ||||
ReadCompactSize(vRecv); | ReadCompactSize(vRecv); | ||||
} | } | ||||
return ProcessHeadersMessage(config, pfrom, connman, headers, | return ProcessHeadersMessage(config, pfrom, connman, headers, | ||||
/*via_compact_block=*/false); | /*via_compact_block=*/false); | ||||
} | } | ||||
if (strCommand == NetMsgType::BLOCK) { | if (msg_type == NetMsgType::BLOCK) { | ||||
// Ignore block received while importing | // Ignore block received while importing | ||||
if (fImporting || fReindex) { | if (fImporting || fReindex) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"Unexpected block message received from peer %d\n", | "Unexpected block message received from peer %d\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
return true; | return true; | ||||
} | } | ||||
Show All 27 Lines | if (msg_type == NetMsgType::BLOCK) { | ||||
} else { | } else { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
mapBlockSource.erase(hash); | mapBlockSource.erase(hash); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
// Ignore avalanche requests while importing | // Ignore avalanche requests while importing | ||||
if (strCommand == NetMsgType::AVAPOLL && !fImporting && !fReindex && | if (msg_type == NetMsgType::AVAPOLL && !fImporting && !fReindex && | ||||
g_avalanche && | g_avalanche && | ||||
gArgs.GetBoolArg("-enableavalanche", AVALANCHE_DEFAULT_ENABLED)) { | gArgs.GetBoolArg("-enableavalanche", AVALANCHE_DEFAULT_ENABLED)) { | ||||
auto now = std::chrono::steady_clock::now(); | auto now = std::chrono::steady_clock::now(); | ||||
int64_t cooldown = | int64_t cooldown = | ||||
gArgs.GetArg("-avacooldown", AVALANCHE_DEFAULT_COOLDOWN); | gArgs.GetArg("-avacooldown", AVALANCHE_DEFAULT_COOLDOWN); | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::AVAPOLL && !fImporting && !fReindex && | ||||
// Send the query to the node. | // Send the query to the node. | ||||
g_avalanche->sendResponse( | g_avalanche->sendResponse( | ||||
pfrom, avalanche::Response(round, cooldown, std::move(votes))); | pfrom, avalanche::Response(round, cooldown, std::move(votes))); | ||||
return true; | return true; | ||||
} | } | ||||
// Ignore avalanche requests while importing | // Ignore avalanche requests while importing | ||||
if (strCommand == NetMsgType::AVARESPONSE && !fImporting && !fReindex && | if (msg_type == NetMsgType::AVARESPONSE && !fImporting && !fReindex && | ||||
g_avalanche && | g_avalanche && | ||||
gArgs.GetBoolArg("-enableavalanche", AVALANCHE_DEFAULT_ENABLED)) { | gArgs.GetBoolArg("-enableavalanche", AVALANCHE_DEFAULT_ENABLED)) { | ||||
// As long as QUIC is not implemented, we need to sign response and | // As long as QUIC is not implemented, we need to sign response and | ||||
// verify response's signatures in order to avoid any manipulation of | // verify response's signatures in order to avoid any manipulation of | ||||
// messages at the transport level. | // messages at the transport level. | ||||
CHashVerifier<CDataStream> verifier(&vRecv); | CHashVerifier<CDataStream> verifier(&vRecv); | ||||
avalanche::Response response; | avalanche::Response response; | ||||
verifier >> response; | verifier >> response; | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::AVARESPONSE && !fImporting && !fReindex && | ||||
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", | LogPrint(BCLog::NET, "failed to activate chain (%s)\n", | ||||
state.ToString()); | state.ToString()); | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::GETADDR) { | if (msg_type == NetMsgType::GETADDR) { | ||||
// This asymmetric behavior for inbound and outbound connections was | // This asymmetric behavior for inbound and outbound connections was | ||||
// introduced to prevent a fingerprinting attack: an attacker can send | // introduced to prevent a fingerprinting attack: an attacker can send | ||||
// specific fake addresses to users' AddrMan and later request them by | // specific fake addresses to users' AddrMan and later request them by | ||||
// sending getaddr messages. Making nodes which are behind NAT and can | // sending getaddr messages. Making nodes which are behind NAT and can | ||||
// only make outgoing connections ignore the getaddr message mitigates | // only make outgoing connections ignore the getaddr message mitigates | ||||
// the attack. | // the attack. | ||||
if (!pfrom->fInbound) { | if (!pfrom->fInbound) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
Show All 24 Lines | if (msg_type == NetMsgType::GETADDR) { | ||||
for (const CAddress &addr : vAddr) { | for (const CAddress &addr : vAddr) { | ||||
if (!banman->IsDiscouraged(addr) && !banman->IsBanned(addr)) { | if (!banman->IsDiscouraged(addr) && !banman->IsBanned(addr)) { | ||||
pfrom->PushAddress(addr, insecure_rand); | pfrom->PushAddress(addr, insecure_rand); | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::MEMPOOL) { | if (msg_type == NetMsgType::MEMPOOL) { | ||||
if (!(pfrom->GetLocalServices() & NODE_BLOOM) && | if (!(pfrom->GetLocalServices() & NODE_BLOOM) && | ||||
!pfrom->HasPermission(PF_MEMPOOL)) { | !pfrom->HasPermission(PF_MEMPOOL)) { | ||||
if (!pfrom->HasPermission(PF_NOBAN)) { | if (!pfrom->HasPermission(PF_NOBAN)) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"mempool request with bloom filters disabled, " | "mempool request with bloom filters disabled, " | ||||
"disconnect peer=%d\n", | "disconnect peer=%d\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
Show All 15 Lines | if (msg_type == NetMsgType::MEMPOOL) { | ||||
if (pfrom->m_tx_relay != nullptr) { | if (pfrom->m_tx_relay != nullptr) { | ||||
LOCK(pfrom->m_tx_relay->cs_tx_inventory); | LOCK(pfrom->m_tx_relay->cs_tx_inventory); | ||||
pfrom->m_tx_relay->fSendMempool = true; | pfrom->m_tx_relay->fSendMempool = true; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::PING) { | if (msg_type == NetMsgType::PING) { | ||||
if (pfrom->nVersion > BIP0031_VERSION) { | if (pfrom->nVersion > BIP0031_VERSION) { | ||||
uint64_t nonce = 0; | uint64_t nonce = 0; | ||||
vRecv >> nonce; | vRecv >> nonce; | ||||
// Echo the message back with the nonce. This allows for two useful | // Echo the message back with the nonce. This allows for two useful | ||||
// features: | // features: | ||||
// | // | ||||
// 1) A remote node can quickly check if the connection is | // 1) A remote node can quickly check if the connection is | ||||
// operational. | // operational. | ||||
// 2) Remote nodes can measure the latency of the network thread. If | // 2) Remote nodes can measure the latency of the network thread. If | ||||
// this node is overloaded it won't respond to pings quickly and the | // this node is overloaded it won't respond to pings quickly and the | ||||
// remote node can avoid sending us more work, like chain download | // remote node can avoid sending us more work, like chain download | ||||
// requests. | // requests. | ||||
// | // | ||||
// The nonce stops the remote getting confused between different | // The nonce stops the remote getting confused between different | ||||
// pings: without it, if the remote node sends a ping once per | // pings: without it, if the remote node sends a ping once per | ||||
// second and this node takes 5 seconds to respond to each, the 5th | // second and this node takes 5 seconds to respond to each, the 5th | ||||
// ping the remote sends would appear to return very quickly. | // ping the remote sends would appear to return very quickly. | ||||
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce)); | connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce)); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::PONG) { | if (msg_type == NetMsgType::PONG) { | ||||
int64_t pingUsecEnd = nTimeReceived; | int64_t pingUsecEnd = nTimeReceived; | ||||
uint64_t nonce = 0; | uint64_t nonce = 0; | ||||
size_t nAvail = vRecv.in_avail(); | size_t nAvail = vRecv.in_avail(); | ||||
bool bPingFinished = false; | bool bPingFinished = false; | ||||
std::string sProblem; | std::string sProblem; | ||||
if (nAvail >= sizeof(nonce)) { | if (nAvail >= sizeof(nonce)) { | ||||
vRecv >> nonce; | vRecv >> nonce; | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::PONG) { | ||||
nAvail); | nAvail); | ||||
} | } | ||||
if (bPingFinished) { | if (bPingFinished) { | ||||
pfrom->nPingNonceSent = 0; | pfrom->nPingNonceSent = 0; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::FILTERLOAD) { | if (msg_type == 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, 100, "oversized-bloom-filter"); | Misbehaving(pfrom, 100, "oversized-bloom-filter"); | ||||
} else if (pfrom->m_tx_relay != nullptr) { | } else if (pfrom->m_tx_relay != nullptr) { | ||||
LOCK(pfrom->m_tx_relay->cs_filter); | LOCK(pfrom->m_tx_relay->cs_filter); | ||||
pfrom->m_tx_relay->pfilter.reset(new CBloomFilter(filter)); | pfrom->m_tx_relay->pfilter.reset(new CBloomFilter(filter)); | ||||
pfrom->m_tx_relay->pfilter->UpdateEmptyFull(); | pfrom->m_tx_relay->pfilter->UpdateEmptyFull(); | ||||
pfrom->m_tx_relay->fRelayTxes = true; | pfrom->m_tx_relay->fRelayTxes = true; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::FILTERADD) { | if (msg_type == NetMsgType::FILTERADD) { | ||||
std::vector<uint8_t> vData; | std::vector<uint8_t> vData; | ||||
vRecv >> vData; | vRecv >> vData; | ||||
// Nodes must NEVER send a data item > 520 bytes (the max size for a | // Nodes must NEVER send a data item > 520 bytes (the max size for a | ||||
// script data object, and thus, the maximum size any matched object can | // script data object, and thus, the maximum size any matched object can | ||||
// have) in a filteradd message. | // have) in a filteradd message. | ||||
bool bad = false; | bool bad = false; | ||||
if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) { | if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) { | ||||
Show All 10 Lines | if (msg_type == NetMsgType::FILTERADD) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
// The structure of this code doesn't really allow for a good error | // The structure of this code doesn't really allow for a good error | ||||
// code. We'll go generic. | // code. We'll go generic. | ||||
Misbehaving(pfrom, 100, "invalid-filteradd"); | Misbehaving(pfrom, 100, "invalid-filteradd"); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::FILTERCLEAR) { | if (msg_type == NetMsgType::FILTERCLEAR) { | ||||
if (pfrom->m_tx_relay == nullptr) { | if (pfrom->m_tx_relay == nullptr) { | ||||
return true; | return true; | ||||
} | } | ||||
LOCK(pfrom->m_tx_relay->cs_filter); | LOCK(pfrom->m_tx_relay->cs_filter); | ||||
if (pfrom->GetLocalServices() & NODE_BLOOM) { | if (pfrom->GetLocalServices() & NODE_BLOOM) { | ||||
pfrom->m_tx_relay->pfilter.reset(new CBloomFilter()); | pfrom->m_tx_relay->pfilter.reset(new CBloomFilter()); | ||||
} | } | ||||
pfrom->m_tx_relay->fRelayTxes = true; | pfrom->m_tx_relay->fRelayTxes = true; | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::FEEFILTER) { | if (msg_type == NetMsgType::FEEFILTER) { | ||||
Amount newFeeFilter = Amount::zero(); | Amount newFeeFilter = Amount::zero(); | ||||
vRecv >> newFeeFilter; | vRecv >> newFeeFilter; | ||||
if (MoneyRange(newFeeFilter)) { | if (MoneyRange(newFeeFilter)) { | ||||
if (pfrom->m_tx_relay != nullptr) { | if (pfrom->m_tx_relay != nullptr) { | ||||
LOCK(pfrom->m_tx_relay->cs_feeFilter); | LOCK(pfrom->m_tx_relay->cs_feeFilter); | ||||
pfrom->m_tx_relay->minFeeFilter = newFeeFilter; | pfrom->m_tx_relay->minFeeFilter = newFeeFilter; | ||||
} | } | ||||
LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", | LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", | ||||
CFeeRate(newFeeFilter).ToString(), pfrom->GetId()); | CFeeRate(newFeeFilter).ToString(), pfrom->GetId()); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::NOTFOUND) { | if (msg_type == NetMsgType::NOTFOUND) { | ||||
// Remove the NOTFOUND transactions from the peer | // Remove the NOTFOUND transactions from the peer | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
CNodeState *state = State(pfrom->GetId()); | CNodeState *state = State(pfrom->GetId()); | ||||
std::vector<CInv> vInv; | std::vector<CInv> vInv; | ||||
vRecv >> vInv; | vRecv >> vInv; | ||||
if (vInv.size() <= | if (vInv.size() <= | ||||
MAX_PEER_TX_IN_FLIGHT + MAX_BLOCKS_IN_TRANSIT_PER_PEER) { | MAX_PEER_TX_IN_FLIGHT + MAX_BLOCKS_IN_TRANSIT_PER_PEER) { | ||||
for (CInv &inv : vInv) { | for (CInv &inv : vInv) { | ||||
Show All 14 Lines | if (msg_type == NetMsgType::NOTFOUND) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
// Ignore unknown commands for extensibility | // Ignore unknown commands for extensibility | ||||
LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", | LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", | ||||
SanitizeString(strCommand), pfrom->GetId()); | SanitizeString(msg_type), pfrom->GetId()); | ||||
return true; | return true; | ||||
} | } | ||||
bool PeerLogicValidation::CheckIfBanned(CNode *pnode) { | bool PeerLogicValidation::CheckIfBanned(CNode *pnode) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
CNodeState &state = *State(pnode->GetId()); | CNodeState &state = *State(pnode->GetId()); | ||||
if (state.m_should_discourage) { | if (state.m_should_discourage) { | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | bool PeerLogicValidation::ProcessMessages(const Config &config, CNode *pfrom, | ||||
} | } | ||||
// Check header | // Check header | ||||
if (!msg.m_valid_header) { | if (!msg.m_valid_header) { | ||||
LogPrint(BCLog::NET, "PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", | LogPrint(BCLog::NET, "PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", | ||||
SanitizeString(msg.m_command), pfrom->GetId()); | SanitizeString(msg.m_command), pfrom->GetId()); | ||||
return fMoreWork; | return fMoreWork; | ||||
} | } | ||||
const std::string &strCommand = msg.m_command; | const std::string &msg_type = msg.m_command; | ||||
// Message size | // Message size | ||||
unsigned int nMessageSize = msg.m_message_size; | unsigned int nMessageSize = msg.m_message_size; | ||||
// Checksum | // Checksum | ||||
CDataStream &vRecv = msg.m_recv; | CDataStream &vRecv = msg.m_recv; | ||||
if (!msg.m_valid_checksum) { | if (!msg.m_valid_checksum) { | ||||
LogPrint(BCLog::NET, "%s(%s, %u bytes): CHECKSUM ERROR peer=%d\n", | LogPrint(BCLog::NET, "%s(%s, %u bytes): CHECKSUM ERROR peer=%d\n", | ||||
__func__, SanitizeString(strCommand), nMessageSize, | __func__, SanitizeString(msg_type), nMessageSize, | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
if (m_banman) { | if (m_banman) { | ||||
m_banman->Discourage(pfrom->addr); | m_banman->Discourage(pfrom->addr); | ||||
} | } | ||||
connman->DisconnectNode(pfrom->addr); | connman->DisconnectNode(pfrom->addr); | ||||
return fMoreWork; | return fMoreWork; | ||||
} | } | ||||
// Process message | // Process message | ||||
bool fRet = false; | bool fRet = false; | ||||
try { | try { | ||||
fRet = ProcessMessage(config, pfrom, strCommand, vRecv, msg.m_time, | fRet = ProcessMessage(config, pfrom, msg_type, vRecv, msg.m_time, | ||||
connman, m_banman, interruptMsgProc); | connman, m_banman, interruptMsgProc); | ||||
if (interruptMsgProc) { | if (interruptMsgProc) { | ||||
return false; | return false; | ||||
} | } | ||||
if (!pfrom->vRecvGetData.empty()) { | if (!pfrom->vRecvGetData.empty()) { | ||||
fMoreWork = true; | fMoreWork = true; | ||||
} | } | ||||
} catch (const std::exception &e) { | } catch (const std::exception &e) { | ||||
LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' (%s) caught\n", | LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' (%s) caught\n", | ||||
__func__, SanitizeString(strCommand), nMessageSize, e.what(), | __func__, SanitizeString(msg_type), nMessageSize, e.what(), | ||||
typeid(e).name()); | typeid(e).name()); | ||||
} catch (...) { | } catch (...) { | ||||
LogPrint(BCLog::NET, "%s(%s, %u bytes): Unknown exception caught\n", | LogPrint(BCLog::NET, "%s(%s, %u bytes): Unknown exception caught\n", | ||||
__func__, SanitizeString(strCommand), nMessageSize); | __func__, SanitizeString(msg_type), nMessageSize); | ||||
} | } | ||||
if (!fRet) { | if (!fRet) { | ||||
LogPrint(BCLog::NET, "%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(msg_type), nMessageSize, pfrom->GetId()); | ||||
} | } | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
CheckIfBanned(pfrom); | CheckIfBanned(pfrom); | ||||
return fMoreWork; | return fMoreWork; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 933 Lines • Show Last 20 Lines |