Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 1,729 Lines • ▼ Show 20 Lines | void PeerManager::BlockChecked(const CBlock &block, | ||||
} | } | ||||
} | } | ||||
////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////// | ||||
// | // | ||||
// Messages | // Messages | ||||
// | // | ||||
static bool AlreadyHave(const CInv &inv, const CTxMemPool &mempool) | static bool AlreadyHaveTx(const CInv &inv, const CTxMemPool &mempool) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
switch (inv.type) { | |||||
case MSG_TX: { | |||||
assert(recentRejects); | assert(recentRejects); | ||||
if (::ChainActive().Tip()->GetBlockHash() != | if (::ChainActive().Tip()->GetBlockHash() != hashRecentRejectsChainTip) { | ||||
hashRecentRejectsChainTip) { | |||||
// If the chain tip has changed previously rejected transactions | // If the chain tip has changed previously rejected transactions | ||||
// might be now valid, e.g. due to a nLockTime'd tx becoming | // might be now valid, e.g. due to a nLockTime'd tx becoming | ||||
// valid, or a double-spend. Reset the rejects filter and give | // valid, or a double-spend. Reset the rejects filter and give | ||||
// those txs a second chance. | // those txs a second chance. | ||||
hashRecentRejectsChainTip = | hashRecentRejectsChainTip = ::ChainActive().Tip()->GetBlockHash(); | ||||
::ChainActive().Tip()->GetBlockHash(); | |||||
recentRejects->reset(); | recentRejects->reset(); | ||||
} | } | ||||
const TxId txid(inv.hash); | const TxId txid(inv.hash); | ||||
{ | { | ||||
LOCK(g_cs_orphans); | LOCK(g_cs_orphans); | ||||
if (mapOrphanTransactions.count(txid)) { | if (mapOrphanTransactions.count(txid)) { | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
{ | { | ||||
LOCK(g_cs_recent_confirmed_transactions); | LOCK(g_cs_recent_confirmed_transactions); | ||||
if (g_recent_confirmed_transactions->contains(txid)) { | if (g_recent_confirmed_transactions->contains(txid)) { | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
return recentRejects->contains(txid) || mempool.exists(txid); | return recentRejects->contains(txid) || mempool.exists(txid); | ||||
} | } | ||||
case MSG_BLOCK: | |||||
static bool AlreadyHaveBlock(const CInv &inv, const CTxMemPool &mempool) | |||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | |||||
return LookupBlockIndex(BlockHash(inv.hash)) != nullptr; | return LookupBlockIndex(BlockHash(inv.hash)) != nullptr; | ||||
} | } | ||||
// Don't know what it is, just say we already got one | |||||
return true; | |||||
} | |||||
void RelayTransaction(const TxId &txid, const CConnman &connman) { | void RelayTransaction(const TxId &txid, const CConnman &connman) { | ||||
connman.ForEachNode( | connman.ForEachNode( | ||||
[&txid](CNode *pnode) { pnode->PushTxInventory(txid); }); | [&txid](CNode *pnode) { pnode->PushTxInventory(txid); }); | ||||
} | } | ||||
static void RelayAddress(const CAddress &addr, bool fReachable, | static void RelayAddress(const CAddress &addr, bool fReachable, | ||||
const CConnman &connman) { | const CConnman &connman) { | ||||
▲ Show 20 Lines • Show All 1,332 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::INV) { | ||||
const auto current_time = GetTime<std::chrono::microseconds>(); | const auto current_time = GetTime<std::chrono::microseconds>(); | ||||
std::optional<BlockHash> best_block; | std::optional<BlockHash> best_block; | ||||
for (CInv &inv : vInv) { | for (CInv &inv : vInv) { | ||||
if (interruptMsgProc) { | if (interruptMsgProc) { | ||||
return; | return; | ||||
} | } | ||||
bool fAlreadyHave = AlreadyHave(inv, m_mempool); | |||||
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), | |||||
fAlreadyHave ? "have" : "new", pfrom.GetId()); | |||||
if (inv.type == MSG_BLOCK) { | if (inv.type == MSG_BLOCK) { | ||||
bool fAlreadyHave = AlreadyHaveBlock(inv, m_mempool); | |||||
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", | |||||
inv.ToString(), fAlreadyHave ? "have" : "new", | |||||
pfrom.GetId()); | |||||
const BlockHash hash{inv.hash}; | const BlockHash hash{inv.hash}; | ||||
UpdateBlockAvailability(pfrom.GetId(), hash); | UpdateBlockAvailability(pfrom.GetId(), hash); | ||||
if (!fAlreadyHave && !fImporting && !fReindex && | if (!fAlreadyHave && !fImporting && !fReindex && | ||||
!mapBlocksInFlight.count(hash)) { | !mapBlocksInFlight.count(hash)) { | ||||
// Headers-first is the primary method of announcement on | // Headers-first is the primary method of announcement on | ||||
// the network. If a node fell back to sending blocks by | // the network. If a node fell back to sending blocks by | ||||
// inv, it's probably for a re-org. The final block hash | // inv, it's probably for a re-org. The final block hash | ||||
// provided should be the highest, so send a getheaders and | // provided should be the highest, so send a getheaders and | ||||
// then fetch the blocks we need to catch up. | // then fetch the blocks we need to catch up. | ||||
best_block = std::move(hash); | best_block = std::move(hash); | ||||
} | } | ||||
} else { | } else { | ||||
bool fAlreadyHave = AlreadyHaveTx(inv, m_mempool); | |||||
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", | |||||
inv.ToString(), fAlreadyHave ? "have" : "new", | |||||
pfrom.GetId()); | |||||
const TxId txid(inv.hash); | const TxId txid(inv.hash); | ||||
pfrom.AddKnownTx(txid); | pfrom.AddKnownTx(txid); | ||||
if (fBlocksOnly) { | if (fBlocksOnly) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"transaction (%s) inv sent in violation of " | "transaction (%s) inv sent in violation of " | ||||
"protocol, disconnecting peer=%d\n", | "protocol, disconnecting peer=%d\n", | ||||
txid.ToString(), pfrom.GetId()); | txid.ToString(), pfrom.GetId()); | ||||
pfrom.fDisconnect = true; | pfrom.fDisconnect = true; | ||||
▲ Show 20 Lines • Show All 287 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::TX) { | ||||
TxValidationState state; | TxValidationState state; | ||||
CNodeState *nodestate = State(pfrom.GetId()); | CNodeState *nodestate = State(pfrom.GetId()); | ||||
nodestate->m_tx_download.m_tx_announced.erase(txid); | nodestate->m_tx_download.m_tx_announced.erase(txid); | ||||
nodestate->m_tx_download.m_tx_in_flight.erase(txid); | nodestate->m_tx_download.m_tx_in_flight.erase(txid); | ||||
EraseTxRequest(txid); | EraseTxRequest(txid); | ||||
if (!AlreadyHave(CInv(MSG_TX, txid), m_mempool) && | if (!AlreadyHaveTx(CInv(MSG_TX, txid), m_mempool) && | ||||
AcceptToMemoryPool(config, m_mempool, state, ptx, | AcceptToMemoryPool(config, m_mempool, state, ptx, | ||||
false /* bypass_limits */, | false /* bypass_limits */, | ||||
Amount::zero() /* nAbsurdFee */)) { | Amount::zero() /* nAbsurdFee */)) { | ||||
m_mempool.check(&::ChainstateActive().CoinsTip()); | m_mempool.check(&::ChainstateActive().CoinsTip()); | ||||
RelayTransaction(tx.GetId(), m_connman); | RelayTransaction(tx.GetId(), m_connman); | ||||
for (size_t i = 0; i < tx.vout.size(); i++) { | for (size_t i = 0; i < tx.vout.size(); i++) { | ||||
auto it_by_prev = | auto it_by_prev = | ||||
mapOrphanTransactionsByPrev.find(COutPoint(txid, i)); | mapOrphanTransactionsByPrev.find(COutPoint(txid, i)); | ||||
Show All 27 Lines | if (msg_type == NetMsgType::TX) { | ||||
} | } | ||||
if (!fRejectedParents) { | if (!fRejectedParents) { | ||||
const auto current_time = GetTime<std::chrono::microseconds>(); | const auto current_time = GetTime<std::chrono::microseconds>(); | ||||
for (const CTxIn &txin : tx.vin) { | for (const CTxIn &txin : tx.vin) { | ||||
// FIXME: MSG_TX should use a TxHash, not a TxId. | // FIXME: MSG_TX should use a TxHash, not a TxId. | ||||
const TxId _txid = txin.prevout.GetTxId(); | const TxId _txid = txin.prevout.GetTxId(); | ||||
pfrom.AddKnownTx(_txid); | pfrom.AddKnownTx(_txid); | ||||
if (!AlreadyHave(CInv(MSG_TX, _txid), m_mempool)) { | if (!AlreadyHaveTx(CInv(MSG_TX, _txid), m_mempool)) { | ||||
RequestTx(State(pfrom.GetId()), _txid, current_time); | RequestTx(State(pfrom.GetId()), _txid, current_time); | ||||
} | } | ||||
} | } | ||||
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 (see CVE-2012-3789) | // unbounded (see CVE-2012-3789) | ||||
unsigned int nMaxOrphanTx = (unsigned int)std::max( | unsigned int nMaxOrphanTx = (unsigned int)std::max( | ||||
▲ Show 20 Lines • Show All 2,006 Lines • ▼ Show 20 Lines | if (pingSend) { | ||||
tx_process_time.begin()->first <= current_time && | tx_process_time.begin()->first <= current_time && | ||||
state.m_tx_download.m_tx_in_flight.size() < | state.m_tx_download.m_tx_in_flight.size() < | ||||
MAX_PEER_TX_IN_FLIGHT) { | MAX_PEER_TX_IN_FLIGHT) { | ||||
const TxId txid = tx_process_time.begin()->second; | const TxId txid = tx_process_time.begin()->second; | ||||
// Erase this entry from tx_process_time (it may be added back for | // Erase this entry from tx_process_time (it may be added back for | ||||
// processing at a later time, see below) | // processing at a later time, see below) | ||||
tx_process_time.erase(tx_process_time.begin()); | tx_process_time.erase(tx_process_time.begin()); | ||||
CInv inv(MSG_TX, txid); | CInv inv(MSG_TX, txid); | ||||
if (!AlreadyHave(inv, m_mempool)) { | if (!AlreadyHaveTx(inv, m_mempool)) { | ||||
// If this transaction was last requested more than 1 minute | // If this transaction was last requested more than 1 minute | ||||
// ago, then request. | // ago, then request. | ||||
const auto last_request_time = GetTxRequestTime(txid); | const auto last_request_time = GetTxRequestTime(txid); | ||||
if (last_request_time <= current_time - GETDATA_TX_INTERVAL) { | if (last_request_time <= current_time - GETDATA_TX_INTERVAL) { | ||||
LogPrint(BCLog::NET, "Requesting %s peer=%d\n", | LogPrint(BCLog::NET, "Requesting %s peer=%d\n", | ||||
inv.ToString(), pto->GetId()); | inv.ToString(), pto->GetId()); | ||||
vGetData.push_back(inv); | vGetData.push_back(inv); | ||||
if (vGetData.size() >= MAX_GETDATA_SZ) { | if (vGetData.size() >= MAX_GETDATA_SZ) { | ||||
▲ Show 20 Lines • Show All 100 Lines • Show Last 20 Lines |