mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-12-13 14:14:00 +01:00
[refactor] move Find1P1CPackage to txdownload
Move-only.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#define BITCOIN_NODE_TXDOWNLOADMAN_H
|
||||
|
||||
#include <net.h>
|
||||
#include <policy/packages.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
@@ -38,6 +39,8 @@ static constexpr auto GETDATA_TX_INTERVAL{60s};
|
||||
struct TxDownloadOptions {
|
||||
/** Read-only reference to mempool. */
|
||||
const CTxMemPool& m_mempool;
|
||||
/** RNG provided by caller. */
|
||||
FastRandomContext& m_rng;
|
||||
};
|
||||
struct TxDownloadConnectionInfo {
|
||||
/** Whether this peer is preferred for transaction download. */
|
||||
@@ -47,6 +50,39 @@ struct TxDownloadConnectionInfo {
|
||||
/** Whether this peer supports wtxid relay. */
|
||||
const bool m_wtxid_relay;
|
||||
};
|
||||
struct PackageToValidate {
|
||||
Package m_txns;
|
||||
std::vector<NodeId> m_senders;
|
||||
/** Construct a 1-parent-1-child package. */
|
||||
explicit PackageToValidate(const CTransactionRef& parent,
|
||||
const CTransactionRef& child,
|
||||
NodeId parent_sender,
|
||||
NodeId child_sender) :
|
||||
m_txns{parent, child},
|
||||
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 {
|
||||
Assume(m_txns.size() == 2);
|
||||
return strprintf("parent %s (wtxid=%s, sender=%d) + child %s (wtxid=%s, sender=%d)",
|
||||
m_txns.front()->GetHash().ToString(),
|
||||
m_txns.front()->GetWitnessHash().ToString(),
|
||||
m_senders.front(),
|
||||
m_txns.back()->GetHash().ToString(),
|
||||
m_txns.back()->GetWitnessHash().ToString(),
|
||||
m_senders.back());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Class responsible for deciding what transactions to request and, once
|
||||
@@ -111,6 +147,11 @@ public:
|
||||
|
||||
/** Should be called when a notfound for a tx has been received. */
|
||||
void ReceivedNotFound(NodeId nodeid, const std::vector<uint256>& txhashes);
|
||||
|
||||
/** Look for a child of this transaction in the orphanage to form a 1-parent-1-child package,
|
||||
* skipping any combinations that have already been tried. Return the resulting package along with
|
||||
* the senders of its respective transactions, or std::nullopt if no package is found. */
|
||||
std::optional<PackageToValidate> Find1P1CPackage(const CTransactionRef& ptx, NodeId nodeid);
|
||||
};
|
||||
} // namespace node
|
||||
#endif // BITCOIN_NODE_TXDOWNLOADMAN_H
|
||||
|
||||
@@ -71,6 +71,10 @@ void TxDownloadManager::ReceivedNotFound(NodeId nodeid, const std::vector<uint25
|
||||
{
|
||||
m_impl->ReceivedNotFound(nodeid, txhashes);
|
||||
}
|
||||
std::optional<PackageToValidate> TxDownloadManager::Find1P1CPackage(const CTransactionRef& ptx, NodeId nodeid)
|
||||
{
|
||||
return m_impl->Find1P1CPackage(ptx, nodeid);
|
||||
}
|
||||
|
||||
// TxDownloadManagerImpl
|
||||
void TxDownloadManagerImpl::ActiveTipChange()
|
||||
@@ -218,4 +222,54 @@ void TxDownloadManagerImpl::ReceivedNotFound(NodeId nodeid, const std::vector<ui
|
||||
m_txrequest.ReceivedResponse(nodeid, txhash);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<PackageToValidate> TxDownloadManagerImpl::Find1P1CPackage(const CTransactionRef& ptx, NodeId nodeid)
|
||||
{
|
||||
const auto& parent_wtxid{ptx->GetWitnessHash()};
|
||||
|
||||
Assume(RecentRejectsReconsiderableFilter().contains(parent_wtxid.ToUint256()));
|
||||
|
||||
// Prefer children from this peer. This helps prevent censorship attempts in which an attacker
|
||||
// sends lots of fake children for the parent, and we (unluckily) keep selecting the fake
|
||||
// children instead of the real one provided by the honest peer.
|
||||
const auto cpfp_candidates_same_peer{m_orphanage.GetChildrenFromSamePeer(ptx, nodeid)};
|
||||
|
||||
// These children should be sorted from newest to oldest. In the (probably uncommon) case
|
||||
// of children that replace each other, this helps us accept the highest feerate (probably the
|
||||
// most recent) one efficiently.
|
||||
for (const auto& child : cpfp_candidates_same_peer) {
|
||||
Package maybe_cpfp_package{ptx, child};
|
||||
if (!RecentRejectsReconsiderableFilter().contains(GetPackageHash(maybe_cpfp_package))) {
|
||||
return PackageToValidate{ptx, child, nodeid, nodeid};
|
||||
}
|
||||
}
|
||||
|
||||
// If no suitable candidate from the same peer is found, also try children that were provided by
|
||||
// a different peer. This is useful because sometimes multiple peers announce both transactions
|
||||
// to us, and we happen to download them from different peers (we wouldn't have known that these
|
||||
// 2 transactions are related). We still want to find 1p1c packages then.
|
||||
//
|
||||
// If we start tracking all announcers of orphans, we can restrict this logic to parent + child
|
||||
// pairs in which both were provided by the same peer, i.e. delete this step.
|
||||
const auto cpfp_candidates_different_peer{m_orphanage.GetChildrenFromDifferentPeer(ptx, nodeid)};
|
||||
|
||||
// Find the first 1p1c that hasn't already been rejected. We randomize the order to not
|
||||
// create a bias that attackers can use to delay package acceptance.
|
||||
//
|
||||
// Create a random permutation of the indices.
|
||||
std::vector<size_t> tx_indices(cpfp_candidates_different_peer.size());
|
||||
std::iota(tx_indices.begin(), tx_indices.end(), 0);
|
||||
std::shuffle(tx_indices.begin(), tx_indices.end(), m_opts.m_rng);
|
||||
|
||||
for (const auto index : tx_indices) {
|
||||
// If we already tried a package and failed for any reason, the combined hash was
|
||||
// cached in m_lazy_recent_rejects_reconsiderable.
|
||||
const auto [child_tx, child_sender] = cpfp_candidates_different_peer.at(index);
|
||||
Package maybe_cpfp_package{ptx, child_tx};
|
||||
if (!RecentRejectsReconsiderableFilter().contains(GetPackageHash(maybe_cpfp_package))) {
|
||||
return PackageToValidate{ptx, child_tx, nodeid, child_sender};
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
} // namespace node
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <kernel/chain.h>
|
||||
#include <net.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <policy/packages.h>
|
||||
#include <txorphanage.h>
|
||||
#include <txrequest.h>
|
||||
|
||||
@@ -159,6 +160,8 @@ public:
|
||||
|
||||
/** Marks a tx as ReceivedResponse in txrequest. */
|
||||
void ReceivedNotFound(NodeId nodeid, const std::vector<uint256>& txhashes);
|
||||
|
||||
std::optional<PackageToValidate> Find1P1CPackage(const CTransactionRef& ptx, NodeId nodeid);
|
||||
};
|
||||
} // namespace node
|
||||
#endif // BITCOIN_NODE_TXDOWNLOADMAN_IMPL_H
|
||||
|
||||
Reference in New Issue
Block a user