|
|
@ -565,8 +565,8 @@ private:
|
|
|
|
bool MaybeDiscourageAndDisconnect(CNode& pnode, Peer& peer);
|
|
|
|
bool MaybeDiscourageAndDisconnect(CNode& pnode, Peer& peer);
|
|
|
|
|
|
|
|
|
|
|
|
struct PackageToValidate {
|
|
|
|
struct PackageToValidate {
|
|
|
|
const Package m_txns;
|
|
|
|
Package m_txns;
|
|
|
|
const std::vector<NodeId> m_senders;
|
|
|
|
std::vector<NodeId> m_senders;
|
|
|
|
/** Construct a 1-parent-1-child package. */
|
|
|
|
/** Construct a 1-parent-1-child package. */
|
|
|
|
explicit PackageToValidate(const CTransactionRef& parent,
|
|
|
|
explicit PackageToValidate(const CTransactionRef& parent,
|
|
|
|
const CTransactionRef& child,
|
|
|
|
const CTransactionRef& child,
|
|
|
@ -576,6 +576,16 @@ private:
|
|
|
|
m_senders {parent_sender, child_sender}
|
|
|
|
m_senders {parent_sender, child_sender}
|
|
|
|
{}
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Move ctor
|
|
|
|
|
|
|
|
PackageToValidate(PackageToValidate&& other) : m_txns{std::move(other.m_txns)}, m_senders{std::move(other.m_senders)} {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Move assignment
|
|
|
|
|
|
|
|
PackageToValidate& operator=(PackageToValidate&& other) {
|
|
|
|
|
|
|
|
this->m_txns = std::move(other.m_txns);
|
|
|
|
|
|
|
|
this->m_senders = std::move(other.m_senders);
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string ToString() const {
|
|
|
|
std::string ToString() const {
|
|
|
|
Assume(m_txns.size() == 2);
|
|
|
|
Assume(m_txns.size() == 2);
|
|
|
|
return strprintf("parent %s (wtxid=%s, sender=%d) + child %s (wtxid=%s, sender=%d)",
|
|
|
|
return strprintf("parent %s (wtxid=%s, sender=%d) + child %s (wtxid=%s, sender=%d)",
|
|
|
@ -589,11 +599,17 @@ private:
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** Handle a transaction whose result was not MempoolAcceptResult::ResultType::VALID.
|
|
|
|
/** Handle a transaction whose result was not MempoolAcceptResult::ResultType::VALID.
|
|
|
|
* @param[in] first_time_failure Whether this tx should be added to vExtraTxnForCompact.
|
|
|
|
* @param[in] first_time_failure Whether we should consider inserting into vExtraTxnForCompact, adding
|
|
|
|
|
|
|
|
* a new orphan to resolve, or looking for a package to submit.
|
|
|
|
|
|
|
|
* Set to true for transactions just received over p2p.
|
|
|
|
* Set to false if the tx has already been rejected before,
|
|
|
|
* Set to false if the tx has already been rejected before,
|
|
|
|
* e.g. is an orphan, to avoid adding duplicate entries.
|
|
|
|
* e.g. is already in the orphanage, to avoid adding duplicate entries.
|
|
|
|
* Updates m_txrequest, m_lazy_recent_rejects, m_lazy_recent_rejects_reconsiderable, m_orphanage, and vExtraTxnForCompact. */
|
|
|
|
* Updates m_txrequest, m_lazy_recent_rejects, m_lazy_recent_rejects_reconsiderable, m_orphanage, and vExtraTxnForCompact.
|
|
|
|
void ProcessInvalidTx(NodeId nodeid, const CTransactionRef& tx, const TxValidationState& result,
|
|
|
|
*
|
|
|
|
|
|
|
|
* @returns a PackageToValidate if this transaction has a reconsiderable failure and an eligible package was found,
|
|
|
|
|
|
|
|
* or std::nullopt otherwise.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
std::optional<PackageToValidate> ProcessInvalidTx(NodeId nodeid, const CTransactionRef& tx, const TxValidationState& result,
|
|
|
|
bool first_time_failure)
|
|
|
|
bool first_time_failure)
|
|
|
|
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, m_tx_download_mutex);
|
|
|
|
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, m_tx_download_mutex);
|
|
|
|
|
|
|
|
|
|
|
@ -2999,7 +3015,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx, const TxValidationState& state,
|
|
|
|
std::optional<PeerManagerImpl::PackageToValidate> PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx, const TxValidationState& state,
|
|
|
|
bool first_time_failure)
|
|
|
|
bool first_time_failure)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
AssertLockNotHeld(m_peer_mutex);
|
|
|
|
AssertLockNotHeld(m_peer_mutex);
|
|
|
@ -3017,6 +3033,8 @@ void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx
|
|
|
|
ptx->GetWitnessHash().ToString(),
|
|
|
|
ptx->GetWitnessHash().ToString(),
|
|
|
|
nodeid,
|
|
|
|
nodeid,
|
|
|
|
state.ToString());
|
|
|
|
state.ToString());
|
|
|
|
|
|
|
|
// Populated if failure is reconsiderable and eligible package is found.
|
|
|
|
|
|
|
|
std::optional<PackageToValidate> package_to_validate;
|
|
|
|
|
|
|
|
|
|
|
|
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
|
|
|
|
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
|
|
|
|
// Only process a new orphan if this is a first time failure, as otherwise it must be either
|
|
|
|
// Only process a new orphan if this is a first time failure, as otherwise it must be either
|
|
|
@ -3097,7 +3115,7 @@ void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx
|
|
|
|
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
|
|
|
|
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
return std::nullopt;
|
|
|
|
} else if (state.GetResult() != TxValidationResult::TX_WITNESS_STRIPPED) {
|
|
|
|
} else if (state.GetResult() != TxValidationResult::TX_WITNESS_STRIPPED) {
|
|
|
|
// We can add the wtxid of this transaction to our reject filter.
|
|
|
|
// We can add the wtxid of this transaction to our reject filter.
|
|
|
|
// Do not add txids of witness transactions or witness-stripped
|
|
|
|
// Do not add txids of witness transactions or witness-stripped
|
|
|
@ -3117,6 +3135,14 @@ void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx
|
|
|
|
// because we should not download or submit this transaction by itself again, but may
|
|
|
|
// because we should not download or submit this transaction by itself again, but may
|
|
|
|
// submit it as part of a package later.
|
|
|
|
// submit it as part of a package later.
|
|
|
|
RecentRejectsReconsiderableFilter().insert(ptx->GetWitnessHash().ToUint256());
|
|
|
|
RecentRejectsReconsiderableFilter().insert(ptx->GetWitnessHash().ToUint256());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (first_time_failure) {
|
|
|
|
|
|
|
|
// When a transaction fails for TX_RECONSIDERABLE, look for a matching child in the
|
|
|
|
|
|
|
|
// orphanage, as it is possible that they succeed as a package.
|
|
|
|
|
|
|
|
LogDebug(BCLog::TXPACKAGES, "tx %s (wtxid=%s) failed but reconsiderable, looking for child in orphanage\n",
|
|
|
|
|
|
|
|
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());
|
|
|
|
|
|
|
|
package_to_validate = Find1P1CPackage(ptx, nodeid);
|
|
|
|
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
RecentRejectsFilter().insert(ptx->GetWitnessHash().ToUint256());
|
|
|
|
RecentRejectsFilter().insert(ptx->GetWitnessHash().ToUint256());
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -3147,6 +3173,8 @@ void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx
|
|
|
|
if (Assume(state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) && m_orphanage.EraseTx(ptx->GetWitnessHash()) > 0) {
|
|
|
|
if (Assume(state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) && m_orphanage.EraseTx(ptx->GetWitnessHash()) > 0) {
|
|
|
|
LogDebug(BCLog::TXPACKAGES, " removed orphan tx %s (wtxid=%s)\n", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());
|
|
|
|
LogDebug(BCLog::TXPACKAGES, " removed orphan tx %s (wtxid=%s)\n", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return package_to_validate;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void PeerManagerImpl::ProcessValidTx(NodeId nodeid, const CTransactionRef& tx, const std::list<CTransactionRef>& replaced_transactions)
|
|
|
|
void PeerManagerImpl::ProcessValidTx(NodeId nodeid, const CTransactionRef& tx, const std::list<CTransactionRef>& replaced_transactions)
|
|
|
@ -4526,14 +4554,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
|
|
|
pfrom.m_last_tx_time = GetTime<std::chrono::seconds>();
|
|
|
|
pfrom.m_last_tx_time = GetTime<std::chrono::seconds>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (state.IsInvalid()) {
|
|
|
|
if (state.IsInvalid()) {
|
|
|
|
ProcessInvalidTx(pfrom.GetId(), ptx, state, /*first_time_failure=*/true);
|
|
|
|
if (auto package_to_validate{ProcessInvalidTx(pfrom.GetId(), ptx, state, /*first_time_failure=*/true)}) {
|
|
|
|
}
|
|
|
|
|
|
|
|
// When a transaction fails for TX_RECONSIDERABLE, look for a matching child in the
|
|
|
|
|
|
|
|
// orphanage, as it is possible that they succeed as a package.
|
|
|
|
|
|
|
|
if (state.GetResult() == TxValidationResult::TX_RECONSIDERABLE) {
|
|
|
|
|
|
|
|
LogDebug(BCLog::TXPACKAGES, "tx %s (wtxid=%s) failed but reconsiderable, looking for child in orphanage\n",
|
|
|
|
|
|
|
|
txid.ToString(), wtxid.ToString());
|
|
|
|
|
|
|
|
if (auto package_to_validate{Find1P1CPackage(ptx, pfrom.GetId())}) {
|
|
|
|
|
|
|
|
const auto package_result{ProcessNewPackage(m_chainman.ActiveChainstate(), m_mempool, package_to_validate->m_txns, /*test_accept=*/false, /*client_maxfeerate=*/std::nullopt)};
|
|
|
|
const auto package_result{ProcessNewPackage(m_chainman.ActiveChainstate(), m_mempool, package_to_validate->m_txns, /*test_accept=*/false, /*client_maxfeerate=*/std::nullopt)};
|
|
|
|
LogDebug(BCLog::TXPACKAGES, "package evaluation for %s: %s\n", package_to_validate->ToString(),
|
|
|
|
LogDebug(BCLog::TXPACKAGES, "package evaluation for %s: %s\n", package_to_validate->ToString(),
|
|
|
|
package_result.m_state.IsValid() ? "package accepted" : "package rejected");
|
|
|
|
package_result.m_state.IsValid() ? "package accepted" : "package rejected");
|
|
|
|