15#include <boost/multi_index/indexed_by.hpp>
16#include <boost/multi_index/ordered_index.hpp>
17#include <boost/multi_index/tag.hpp>
18#include <boost/multi_index_container.hpp>
22#include <unordered_map>
67 return 1 + (
m_tx->vin.size() / 10);
85 using ByPeerView = std::tuple<NodeId, bool, SequenceNumber>;
95 boost::multi_index::ordered_unique<boost::multi_index::tag<ByWtxid>, WtxidExtractor>,
96 boost::multi_index::ordered_unique<boost::multi_index::tag<ByPeer>, ByPeerViewExtractor>
99 using AnnouncementMap = boost::multi_index::multi_index_container<Announcement, OrphanIndices>;
100 template<
typename Tag>
101 using Iter =
typename AnnouncementMap::index<Tag>::type::iterator;
175 template<
typename Tag>
254 const auto&
wtxid{it->m_tx->GetWitnessHash()};
255 for (
const auto& input : it->m_tx->vin) {
278 if (it == index.end())
return false;
279 if (std::next(it) != index.end() && std::next(it)->m_tx->GetWitnessHash() == it->m_tx->GetWitnessHash())
return false;
280 if (it != index.begin() && std::prev(it)->m_tx->GetWitnessHash() == it->m_tx->GetWitnessHash())
return false;
308 const auto&
wtxid{tx->GetWitnessHash()};
309 const auto& txid{tx->GetHash()};
331 for (
const auto& input : tx->vin) {
345 peer, txid.ToString(),
wtxid.ToString());
362 if (it->m_tx->GetWitnessHash() !=
wtxid)
return false;
365 const auto&
ptx = it->m_tx;
374 const auto& txid =
ptx->GetHash();
376 peer, txid.ToString(),
wtxid.ToString());
394 const auto txid = it->m_tx->GetHash();
420 if (it ==
index_by_peer.end() || it->m_announcer != peer)
return;
423 while (it !=
index_by_peer.end() && it->m_announcer == peer) {
464 static constexpr auto compare_score = [](
const auto& left,
const auto& right) {
465 if (left.second != right.second)
return left.second < right.second;
467 return left.first < right.first;
529 std::vector<std::pair<Wtxid, NodeId>>
ret;
531 for (
unsigned int i = 0; i < tx.
vout.size(); i++) {
550 if (!
Assume(it->m_tx->GetWitnessHash() ==
wtxid))
break;
554 Assume(!it->m_reconsider);
556 ret.emplace_back(
wtxid, it->m_announcer);
560 it->m_tx->GetHash().ToString(), it->m_tx->GetWitnessHash().ToString(), it->m_announcer);
590 if (it !=
m_orphans.get<
ByPeer>().end() && it->m_announcer == peer && it->m_reconsider) {
607 return it !=
m_orphans.get<
ByPeer>().end() && it->m_announcer == peer && it->m_reconsider;
619 for (
const auto& input :
block_tx.vin) {
662 for (
const auto& input :
it_upper->m_tx->vin) {
674 std::vector<TxOrphanage::OrphanInfo> result;
683 if (std::next(it) ==
index_by_wtxid.end() || std::next(it)->m_tx->GetWitnessHash() != it->m_tx->GetWitnessHash()) {
703 for (
const auto& input : it->m_tx->vin) {
706 unique_wtxids_to_scores.emplace(it->m_tx->GetWitnessHash(), std::make_pair(it->GetMemUsage(), it->GetLatencyScore() - 1));
709 peer_info.m_total_usage += it->GetMemUsage();
711 peer_info.m_total_latency_score += it->GetLatencyScore();
713 if (it->m_reconsider) {
777 return std::make_unique<TxOrphanageImpl>();
#define Assume(val)
Assume is the identity function.
std::vector< CTransactionRef > vtx
An outpoint - a combination of a transaction hash and an index n into its vout.
The basic transaction that is broadcasted on the network and contained in blocks.
const std::vector< CTxOut > vout
const Txid & GetHash() const LIFETIMEBOUND
I randrange(I range) noexcept
Generate a random integer in the range [0..range), with range > 0.
A class to track orphan transactions (failed on TX_MISSING_INPUTS) Since we cannot distinguish orphan...
typename AnnouncementMap::index< Tag >::type::iterator Iter
void EraseForBlock(const CBlock &block) override
Erase all orphans included in or invalidated by a new block.
boost::multi_index::multi_index_container< Announcement, OrphanIndices > AnnouncementMap
TxOrphanage::Usage MaxGlobalUsage() const override
Maximum allowed (deduplicated) memory usage for all transactions (see Announcement::GetMemUsage()).
void Erase(Iter< Tag > it)
Erase from m_orphans and update m_peer_orphanage_info.
TxOrphanage::Count m_unique_orphans
Number of unique orphans by wtxid.
bool AddAnnouncer(const Wtxid &wtxid, NodeId peer) override
Add an additional announcer to an orphan if it exists.
bool IsUnique(Iter< ByWtxid > it) const
Check if there is exactly one announcement with the same wtxid as it.
bool HaveTxToReconsider(NodeId peer) override
Return whether there is a tx that can be reconsidered.
bool AddTx(const CTransactionRef &tx, NodeId peer) override
Add a new orphan transaction.
CTransactionRef GetTx(const Wtxid &wtxid) const override
Get a transaction by its witness txid.
TxOrphanageImpl()=default
std::vector< std::pair< Wtxid, NodeId > > AddChildrenToWorkSet(const CTransaction &tx, FastRandomContext &rng) override
Add any orphans that list a particular tx as a parent into the from peer's work set.
TxOrphanageImpl(Count max_global_latency_score, Usage reserved_peer_usage)
bool HaveTxFromPeer(const Wtxid &wtxid, NodeId peer) const override
Check if a {tx, peer} exists in the orphanage.
TxOrphanage::Usage m_unique_orphan_usage
Memory used by orphans (see Announcement::GetMemUsage()), deduplicated by wtxid.
const TxOrphanage::Usage m_reserved_usage_per_peer
std::tuple< NodeId, bool, SequenceNumber > ByPeerView
SequenceNumber m_current_sequence
Global sequence number, increment each time an announcement is added.
TxOrphanage::Count m_unique_rounded_input_scores
The sum of each unique transaction's latency scores including the inputs only (see Announcement::GetL...
std::set< Wtxid > m_reconsiderable_wtxids
Set of Wtxids for which (exactly) one announcement with m_reconsider=true exists.
bool EraseTxInternal(const Wtxid &wtxid)
Erase by wtxid.
CTransactionRef GetTxToReconsider(NodeId peer) override
If there is a tx that can be reconsidered, return it and set it back to non-reconsiderable.
bool EraseTx(const Wtxid &wtxid) override
Erase an orphan by wtxid, including all announcements if there are multiple.
~TxOrphanageImpl() noexcept override=default
TxOrphanage::Count AnnouncementsFromPeer(NodeId peer) const override
Number of orphans stored from this peer.
TxOrphanage::Count MaxPeerLatencyScore() const override
Maximum allowed (deduplicated) latency score for all transactions (see Announcement::GetLatencyScore(...
void EraseForPeer(NodeId peer) override
Erase all entries by this peer.
AnnouncementMap m_orphans
std::unordered_map< NodeId, PeerDoSInfo > m_peer_orphanage_info
Store per-peer statistics.
bool HaveTx(const Wtxid &wtxid) const override
Check if we already have an orphan transaction (by wtxid only)
void LimitOrphans()
Limit the orphanage to MaxGlobalLatencyScore and MaxGlobalUsage.
TxOrphanage::Count TotalLatencyScore() const override
Get the total latency score of all orphans.
bool NeedsTrim() const
Check if the orphanage needs trimming.
std::unordered_map< COutPoint, std::set< Wtxid >, SaltedOutpointHasher > m_outpoint_to_orphan_wtxids
Index from the parents' outputs to wtxids that exist in m_orphans.
TxOrphanage::Count CountUniqueOrphans() const override
Number of unique orphans (by wtxid).
const TxOrphanage::Count m_max_global_latency_score
TxOrphanage::Count LatencyScoreFromPeer(NodeId peer) const override
Latency score of transactions announced by this peer.
TxOrphanage::Usage ReservedPeerUsage() const override
Get the reserved usage per peer.
TxOrphanage::Count CountAnnouncements() const override
Number of announcements, i.e.
TxOrphanage::Count MaxGlobalLatencyScore() const override
Get the maximum global latency score allowed.
std::vector< CTransactionRef > GetChildrenFromSamePeer(const CTransactionRef &parent, NodeId nodeid) const override
Get all children that spend from this tx and were received from nodeid.
TxOrphanage::Usage UsageByPeer(NodeId peer) const override
Total usage (weight) of orphans for which this peer is an announcer.
TxOrphanage::Usage TotalOrphanUsage() const override
Get the total usage (weight) of all orphans.
std::vector< OrphanInfo > GetOrphanTransactions() const override
Get all orphan transactions.
std::tuple< Wtxid, NodeId > ByWtxidView
void SanityCheck() const override
Check consistency between PeerOrphanInfo and m_orphans.
transaction_identifier represents the two canonical transaction identifier types (txid,...
static int32_t GetTransactionWeight(const CTransaction &tx)
#define LogDebug(category,...)
static constexpr NodeId MIN_PEER
Minimum NodeId for lower_bound lookups (in practice, NodeIds start at 0).
std::unique_ptr< TxOrphanage > MakeTxOrphanage() noexcept
Create a new TxOrphanage instance.
static constexpr unsigned int DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE
Default value for TxOrphanage::m_max_global_latency_score.
static constexpr int64_t DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER
Default value for TxOrphanage::m_reserved_usage_per_peer.
static constexpr NodeId MAX_PEER
Maximum NodeId for upper_bound lookups.
static constexpr int32_t MAX_STANDARD_TX_WEIGHT
The maximum weight for transactions we're willing to relay/mine.
std::shared_ptr< const CTransaction > CTransactionRef
Data structure storing a fee and size, ordered by increasing fee/size.
Allows providing orphan information externally.
const NodeId m_announcer
Which peer announced this tx.
TxOrphanage::Count GetLatencyScore() const
Get an approximation of how much this transaction contributes to latency in EraseForBlock and EraseFo...
const CTransactionRef m_tx
TxOrphanage::Usage GetMemUsage() const
Get an approximation for "memory usage".
bool m_reconsider
Whether this tx should be reconsidered.
const SequenceNumber m_entry_sequence
What order this transaction entered the orphanage.
Announcement(const CTransactionRef &tx, NodeId peer, SequenceNumber seq)
FeeFrac GetDosScore(TxOrphanage::Count max_peer_latency_score, TxOrphanage::Usage max_peer_memory) const
There are 2 DoS scores:
void Add(const Announcement &ann)
TxOrphanage::Usage m_total_usage
TxOrphanage::Count m_total_latency_score
TxOrphanage::Count m_count_announcements
bool operator==(const PeerDoSInfo &other) const
bool Subtract(const Announcement &ann)
consteval auto _(util::TranslatedLiteral str)
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.