23 const TxId &txid = tx->GetId();
24 if (m_orphans.count(txid)) {
34 unsigned int sz = tx->GetTotalSize();
37 "ignoring large orphan tx (size: %u, hash: %s)\n", sz,
42 auto ret = m_orphans.emplace(
44 m_orphan_list.size()});
46 m_orphan_list.push_back(ret.first);
47 for (
const CTxIn &txin : tx->vin) {
48 m_outpoint_to_orphan_it[txin.
prevout].insert(ret.first);
52 txid.
ToString(), m_orphans.size(), m_outpoint_to_orphan_it.size());
58 std::map<TxId, OrphanTx>::iterator it = m_orphans.find(txid);
59 if (it == m_orphans.end()) {
62 for (
const CTxIn &txin : it->second.tx->vin) {
63 auto itPrev = m_outpoint_to_orphan_it.find(txin.
prevout);
64 if (itPrev == m_outpoint_to_orphan_it.end()) {
67 itPrev->second.erase(it);
68 if (itPrev->second.empty()) {
69 m_outpoint_to_orphan_it.erase(itPrev);
73 size_t old_pos = it->second.list_pos;
74 assert(m_orphan_list[old_pos] == it);
75 if (old_pos + 1 != m_orphan_list.size()) {
78 auto it_last = m_orphan_list.back();
79 m_orphan_list[old_pos] = it_last;
80 it_last->second.list_pos = old_pos;
82 m_orphan_list.pop_back();
92 std::map<TxId, OrphanTx>::iterator iter = m_orphans.begin();
93 while (iter != m_orphans.end()) {
94 std::map<TxId, OrphanTx>::iterator maybeErase =
96 if (maybeErase->second.fromPeer == peer) {
97 nErased +=
EraseTx(maybeErase->second.tx->GetId());
109 unsigned int nEvicted = 0;
110 static int64_t nNextSweep;
112 if (nNextSweep <= nNow) {
115 int64_t nMinExpTime =
117 std::map<TxId, OrphanTx>::iterator iter = m_orphans.begin();
118 while (iter != m_orphans.end()) {
119 std::map<TxId, OrphanTx>::iterator maybeErase = iter++;
120 if (maybeErase->second.nTimeExpire <= nNow) {
121 nErased +=
EraseTx(maybeErase->second.tx->GetId());
124 std::min(maybeErase->second.nTimeExpire, nMinExpTime);
136 while (m_orphans.size() > max_orphans) {
138 size_t randompos = rng.
randrange(m_orphan_list.size());
139 EraseTx(m_orphan_list[randompos]->first);
146 std::set<TxId> &orphan_work_set)
const {
148 for (
size_t i = 0; i < tx.
vout.size(); i++) {
149 const auto it_by_prev =
151 if (it_by_prev != m_outpoint_to_orphan_it.end()) {
152 for (
const auto &elem : it_by_prev->second) {
153 orphan_work_set.insert(elem->first);
161 return m_orphans.count(txid);
167 const auto it = m_orphans.find(txid);
168 if (it == m_orphans.end()) {
169 return {
nullptr, -1};
171 return {it->second.tx, it->second.fromPeer};
177 std::vector<TxId> vOrphanErase;
183 for (
const auto &txin : tx.
vin) {
184 auto itByPrev = m_outpoint_to_orphan_it.find(txin.prevout);
185 if (itByPrev == m_outpoint_to_orphan_it.end()) {
189 for (
auto mi = itByPrev->second.begin();
190 mi != itByPrev->second.end(); ++mi) {
193 vOrphanErase.push_back(orphanId);
199 if (vOrphanErase.size()) {
201 for (
const auto &orphanId : vOrphanErase) {
205 "Erased %d orphan tx included or conflicted by block\n",
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 std::vector< CTxIn > vin
An input of a transaction.
uint64_t randrange(uint64_t range) noexcept
Generate a random integer in the range [0..range).
bool HaveTx(const TxId &txid) const LOCKS_EXCLUDED(g_cs_orphans)
Check if we already have an orphan transaction.
std::pair< CTransactionRef, NodeId > GetTx(const TxId &txid) const EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
Get an orphan transaction and its originating peer (Transaction ref will be nullptr if not found)
void EraseForBlock(const CBlock &block) LOCKS_EXCLUDED(g_cs_orphans)
Erase all orphans included in or invalidated by a new block.
void EraseForPeer(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
Erase all orphans announced by a peer (eg, after that peer disconnects)
bool AddTx(const CTransactionRef &tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
Add a new orphan transaction.
unsigned int LimitOrphans(unsigned int max_orphans) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
Limit the orphanage to the given maximum.
void AddChildrenToWorkSet(const CTransaction &tx, std::set< TxId > &orphan_work_set) const EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
Add any orphans that list a particular tx as a parent into a peer's work set (ie orphans that may hav...
int EraseTx(const TxId &txid) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
Erase an orphan by txid.
std::string ToString() const
#define LogPrint(category,...)
static const unsigned int MAX_STANDARD_TX_SIZE
The maximum size for transactions we're willing to relay/mine.
std::shared_ptr< const CTransaction > CTransactionRef
A TxId is the identifier of a transaction.
T GetTime()
Return system time (or mocked time, if set)
RecursiveMutex g_cs_orphans
Guards orphan transactions and extra txs for compact blocks.
static constexpr int64_t ORPHAN_TX_EXPIRE_INTERVAL
Minimum time between orphan transactions expire time checks in seconds.
static constexpr int64_t ORPHAN_TX_EXPIRE_TIME
Expiration time for orphan transactions in seconds.