xrpld
Loading...
Searching...
No Matches
InboundTransactions.cpp
1#include <xrpld/app/ledger/InboundTransactions.h>
2
3#include <xrpld/app/ledger/detail/TransactionAcquire.h>
4#include <xrpld/app/main/Application.h>
5#include <xrpld/overlay/PeerSet.h>
6
7#include <xrpl/basics/Log.h>
8#include <xrpl/basics/Slice.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
18#include <xrpl.pb.h>
19
20#include <algorithm>
21#include <cstdint>
22#include <functional>
23#include <memory>
24#include <mutex>
25#include <utility>
26#include <vector>
27
28namespace xrpl {
29
30// Need to be named before converting
31static constexpr auto kStartPeers = 2; // ideal number of peers to start with
32static constexpr auto kSetKeepRounds = 3; // how many rounds to keep a set
33
35{
36 // A transaction set we generated, acquired, or are acquiring
37public:
41
48 {
49 ;
50 }
51};
52
54{
55public:
57 Application& app,
58 beast::insight::Collector::ptr const& collector,
59 std::function<void(std::shared_ptr<SHAMap> const&, bool)> gotSet,
61 : app_(app)
63 , gotSet_(std::move(gotSet))
64 , peerSetBuilder_(std::move(peerSetBuilder))
65 , j_(app_.getJournal("InboundTransactions"))
66 {
67 zeroSet_.set =
69 zeroSet_.set->setUnbacked();
70 }
71
73 getAcquire(uint256 const& hash)
74 {
75 {
76 std::scoped_lock const sl(lock_);
77
78 auto it = map_.find(hash);
79
80 if (it != map_.end())
81 return it->second.acquire;
82 }
83 return {};
84 }
85
87 getSet(uint256 const& hash, bool acquire) override
88 {
90
91 {
92 std::scoped_lock const sl(lock_);
93
94 if (auto it = map_.find(hash); it != map_.end())
95 {
96 if (acquire)
97 {
98 it->second.seq = seq_;
99 if (it->second.acquire)
100 {
101 it->second.acquire->stillNeed();
102 }
103 }
104 return it->second.set;
105 }
106
107 if (!acquire || stopping_)
109
111
112 auto& obj = map_[hash];
113 obj.acquire = ta;
114 obj.seq = seq_;
115 }
116
117 ta->init(kStartPeers);
118
119 return {};
120 }
121
124 void
126 LedgerHash const& hash,
129 {
130 protocol::TMLedgerData const& packet = *packetPtr;
131
132 JLOG(j_.trace()) << "Got data (" << packet.nodes().size()
133 << ") for acquiring ledger: " << hash;
134
136
137 if (ta == nullptr)
138 {
139 peer->charge(Resource::kFeeUselessData, "ledger_data");
140 return;
141 }
142
144 data.reserve(packet.nodes().size());
145
146 for (auto const& node : packet.nodes())
147 {
148 if (!node.has_nodeid() || !node.has_nodedata())
149 {
150 peer->charge(Resource::kFeeMalformedRequest, "ledger_data");
151 return;
152 }
153
154 auto const id = deserializeSHAMapNodeID(node.nodeid());
155
156 if (!id)
157 {
158 peer->charge(Resource::kFeeInvalidData, "ledger_data");
159 return;
160 }
161
162 data.emplace_back(*id, makeSlice(node.nodedata()));
163 }
164
165 if (!ta->takeNodes(data, peer).isUseful())
166 peer->charge(Resource::kFeeUselessData, "ledger_data not useful");
167 }
168
169 void
170 giveSet(uint256 const& hash, std::shared_ptr<SHAMap> const& set, bool fromAcquire) override
171 {
172 bool isNew = true;
173
174 {
175 std::scoped_lock const sl(lock_);
176
177 auto& inboundSet = map_[hash];
178
179 inboundSet.seq = std::max(inboundSet.seq, seq_);
180
181 if (inboundSet.set)
182 {
183 isNew = false;
184 }
185 else
186 {
187 inboundSet.set = set;
188 }
189
190 inboundSet.acquire.reset();
191 }
192
193 if (isNew)
194 gotSet_(set, fromAcquire);
195 }
196
197 void
199 {
200 std::scoped_lock const lock(lock_);
201
202 // Protect zero set from expiration
203 zeroSet_.seq = seq;
204
205 if (seq_ != seq)
206 {
207 seq_ = seq;
208
209 auto it = map_.begin();
210
211 std::uint32_t const minSeq = (seq < kSetKeepRounds) ? 0 : (seq - kSetKeepRounds);
212 std::uint32_t const maxSeq = seq + kSetKeepRounds;
213
214 while (it != map_.end())
215 {
216 if (it->second.seq < minSeq || it->second.seq > maxSeq)
217 {
218 it = map_.erase(it);
219 }
220 else
221 {
222 ++it;
223 }
224 }
225 }
226 }
227
228 void
229 stop() override
230 {
231 std::scoped_lock const lock(lock_);
232 stopping_ = true;
233 map_.clear();
234 }
235
236private:
238
240
242
243 bool stopping_{false};
246
247 // The empty transaction set whose hash is zero
249
251
253
255};
256
257//------------------------------------------------------------------------------
258
260
263 Application& app,
264 beast::insight::Collector::ptr const& collector,
265 std::function<void(std::shared_ptr<SHAMap> const&, bool)> gotSet)
266{
268 app, collector, std::move(gotSet), makePeerSetBuilder(app));
269}
270
271} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:38
std::shared_ptr< Collector > ptr
Definition Collector.h:26
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 kFeeMalformedRequest
Schedule of fees charged for imposing load on the server.
Charge const kFeeInvalidData
Charge const kFeeUselessData
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,...
uint256 LedgerHash
std::unique_ptr< PeerSetBuilder > makePeerSetBuilder(Application &app)
Definition PeerSet.cpp:137
static constexpr auto kStartPeers
std::optional< SHAMapNodeID > deserializeSHAMapNodeID(void const *data, std::size_t size)
Return an object representing a serialized SHAMap Node ID.
std::unordered_map< Key, Value, Hash, Pred, Allocator > hash_map
static constexpr auto kSetKeepRounds
BaseUInt< 256 > uint256
Definition base_uint.h:562
std::enable_if_t< std::is_same_v< T, char >||std::is_same_v< T, unsigned char >, Slice > makeSlice(std::array< T, N > const &a)
Definition Slice.h:215