forked from bitcoin/bitcoin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
txdownloadman.h
179 lines (153 loc) · 7.8 KB
/
txdownloadman.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright (c) 2024 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_NODE_TXDOWNLOADMAN_H
#define BITCOIN_NODE_TXDOWNLOADMAN_H
#include <net.h>
#include <policy/packages.h>
#include <txorphanage.h>
#include <cstdint>
#include <memory>
class CBlock;
class CRollingBloomFilter;
class CTxMemPool;
class GenTxid;
class TxRequestTracker;
namespace node {
class TxDownloadManagerImpl;
/** Maximum number of in-flight transaction requests from a peer. It is not a hard limit, but the threshold at which
* point the OVERLOADED_PEER_TX_DELAY kicks in. */
static constexpr int32_t MAX_PEER_TX_REQUEST_IN_FLIGHT = 100;
/** Maximum number of transactions to consider for requesting, per peer. It provides a reasonable DoS limit to
* per-peer memory usage spent on announcements, while covering peers continuously sending INVs at the maximum
* rate (by our own policy, see INVENTORY_BROADCAST_PER_SECOND) for several minutes, while not receiving
* the actual transaction (from any peer) in response to requests for them. */
static constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS = 5000;
/** How long to delay requesting transactions via txids, if we have wtxid-relaying peers */
static constexpr auto TXID_RELAY_DELAY{2s};
/** How long to delay requesting transactions from non-preferred peers */
static constexpr auto NONPREF_PEER_TX_DELAY{2s};
/** How long to delay requesting transactions from overloaded peers (see MAX_PEER_TX_REQUEST_IN_FLIGHT). */
static constexpr auto OVERLOADED_PEER_TX_DELAY{2s};
/** How long to wait before downloading a transaction from an additional peer */
static constexpr auto GETDATA_TX_INTERVAL{60s};
struct TxDownloadOptions {
/** Read-only reference to mempool. */
const CTxMemPool& m_mempool;
/** RNG provided by caller. */
FastRandomContext& m_rng;
/** Maximum number of transactions allowed in orphanage. */
const uint32_t m_max_orphan_txs;
/** Instantiate TxRequestTracker as deterministic (used for tests). */
bool m_deterministic_txrequest{false};
};
struct TxDownloadConnectionInfo {
/** Whether this peer is preferred for transaction download. */
const bool m_preferred;
/** Whether this peer has Relay permissions. */
const bool m_relay_permissions;
/** Whether this peer supports wtxid relay. */
const bool m_wtxid_relay;
};
struct PackageToValidate {
Package m_txns;
std::vector<NodeId> m_senders;
/** Construct a 1-parent-1-child package. */
explicit PackageToValidate(const CTransactionRef& parent,
const CTransactionRef& child,
NodeId parent_sender,
NodeId child_sender) :
m_txns{parent, child},
m_senders{parent_sender, child_sender}
{}
// Move ctor
PackageToValidate(PackageToValidate&& other) : m_txns{std::move(other.m_txns)}, m_senders{std::move(other.m_senders)} {}
// Copy ctor
PackageToValidate(const PackageToValidate& other) = default;
// Move assignment
PackageToValidate& operator=(PackageToValidate&& other) {
this->m_txns = std::move(other.m_txns);
this->m_senders = std::move(other.m_senders);
return *this;
}
std::string ToString() const {
Assume(m_txns.size() == 2);
return strprintf("parent %s (wtxid=%s, sender=%d) + child %s (wtxid=%s, sender=%d)",
m_txns.front()->GetHash().ToString(),
m_txns.front()->GetWitnessHash().ToString(),
m_senders.front(),
m_txns.back()->GetHash().ToString(),
m_txns.back()->GetWitnessHash().ToString(),
m_senders.back());
}
};
struct RejectedTxTodo
{
bool m_should_add_extra_compact_tx;
std::vector<uint256> m_unique_parents;
std::optional<PackageToValidate> m_package_to_validate;
};
/**
* Class responsible for deciding what transactions to request and, once
* downloaded, whether and how to validate them. It is also responsible for
* deciding what transaction packages to validate and how to resolve orphan
* transactions. Its data structures include TxRequestTracker for scheduling
* requests, rolling bloom filters for remembering transactions that have
* already been {accepted, rejected, confirmed}, an orphanage, and a registry of
* each peer's transaction relay-related information.
*
* Caller needs to interact with TxDownloadManager:
* - ValidationInterface callbacks.
* - When a potential transaction relay peer connects or disconnects.
* - When a transaction or package is accepted or rejected from mempool
* - When a inv, notfound, or tx message is received
* - To get instructions for which getdata messages to send
*
* This class is not thread-safe. Access must be synchronized using an
* external mutex.
*/
class TxDownloadManager {
const std::unique_ptr<TxDownloadManagerImpl> m_impl;
public:
explicit TxDownloadManager(const TxDownloadOptions& options);
~TxDownloadManager();
// Responses to chain events. TxDownloadManager is not an actual client of ValidationInterface, these are called through PeerManager.
void ActiveTipChange();
void BlockConnected(const std::shared_ptr<const CBlock>& pblock);
void BlockDisconnected();
/** Creates a new PeerInfo. Saves the connection info to calculate tx announcement delays later. */
void ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo& info);
/** Deletes all txrequest announcements and orphans for a given peer. */
void DisconnectedPeer(NodeId nodeid);
/** Consider adding this tx hash to txrequest. Should be called whenever a new inv has been received.
* Also called internally when a transaction is missing parents so that we can request them.
* @param[in] p2p_inv When true, only add this announcement if we don't already have the tx.
* Returns true if this was a dropped inv (p2p_inv=true and we already have the tx), false otherwise. */
bool AddTxAnnouncement(NodeId peer, const GenTxid& gtxid, std::chrono::microseconds now, bool p2p_inv);
/** Get getdata requests to send. */
std::vector<GenTxid> GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time);
/** Should be called when a notfound for a tx has been received. */
void ReceivedNotFound(NodeId nodeid, const std::vector<uint256>& txhashes);
/** Respond to successful transaction submission to mempool */
void MempoolAcceptedTx(const CTransactionRef& tx);
/** Respond to transaction rejected from mempool */
RejectedTxTodo MempoolRejectedTx(const CTransactionRef& ptx, const TxValidationState& state, NodeId nodeid, bool first_time_failure);
/** Respond to package rejected from mempool */
void MempoolRejectedPackage(const Package& package);
/** Marks a tx as ReceivedResponse in txrequest and checks whether AlreadyHaveTx.
* Return a bool indicating whether this tx should be validated. If false, optionally, a
* PackageToValidate. */
std::pair<bool, std::optional<PackageToValidate>> ReceivedTx(NodeId nodeid, const CTransactionRef& ptx);
/** Whether there are any orphans to reconsider for this peer. */
bool HaveMoreWork(NodeId nodeid) const;
/** Returns next orphan tx to consider, or nullptr if none exist. */
CTransactionRef GetTxToReconsider(NodeId nodeid);
/** Check that all data structures are empty. */
void CheckIsEmpty() const;
/** Check that all data structures that track per-peer information have nothing for this peer. */
void CheckIsEmpty(NodeId nodeid) const;
/** Wrapper for TxOrphanage::GetOrphanTransactions */
std::vector<TxOrphanage::OrphanTxBase> GetOrphanTransactions() const;
};
} // namespace node
#endif // BITCOIN_NODE_TXDOWNLOADMAN_H