-
Notifications
You must be signed in to change notification settings - Fork 36.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This module captures orphan tracking code for tx relay. Can be reviewed with --color-moved=dimmed-zebra
- Loading branch information
Showing
9 changed files
with
170 additions
and
134 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// Copyright (c) 2021 The Bitcoin Core developers | ||
// Distributed under the MIT software license, see the accompanying | ||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
||
#include <txorphanage.h> | ||
|
||
#include <consensus/validation.h> | ||
#include <logging.h> | ||
#include <policy/policy.h> | ||
|
||
#include <cassert> | ||
|
||
/** Minimum time between orphan transactions expire time checks in seconds */ | ||
static constexpr int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60; | ||
|
||
RecursiveMutex g_cs_orphans; | ||
|
||
std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(g_cs_orphans); | ||
std::map<uint256, std::map<uint256, COrphanTx>::iterator> g_orphans_by_wtxid GUARDED_BY(g_cs_orphans); | ||
|
||
std::map<COutPoint, std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(g_cs_orphans); | ||
|
||
std::vector<std::map<uint256, COrphanTx>::iterator> g_orphan_list GUARDED_BY(g_cs_orphans); | ||
|
||
int EraseOrphanTx(uint256 hash) | ||
{ | ||
std::map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash); | ||
if (it == mapOrphanTransactions.end()) | ||
return 0; | ||
for (const CTxIn& txin : it->second.tx->vin) | ||
{ | ||
auto itPrev = mapOrphanTransactionsByPrev.find(txin.prevout); | ||
if (itPrev == mapOrphanTransactionsByPrev.end()) | ||
continue; | ||
itPrev->second.erase(it); | ||
if (itPrev->second.empty()) | ||
mapOrphanTransactionsByPrev.erase(itPrev); | ||
} | ||
|
||
size_t old_pos = it->second.list_pos; | ||
assert(g_orphan_list[old_pos] == it); | ||
if (old_pos + 1 != g_orphan_list.size()) { | ||
// Unless we're deleting the last entry in g_orphan_list, move the last | ||
// entry to the position we're deleting. | ||
auto it_last = g_orphan_list.back(); | ||
g_orphan_list[old_pos] = it_last; | ||
it_last->second.list_pos = old_pos; | ||
} | ||
g_orphan_list.pop_back(); | ||
g_orphans_by_wtxid.erase(it->second.tx->GetWitnessHash()); | ||
|
||
mapOrphanTransactions.erase(it); | ||
return 1; | ||
} | ||
|
||
void EraseOrphansFor(NodeId peer) | ||
{ | ||
LOCK(g_cs_orphans); | ||
int nErased = 0; | ||
std::map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin(); | ||
while (iter != mapOrphanTransactions.end()) | ||
{ | ||
std::map<uint256, COrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid | ||
if (maybeErase->second.fromPeer == peer) | ||
{ | ||
nErased += EraseOrphanTx(maybeErase->second.tx->GetHash()); | ||
} | ||
} | ||
if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx from peer=%d\n", nErased, peer); | ||
} | ||
|
||
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) | ||
{ | ||
LOCK(g_cs_orphans); | ||
|
||
unsigned int nEvicted = 0; | ||
static int64_t nNextSweep; | ||
int64_t nNow = GetTime(); | ||
if (nNextSweep <= nNow) { | ||
// Sweep out expired orphan pool entries: | ||
int nErased = 0; | ||
int64_t nMinExpTime = nNow + ORPHAN_TX_EXPIRE_TIME - ORPHAN_TX_EXPIRE_INTERVAL; | ||
std::map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin(); | ||
while (iter != mapOrphanTransactions.end()) | ||
{ | ||
std::map<uint256, COrphanTx>::iterator maybeErase = iter++; | ||
if (maybeErase->second.nTimeExpire <= nNow) { | ||
nErased += EraseOrphanTx(maybeErase->second.tx->GetHash()); | ||
} else { | ||
nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime); | ||
} | ||
} | ||
// Sweep again 5 minutes after the next entry that expires in order to batch the linear scan. | ||
nNextSweep = nMinExpTime + ORPHAN_TX_EXPIRE_INTERVAL; | ||
if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx due to expiration\n", nErased); | ||
} | ||
FastRandomContext rng; | ||
while (mapOrphanTransactions.size() > nMaxOrphans) | ||
{ | ||
// Evict a random orphan: | ||
size_t randompos = rng.randrange(g_orphan_list.size()); | ||
EraseOrphanTx(g_orphan_list[randompos]->first); | ||
++nEvicted; | ||
} | ||
return nEvicted; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Copyright (c) 2021 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/transaction.h> | ||
#include <sync.h> | ||
|
||
/** Expiration time for orphan transactions in seconds */ | ||
static constexpr int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60; | ||
|
||
/** Guards orphan transactions and extra txs for compact blocks */ | ||
extern RecursiveMutex g_cs_orphans; | ||
|
||
struct COrphanTx { | ||
// When modifying, adapt the copy of this definition in tests/DoS_tests. | ||
CTransactionRef tx; | ||
NodeId fromPeer; | ||
int64_t nTimeExpire; | ||
size_t list_pos; | ||
}; | ||
|
||
int EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans); | ||
void EraseOrphansFor(NodeId peer); | ||
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans); | ||
|
||
/** Map from txid to orphan transaction record. Limited by | ||
* -maxorphantx/DEFAULT_MAX_ORPHAN_TRANSACTIONS */ | ||
extern std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(g_cs_orphans); | ||
|
||
/** Index from wtxid into the mapOrphanTransactions to lookup orphan | ||
* transactions using their witness ids. */ | ||
extern std::map<uint256, std::map<uint256, COrphanTx>::iterator> g_orphans_by_wtxid GUARDED_BY(g_cs_orphans); | ||
|
||
struct IteratorComparator | ||
{ | ||
template<typename I> | ||
bool operator()(const I& a, const I& b) const | ||
{ | ||
return &(*a) < &(*b); | ||
} | ||
}; | ||
|
||
/** Index from the parents' COutPoint into the mapOrphanTransactions. Used | ||
* to remove orphan transactions from the mapOrphanTransactions */ | ||
extern std::map<COutPoint, std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(g_cs_orphans); | ||
|
||
/** Orphan transactions in vector for quick random eviction */ | ||
extern std::vector<std::map<uint256, COrphanTx>::iterator> g_orphan_list GUARDED_BY(g_cs_orphans); | ||
|
||
#endif // BITCOIN_TXORPHANAGE_H |