xrpld
Loading...
Searching...
No Matches
InboundTransactions.cpp
1#include <xrpld/app/ledger/InboundTransactions.h>
2
3#include <xrpld/app/ledger/LedgerNodeHelpers.h>
4#include <xrpld/app/ledger/detail/TransactionAcquire.h>
5#include <xrpld/app/main/Application.h>
6#include <xrpld/overlay/PeerSet.h>
7
8#include <xrpl/basics/Log.h>
9#include <xrpl/basics/UnorderedContainers.h>
10#include <xrpl/beast/insight/Collector.h>
11#include <xrpl/protocol/RippleLedgerHash.h>
12#include <xrpl/resource/Fees.h>
13#include <xrpl/server/NetworkOPs.h>
14#include <xrpl/shamap/SHAMap.h>
15#include <xrpl/shamap/SHAMapMissingNode.h>
16#include <xrpl/shamap/SHAMapNodeID.h>
17#include <xrpl/shamap/SHAMapTreeNode.h>
18
19#include <xrpl.pb.h>
20
21#include <algorithm>
22#include <cstdint>
23#include <functional>
24#include <memory>
25#include <mutex>
26#include <utility>
27#include <vector>
28
29namespace xrpl {
30
31// Need to be named before converting
32static constexpr auto kStartPeers = 2; // ideal number of peers to start with
33static constexpr auto kSetKeepRounds = 3; // how many rounds to keep a set
34
36{
37 // A transaction set we generated, acquired, or are acquiring
38public:
42
49 {
50 ;
51 }
52};
53
55{
56public:
58 Application& app,
59 beast::insight::Collector::ptr const& collector,
60 std::function<void(std::shared_ptr<SHAMap> const&, bool)> gotSet,
62 : app_(app)
64 , gotSet_(std::move(gotSet))
65 , peerSetBuilder_(std::move(peerSetBuilder))
66 , j_(app_.getJournal("InboundTransactions"))
67 {
68 zeroSet_.set =
70 zeroSet_.set->setUnbacked();
71 }
72
74 getAcquire(uint256 const& hash)
75 {
76 {
77 std::scoped_lock const sl(lock_);
78
79 auto it = map_.find(hash);
80
81 if (it != map_.end())
82 return it->second.acquire;
83 }
84 return {};
85 }
86
88 getSet(uint256 const& hash, bool acquire) override
89 {
91
92 {
93 std::scoped_lock const sl(lock_);
94
95 if (auto it = map_.find(hash); it != map_.end())
96 {
97 if (acquire)
98 {
99 it->second.seq = seq_;
100 if (it->second.acquire)
101 {
102 it->second.acquire->stillNeed();
103 }
104 }
105 return it->second.set;
106 }
107
108 if (!acquire || stopping_)
110
112
113 auto& obj = map_[hash];
114 obj.acquire = ta;
115 obj.seq = seq_;
116 }
117
118 ta->init(kStartPeers);
119
120 return {};
121 }
122
126 void
128 LedgerHash const& hash,
131 {
132 protocol::TMLedgerData const& packet = *packetPtr;
133
134 JLOG(j_.trace()) << "Got data (" << packet.nodes().size()
135 << ") for acquiring ledger: " << hash;
136
138
139 if (ta == nullptr)
140 {
141 peer->charge(resource::kFeeUselessData, "ledger_data useless");
142 return;
143 }
144
146 data.reserve(packet.nodes().size());
147
148 for (auto const& ledgerNode : packet.nodes())
149 {
150 auto treeNode = getTreeNode(ledgerNode.nodedata());
151 if (!treeNode)
152 {
153 JLOG(j_.warn()) << "Got invalid node data for TX set " << hash << " from peer "
154 << peer->id();
155 peer->charge(resource::kFeeInvalidData, "ledger_node.node_data invalid");
156 return;
157 }
158
159 auto const nodeID = getSHAMapNodeID(ledgerNode, *treeNode);
160 if (!nodeID)
161 {
162 JLOG(j_.warn()) << "Got invalid node id for TX set " << hash << " from peer "
163 << peer->id();
164 peer->charge(resource::kFeeInvalidData, "ledger_node.node_id invalid");
165 return;
166 }
167
168 data.emplace_back(*nodeID, std::move(treeNode));
169 }
170
171 auto const san = ta->takeNodes(std::move(data), peer);
172 if (san.isInvalid())
173 {
174 peer->charge(resource::kFeeInvalidData, "ledger_data invalid");
175 }
176 else if (!san.isUseful())
177 {
178 peer->charge(resource::kFeeUselessData, "ledger_data useless");
179 }
180 }
181
182 void
183 giveSet(uint256 const& hash, std::shared_ptr<SHAMap> const& set, bool fromAcquire) override
184 {
185 bool isNew = true;
186
187 {
188 std::scoped_lock const sl(lock_);
189
190 auto& inboundSet = map_[hash];
191
192 inboundSet.seq = std::max(inboundSet.seq, seq_);
193
194 if (inboundSet.set)
195 {
196 isNew = false;
197 }
198 else
199 {
200 inboundSet.set = set;
201 }
202
203 inboundSet.acquire.reset();
204 }
205
206 if (isNew)
207 gotSet_(set, fromAcquire);
208 }
209
210 void
212 {
213 std::scoped_lock const lock(lock_);
214
215 // Protect zero set from expiration
216 zeroSet_.seq = seq;
217
218 if (seq_ != seq)
219 {
220 seq_ = seq;
221
222 auto it = map_.begin();
223
224 std::uint32_t const minSeq = (seq < kSetKeepRounds) ? 0 : (seq - kSetKeepRounds);
225 std::uint32_t const maxSeq = seq + kSetKeepRounds;
226
227 while (it != map_.end())
228 {
229 if (it->second.seq < minSeq || it->second.seq > maxSeq)
230 {
231 it = map_.erase(it);
232 }
233 else
234 {
235 ++it;
236 }
237 }
238 }
239 }
240
241 void
242 stop() override
243 {
244 std::scoped_lock const lock(lock_);
245 stopping_ = true;
246 map_.clear();
247 }
248
249private:
251
253
255
256 bool stopping_{false};
259
260 // The empty transaction set whose hash is zero
262
264
266
268};
269
270//------------------------------------------------------------------------------
271
273
276 Application& app,
277 beast::insight::Collector::ptr const& collector,
278 std::function<void(std::shared_ptr<SHAMap> const&, bool)> gotSet)
279{
281 app, collector, std::move(gotSet), makePeerSetBuilder(app));
282}
283
284} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:44
std::shared_ptr< Collector > ptr
Definition Collector.h:29
TransactionAcquire::pointer acquire
std::shared_ptr< SHAMap > set
InboundTransactionSet(std::uint32_t seq, std::shared_ptr< SHAMap > const &set)
void giveSet(uint256 const &hash, std::shared_ptr< SHAMap > const &set, bool fromAcquire) override
Add a transaction set.
TransactionAcquire::pointer getAcquire(uint256 const &hash)
std::unique_ptr< PeerSetBuilder > peerSetBuilder_
std::function< void(std::shared_ptr< SHAMap > const &, bool)> gotSet_
void gotData(LedgerHash const &hash, std::shared_ptr< Peer > peer, std::shared_ptr< protocol::TMLedgerData > packetPtr) override
We received a TMLedgerData from a peer.
void newRound(std::uint32_t seq) override
Informs the container if a new consensus round.
std::shared_ptr< SHAMap > getSet(uint256 const &hash, bool acquire) override
Find and return a transaction set, or nullptr if it is missing.
hash_map< uint256, InboundTransactionSet > MapType
InboundTransactionsImp(Application &app, beast::insight::Collector::ptr const &collector, std::function< void(std::shared_ptr< SHAMap > const &, bool)> gotSet, std::unique_ptr< PeerSetBuilder > peerSetBuilder)
virtual ~InboundTransactions()=0
std::shared_ptr< TransactionAcquire > pointer
T make_shared(T... args)
T make_unique(T... args)
T max(T... args)
STL namespace.
Charge const kFeeUselessData
Charge const kFeeInvalidData
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::unique_ptr< InboundTransactions > makeInboundTransactions(Application &app, beast::insight::Collector::ptr const &collector, std::function< void(std::shared_ptr< SHAMap > const &, bool)> gotSet)
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
std::optional< SHAMapNodeID > getSHAMapNodeID(protocol::TMLedgerNode const &ledgerNode, SHAMapTreeNode const &treeNode)
Extracts or reconstructs the SHAMapNodeID from a ledger node proto message.
SHAMapTreeNodePtr getTreeNode(std::string_view data)
Deserializes a SHAMapTreeNode from wire format data.
uint256 LedgerHash
std::unique_ptr< PeerSetBuilder > makePeerSetBuilder(Application &app)
Definition PeerSet.cpp:141
static constexpr auto kStartPeers
std::unordered_map< Key, Value, Hash, Pred, Allocator > hash_map
static constexpr auto kSetKeepRounds
BaseUInt< 256 > uint256
Definition base_uint.h:580