Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
Show First 20 Lines • Show All 4,120 Lines • ▼ Show 20 Lines | void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, | ||||
LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", | LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", | ||||
txid.ToString(), nodeid, state.ToString()); | txid.ToString(), nodeid, state.ToString()); | ||||
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { | if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { | ||||
return; | return; | ||||
} | } | ||||
if (m_avalanche && m_avalanche->m_preConsensus && | |||||
state.GetResult() == TxValidationResult::TX_AVALANCHE_RECONSIDERABLE) { | |||||
return; | |||||
} | |||||
if (state.GetResult() == TxValidationResult::TX_PACKAGE_RECONSIDERABLE) { | if (state.GetResult() == TxValidationResult::TX_PACKAGE_RECONSIDERABLE) { | ||||
// If the result is TX_PACKAGE_RECONSIDERABLE, add it to | // If the result is TX_PACKAGE_RECONSIDERABLE, add it to | ||||
// m_recent_rejects_package_reconsiderable because we should not | // m_recent_rejects_package_reconsiderable because we should not | ||||
// download or submit this transaction by itself again, but may submit | // download or submit this transaction by itself again, but may submit | ||||
// it as part of a package later. | // it as part of a package later. | ||||
m_recent_rejects_package_reconsiderable.insert(txid); | m_recent_rejects_package_reconsiderable.insert(txid); | ||||
} else { | } else { | ||||
m_recent_rejects.insert(txid); | m_recent_rejects.insert(txid); | ||||
▲ Show 20 Lines • Show All 1,672 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::TX) { | ||||
package_result.m_state.ToString()); | package_result.m_state.ToString()); | ||||
ProcessPackageResult(package_to_validate.value(), | ProcessPackageResult(package_to_validate.value(), | ||||
package_result); | package_result); | ||||
} | } | ||||
} | } | ||||
if (state.GetResult() == | if (state.GetResult() == | ||||
TxValidationResult::TX_AVALANCHE_RECONSIDERABLE) { | TxValidationResult::TX_AVALANCHE_RECONSIDERABLE) { | ||||
// Once added to the conflicting pool, a tx is considered | |||||
// AlreadyHave, and we shouldn't request it anymore. | |||||
m_txrequest.ForgetInvId(tx.GetId()); | |||||
unsigned int nEvicted{0}; | unsigned int nEvicted{0}; | ||||
bool haveConflictingTx{false}; | |||||
// NO_THREAD_SAFETY_ANALYSIS because of g_msgproc_mutex required in | // NO_THREAD_SAFETY_ANALYSIS because of g_msgproc_mutex required in | ||||
// the lambda for m_rng | // the lambda for m_rng | ||||
m_mempool.withConflicting( | m_mempool.withConflicting( | ||||
[&](TxConflicting &conflicting) NO_THREAD_SAFETY_ANALYSIS { | [&](TxConflicting &conflicting) NO_THREAD_SAFETY_ANALYSIS { | ||||
conflicting.AddTx(ptx, pfrom.GetId()); | conflicting.AddTx(ptx, pfrom.GetId()); | ||||
nEvicted = | nEvicted = | ||||
conflicting.LimitTxs(m_opts.max_conflicting_txs, m_rng); | conflicting.LimitTxs(m_opts.max_conflicting_txs, m_rng); | ||||
haveConflictingTx = conflicting.HaveTx(ptx->GetId()); | |||||
}); | }); | ||||
if (nEvicted > 0) { | if (nEvicted > 0) { | ||||
LogPrint(BCLog::TXPACKAGES, | LogPrint(BCLog::TXPACKAGES, | ||||
"conflicting pool overflow, removed %u tx\n", | "conflicting pool overflow, removed %u tx\n", | ||||
nEvicted); | nEvicted); | ||||
} | } | ||||
if (m_avalanche && m_avalanche->m_preConsensus && | |||||
haveConflictingTx) { | |||||
m_avalanche->addToReconcile(ptx); | |||||
} | |||||
} | } | ||||
return; | return; | ||||
} | } | ||||
if (msg_type == NetMsgType::CMPCTBLOCK) { | if (msg_type == NetMsgType::CMPCTBLOCK) { | ||||
// Ignore cmpctblock received while importing | // Ignore cmpctblock received while importing | ||||
if (m_chainman.m_blockman.LoadingBlocks()) { | if (m_chainman.m_blockman.LoadingBlocks()) { | ||||
▲ Show 20 Lines • Show All 867 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::AVARESPONSE) { | ||||
if (auto pitem = std::get_if<const CTransactionRef>(&item)) { | if (auto pitem = std::get_if<const CTransactionRef>(&item)) { | ||||
const CTransactionRef tx = *pitem; | const CTransactionRef tx = *pitem; | ||||
assert(tx != nullptr); | assert(tx != nullptr); | ||||
const TxId &txid = tx->GetId(); | const TxId &txid = tx->GetId(); | ||||
logVoteUpdate(u, "tx", txid); | logVoteUpdate(u, "tx", txid); | ||||
switch (u.getStatus()) { | switch (u.getStatus()) { | ||||
case avalanche::VoteStatus::Rejected: | case avalanche::VoteStatus::Rejected: { | ||||
break; | |||||
case avalanche::VoteStatus::Invalid: { | |||||
// Remove from the mempool and the finalized tree, as | // Remove from the mempool and the finalized tree, as | ||||
// well as all the children txs. | // well as all the children txs. Note that removal from | ||||
// FIXME Remember the tx has been invalidated so we | // the finalized tree is only a safety net and should | ||||
// don't poll for it again and again. | // never happen. | ||||
LOCK(m_mempool.cs); | LOCK2(cs_main, m_mempool.cs); | ||||
auto it = m_mempool.GetIter(txid); | if (m_mempool.exists(txid)) { | ||||
if (it.has_value()) { | |||||
m_mempool.removeRecursive( | m_mempool.removeRecursive( | ||||
*tx, MemPoolRemovalReason::AVALANCHE); | *tx, MemPoolRemovalReason::AVALANCHE); | ||||
std::vector<CTransactionRef> conflictingTxs = | |||||
m_mempool.withConflicting( | |||||
[&tx](const TxConflicting &conflicting) { | |||||
return conflicting.GetConflictTxs(tx); | |||||
}); | |||||
if (conflictingTxs.size() > 0) { | |||||
// Pull the first tx only, erase the others so | |||||
// they can be re-downloaded if needed. | |||||
auto result = m_chainman.ProcessTransaction( | |||||
conflictingTxs[0]); | |||||
assert(result.m_state.IsValid()); | |||||
} | |||||
m_mempool.withConflicting( | |||||
[&conflictingTxs, | |||||
&tx](TxConflicting &conflicting) { | |||||
for (const auto &conflictingTx : | |||||
conflictingTxs) { | |||||
conflicting.EraseTx( | |||||
conflictingTx->GetId()); | |||||
} | |||||
// Note that we don't store the descendants, | |||||
// which should be re-downloaded. This could | |||||
// be optimized but we will have to manage | |||||
// the topological ordering. | |||||
conflicting.AddTx(tx, NO_NODE); | |||||
}); | |||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case avalanche::VoteStatus::Accepted: | case avalanche::VoteStatus::Invalid: { | ||||
m_mempool.withConflicting( | |||||
[&txid](TxConflicting &conflicting) { | |||||
conflicting.EraseTx(txid); | |||||
}); | |||||
WITH_LOCK(cs_main, m_recent_rejects.insert(txid)); | |||||
break; | break; | ||||
case avalanche::VoteStatus::Finalized: { | } | ||||
LOCK(m_mempool.cs); | case avalanche::VoteStatus::Finalized: | ||||
// fallthrough | |||||
case avalanche::VoteStatus::Accepted: { | |||||
{ | |||||
LOCK2(cs_main, m_mempool.cs); | |||||
if (m_mempool.withConflicting( | |||||
[&txid](const TxConflicting &conflicting) { | |||||
return conflicting.HaveTx(txid); | |||||
})) { | |||||
// Swap conflicting txs from/to the mempool | |||||
std::vector<CTransactionRef> | |||||
mempool_conflicting_txs; | |||||
for (const auto &txin : tx->vin) { | |||||
// Find the conflicting txs | |||||
if (CTransactionRef conflict = | |||||
m_mempool.GetConflictTx( | |||||
txin.prevout)) { | |||||
mempool_conflicting_txs.push_back( | |||||
std::move(conflict)); | |||||
} | |||||
} | |||||
m_mempool.removeConflicts(*tx); | |||||
auto result = m_chainman.ProcessTransaction(tx); | |||||
assert(result.m_state.IsValid()); | |||||
m_mempool.withConflicting( | |||||
[&txid, &mempool_conflicting_txs]( | |||||
TxConflicting &conflicting) { | |||||
conflicting.EraseTx(txid); | |||||
// Store the first tx only, the others | |||||
// can be re-downloaded if needed. | |||||
if (mempool_conflicting_txs.size() > | |||||
0) { | |||||
conflicting.AddTx( | |||||
mempool_conflicting_txs[0], | |||||
NO_NODE); | |||||
} | |||||
}); | |||||
} | |||||
} | |||||
if (u.getStatus() == avalanche::VoteStatus::Finalized) { | |||||
LOCK2(cs_main, m_mempool.cs); | |||||
auto it = m_mempool.GetIter(txid); | auto it = m_mempool.GetIter(txid); | ||||
if (!it.has_value()) { | if (!it.has_value()) { | ||||
LogPrint(BCLog::AVALANCHE, | LogPrint( | ||||
BCLog::AVALANCHE, | |||||
"Error: finalized tx (%s) is not in the " | "Error: finalized tx (%s) is not in the " | ||||
"mempool\n", | "mempool\n", | ||||
txid.ToString()); | txid.ToString()); | ||||
break; | break; | ||||
} | } | ||||
m_mempool.setAvalancheFinalized(**it); | m_mempool.setAvalancheFinalized(**it); | ||||
// NO_THREAD_SAFETY_ANALYSIS because | |||||
// m_recent_rejects requires cs_main in the lambda | |||||
m_mempool.withConflicting( | |||||
[&](TxConflicting &conflicting) | |||||
NO_THREAD_SAFETY_ANALYSIS { | |||||
std::vector<CTransactionRef> | |||||
conflictingTxs = | |||||
conflicting.GetConflictTxs(tx); | |||||
for (const auto &conflictingTx : | |||||
conflictingTxs) { | |||||
m_recent_rejects.insert( | |||||
conflictingTx->GetId()); | |||||
conflicting.EraseTx( | |||||
conflictingTx->GetId()); | |||||
} | |||||
}); | |||||
} | |||||
break; | break; | ||||
} | } | ||||
case avalanche::VoteStatus::Stale: | case avalanche::VoteStatus::Stale: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,064 Lines • Show Last 20 Lines |