mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-13 11:25:02 -05:00
![dergoegge](/assets/img/avatar_default.png)
The addresses of the iterator values are non-deterministic (i.e. they depend on where the values were allocated). This causes stability issues when fuzzing (e.g. in the `txorphan` and `mini_miner` harnesses), due the orders (derived from IteratorComparator) not being deterministic. Improve stability by comparing the first element in the iterator value pair instead of using the the value addresses.
113 lines
4.3 KiB
C++
113 lines
4.3 KiB
C++
// Copyright (c) 2021-2022 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#ifndef BITCOIN_TXORPHANAGE_H
|
|
#define BITCOIN_TXORPHANAGE_H
|
|
|
|
#include <net.h>
|
|
#include <primitives/block.h>
|
|
#include <primitives/transaction.h>
|
|
#include <sync.h>
|
|
#include <util/time.h>
|
|
|
|
#include <map>
|
|
#include <set>
|
|
|
|
/** A class to track orphan transactions (failed on TX_MISSING_INPUTS)
|
|
* Since we cannot distinguish orphans from bad transactions with
|
|
* non-existent inputs, we heavily limit the number of orphans
|
|
* we keep and the duration we keep them for.
|
|
*/
|
|
class TxOrphanage {
|
|
public:
|
|
/** Add a new orphan transaction */
|
|
bool AddTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
|
|
|
/** Check if we already have an orphan transaction (by wtxid only) */
|
|
bool HaveTx(const Wtxid& wtxid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
|
|
|
/** Extract a transaction from a peer's work set
|
|
* Returns nullptr if there are no transactions to work on.
|
|
* Otherwise returns the transaction reference, and removes
|
|
* it from the work set.
|
|
*/
|
|
CTransactionRef GetTxToReconsider(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
|
|
|
/** Erase an orphan by wtxid */
|
|
int EraseTx(const Wtxid& wtxid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
|
|
|
/** Erase all orphans announced by a peer (eg, after that peer disconnects) */
|
|
void EraseForPeer(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
|
|
|
/** Erase all orphans included in or invalidated by a new block */
|
|
void EraseForBlock(const CBlock& block) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
|
|
|
/** Limit the orphanage to the given maximum */
|
|
void LimitOrphans(unsigned int max_orphans, FastRandomContext& rng) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
|
|
|
/** Add any orphans that list a particular tx as a parent into the from peer's work set */
|
|
void AddChildrenToWorkSet(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);;
|
|
|
|
/** Does this peer have any work to do? */
|
|
bool HaveTxToReconsider(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);;
|
|
|
|
/** Get all children that spend from this tx and were received from nodeid. Sorted from most
|
|
* recent to least recent. */
|
|
std::vector<CTransactionRef> GetChildrenFromSamePeer(const CTransactionRef& parent, NodeId nodeid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
|
|
|
/** Get all children that spend from this tx but were not received from nodeid. Also return
|
|
* which peer provided each tx. */
|
|
std::vector<std::pair<CTransactionRef, NodeId>> GetChildrenFromDifferentPeer(const CTransactionRef& parent, NodeId nodeid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
|
|
|
/** Return how many entries exist in the orphange */
|
|
size_t Size() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
|
|
{
|
|
LOCK(m_mutex);
|
|
return m_orphans.size();
|
|
}
|
|
|
|
protected:
|
|
/** Guards orphan transactions */
|
|
mutable Mutex m_mutex;
|
|
|
|
struct OrphanTx {
|
|
CTransactionRef tx;
|
|
NodeId fromPeer;
|
|
NodeSeconds nTimeExpire;
|
|
size_t list_pos;
|
|
};
|
|
|
|
/** Map from wtxid to orphan transaction record. Limited by
|
|
* -maxorphantx/DEFAULT_MAX_ORPHAN_TRANSACTIONS */
|
|
std::map<Wtxid, OrphanTx> m_orphans GUARDED_BY(m_mutex);
|
|
|
|
/** Which peer provided the orphans that need to be reconsidered */
|
|
std::map<NodeId, std::set<Wtxid>> m_peer_work_set GUARDED_BY(m_mutex);
|
|
|
|
using OrphanMap = decltype(m_orphans);
|
|
|
|
struct IteratorComparator
|
|
{
|
|
template<typename I>
|
|
bool operator()(const I& a, const I& b) const
|
|
{
|
|
return a->first < b->first;
|
|
}
|
|
};
|
|
|
|
/** Index from the parents' COutPoint into the m_orphans. Used
|
|
* to remove orphan transactions from the m_orphans */
|
|
std::map<COutPoint, std::set<OrphanMap::iterator, IteratorComparator>> m_outpoint_to_orphan_it GUARDED_BY(m_mutex);
|
|
|
|
/** Orphan transactions in vector for quick random eviction */
|
|
std::vector<OrphanMap::iterator> m_orphan_list GUARDED_BY(m_mutex);
|
|
|
|
/** Erase an orphan by wtxid */
|
|
int EraseTxNoLock(const Wtxid& wtxid) EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
|
|
|
|
/** Timestamp for the next scheduled sweep of expired orphans */
|
|
NodeSeconds m_next_sweep GUARDED_BY(m_mutex){0s};
|
|
};
|
|
|
|
#endif // BITCOIN_TXORPHANAGE_H
|