mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-14 12:43:40 +02:00
Merge 5550fa5983 into merged_master (Bitcoin PR #19109)
This commit is contained in:
commit
e0e95b910a
1 changed files with 49 additions and 24 deletions
|
|
@ -38,7 +38,9 @@ static constexpr int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60;
|
|||
/** Minimum time between orphan transactions expire time checks in seconds */
|
||||
static constexpr int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60;
|
||||
/** How long to cache transactions in mapRelay for normal relay */
|
||||
static constexpr std::chrono::seconds RELAY_TX_CACHE_TIME{15 * 60};
|
||||
static constexpr std::chrono::seconds RELAY_TX_CACHE_TIME = std::chrono::minutes{15};
|
||||
/** How long a transaction has to be in the mempool before it can unconditionally be relayed (even when not in mapRelay). */
|
||||
static constexpr std::chrono::seconds UNCONDITIONAL_RELAY_DELAY = std::chrono::minutes{2};
|
||||
/** Headers download timeout expressed in microseconds
|
||||
* Timeout = base + per_header * (expected number of headers) */
|
||||
static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000; // 15 minutes
|
||||
|
|
@ -119,9 +121,18 @@ static constexpr std::chrono::seconds AVG_ADDRESS_BROADCAST_INTERVAL{30};
|
|||
/** Average delay between trickled inventory transmissions in seconds.
|
||||
* Blocks and peers with noban permission bypass this, outbound peers get half this delay. */
|
||||
static const unsigned int INVENTORY_BROADCAST_INTERVAL = 5;
|
||||
/** Maximum number of inventory items to send per transmission.
|
||||
/** Maximum rate of inventory items to send per second.
|
||||
* Limits the impact of low-fee transaction floods. */
|
||||
static constexpr unsigned int INVENTORY_BROADCAST_MAX = 7 * INVENTORY_BROADCAST_INTERVAL;
|
||||
static constexpr unsigned int INVENTORY_BROADCAST_PER_SECOND = 7;
|
||||
/** Maximum number of inventory items to send per transmission. */
|
||||
static constexpr unsigned int INVENTORY_BROADCAST_MAX = INVENTORY_BROADCAST_PER_SECOND * INVENTORY_BROADCAST_INTERVAL;
|
||||
/** The number of most recently announced transactions a peer can request. */
|
||||
static constexpr unsigned int INVENTORY_MAX_RECENT_RELAY = 3500;
|
||||
/** Verify that INVENTORY_MAX_RECENT_RELAY is enough to cache everything typically
|
||||
* relayed before unconditional relay from the mempool kicks in. This is only a
|
||||
* lower bound, and it should be larger to account for higher inv rate to outbound
|
||||
* peers, and random variations in the broadcast mechanism. */
|
||||
static_assert(INVENTORY_MAX_RECENT_RELAY >= INVENTORY_BROADCAST_PER_SECOND * UNCONDITIONAL_RELAY_DELAY / std::chrono::seconds{1}, "INVENTORY_RELAY_MAX too low");
|
||||
/** Average delay between feefilter broadcasts in seconds. */
|
||||
static constexpr unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60;
|
||||
/** Maximum feefilter broadcast delay after significant change. */
|
||||
|
|
@ -395,6 +406,9 @@ struct CNodeState {
|
|||
//! Whether this peer is a manual connection
|
||||
bool m_is_manual_connection;
|
||||
|
||||
//! A rolling bloom filter of all announced tx CInvs to this peer.
|
||||
CRollingBloomFilter m_recently_announced_invs = CRollingBloomFilter{INVENTORY_MAX_RECENT_RELAY, 0.000001};
|
||||
|
||||
CNodeState(CAddress addrIn, std::string addrNameIn, bool is_inbound, bool is_manual) :
|
||||
address(addrIn), name(std::move(addrNameIn)), m_is_inbound(is_inbound),
|
||||
m_is_manual_connection (is_manual)
|
||||
|
|
@ -422,6 +436,7 @@ struct CNodeState {
|
|||
fSupportsDesiredCmpctVersion = false;
|
||||
m_chain_sync = { 0, nullptr, false, false };
|
||||
m_last_block_announcement = 0;
|
||||
m_recently_announced_invs.reset();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1617,30 +1632,28 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
|
|||
}
|
||||
|
||||
//! Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed).
|
||||
CTransactionRef static FindTxForGetData(CNode& peer, const uint256& txid, const std::chrono::seconds mempool_req, const std::chrono::seconds longlived_mempool_time) LOCKS_EXCLUDED(cs_main)
|
||||
CTransactionRef static FindTxForGetData(const CNode& peer, const uint256& txid, const std::chrono::seconds mempool_req, const std::chrono::seconds now) LOCKS_EXCLUDED(cs_main)
|
||||
{
|
||||
// Check if the requested transaction is so recent that we're just
|
||||
// about to announce it to the peer; if so, they certainly shouldn't
|
||||
// know we already have it.
|
||||
{
|
||||
LOCK(peer.m_tx_relay->cs_tx_inventory);
|
||||
if (peer.m_tx_relay->setInventoryTxToSend.count(txid)) return {};
|
||||
auto txinfo = mempool.info(txid);
|
||||
if (txinfo.tx) {
|
||||
// If a TX could have been INVed in reply to a MEMPOOL request,
|
||||
// or is older than UNCONDITIONAL_RELAY_DELAY, permit the request
|
||||
// unconditionally.
|
||||
if ((mempool_req.count() && txinfo.m_time <= mempool_req) || txinfo.m_time <= now - UNCONDITIONAL_RELAY_DELAY) {
|
||||
return std::move(txinfo.tx);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
LOCK(cs_main);
|
||||
// Look up transaction in relay pool
|
||||
auto mi = mapRelay.find(txid);
|
||||
if (mi != mapRelay.end()) return mi->second;
|
||||
}
|
||||
|
||||
auto txinfo = mempool.info(txid);
|
||||
if (txinfo.tx) {
|
||||
// To protect privacy, do not answer getdata using the mempool when
|
||||
// that TX couldn't have been INVed in reply to a MEMPOOL request,
|
||||
// or when it's too recent to have expired from mapRelay.
|
||||
if ((mempool_req.count() && txinfo.m_time <= mempool_req) || txinfo.m_time <= longlived_mempool_time) {
|
||||
return txinfo.tx;
|
||||
// Otherwise, the transaction must have been announced recently.
|
||||
if (State(peer.GetId())->m_recently_announced_invs.contains(txid)) {
|
||||
// If it was, it can be relayed from either the mempool...
|
||||
if (txinfo.tx) return std::move(txinfo.tx);
|
||||
// ... or the relay pool.
|
||||
auto mi = mapRelay.find(txid);
|
||||
if (mi != mapRelay.end()) return mi->second;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1655,8 +1668,7 @@ void static ProcessGetData(CNode& pfrom, const CChainParams& chainparams, CConnm
|
|||
std::vector<CInv> vNotFound;
|
||||
const CNetMsgMaker msgMaker(pfrom.GetSendVersion());
|
||||
|
||||
// mempool entries added before this time have likely expired from mapRelay
|
||||
const std::chrono::seconds longlived_mempool_time = GetTime<std::chrono::seconds>() - RELAY_TX_CACHE_TIME;
|
||||
const std::chrono::seconds now = GetTime<std::chrono::seconds>();
|
||||
// Get last mempool request time
|
||||
const std::chrono::seconds mempool_req = pfrom.m_tx_relay != nullptr ? pfrom.m_tx_relay->m_last_mempool_req.load()
|
||||
: std::chrono::seconds::min();
|
||||
|
|
@ -1677,11 +1689,22 @@ void static ProcessGetData(CNode& pfrom, const CChainParams& chainparams, CConnm
|
|||
continue;
|
||||
}
|
||||
|
||||
CTransactionRef tx = FindTxForGetData(pfrom, inv.hash, mempool_req, longlived_mempool_time);
|
||||
CTransactionRef tx = FindTxForGetData(pfrom, inv.hash, mempool_req, now);
|
||||
if (tx) {
|
||||
int nSendFlags = (inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0);
|
||||
connman->PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *tx));
|
||||
mempool.RemoveUnbroadcastTx(inv.hash);
|
||||
// As we're going to send tx, make sure its unconfirmed parents are made requestable.
|
||||
for (const auto& txin : tx->vin) {
|
||||
auto txinfo = mempool.info(txin.prevout.hash);
|
||||
if (txinfo.tx && txinfo.m_time > now - UNCONDITIONAL_RELAY_DELAY) {
|
||||
// Relaying a transaction with a recent but unconfirmed parent.
|
||||
if (WITH_LOCK(pfrom.m_tx_relay->cs_tx_inventory, return !pfrom.m_tx_relay->filterInventoryKnown.contains(txin.prevout.hash))) {
|
||||
LOCK(cs_main);
|
||||
State(pfrom.GetId())->m_recently_announced_invs.insert(txin.prevout.hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vNotFound.push_back(inv);
|
||||
}
|
||||
|
|
@ -4149,6 +4172,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
|
|||
if (!pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
|
||||
}
|
||||
pto->m_tx_relay->filterInventoryKnown.insert(hash);
|
||||
// Responses to MEMPOOL requests bypass the m_recently_announced_invs filter.
|
||||
vInv.push_back(inv);
|
||||
if (vInv.size() == MAX_INV_SZ) {
|
||||
connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
|
||||
|
|
@ -4202,6 +4226,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
|
|||
}
|
||||
if (pto->m_tx_relay->pfilter && !pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
|
||||
// Send
|
||||
State(pto->GetId())->m_recently_announced_invs.insert(hash);
|
||||
vInv.push_back(CInv(MSG_TX, hash));
|
||||
nRelayedTransactions++;
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue