xrpld
Loading...
Searching...
No Matches
tx_reduce_relay_test.cpp
1#include <test/jtx/Env.h>
2#include <test/jtx/noop.h>
3#include <test/overlay/CapturePeer.h>
4
5#include <xrpld/app/main/Application.h>
6#include <xrpld/core/Config.h>
7#include <xrpld/overlay/Peer.h>
8#include <xrpld/overlay/detail/Handshake.h>
9#include <xrpld/overlay/detail/OverlayImpl.h>
10#include <xrpld/overlay/detail/PeerImp.h>
11
12#include <xrpl/basics/base_uint.h>
13#include <xrpl/beast/unit_test/suite.h>
14#include <xrpl/protocol/KeyType.h>
15#include <xrpl/protocol/PublicKey.h>
16#include <xrpl/protocol/SecretKey.h>
17#include <xrpl/protocol/Serializer.h>
18#include <xrpl/server/Handoff.h>
19
20#include <xrpl.pb.h>
21
22#include <cstddef>
23#include <cstdint>
24#include <functional>
25#include <memory>
26#include <optional>
27#include <set>
28#include <sstream>
29#include <string>
30#include <utility>
31#include <vector>
32
33namespace xrpl::test {
34
36{
37 void
38 doTest(std::string const& msg, bool log, std::function<void(bool)> f)
39 {
40 testcase(msg);
41 f(log);
42 }
43
44 void
46 {
47 doTest("Config Test", log, [&](bool log) {
48 auto test = [&](bool enable,
49 bool metrics,
50 std::uint16_t min,
51 std::uint16_t pct,
52 bool success = true) {
53 std::stringstream str("[reduce_relay]");
54 str << "[reduce_relay]\n"
55 << "tx_enable=" << static_cast<int>(enable) << "\n"
56 << "tx_metrics=" << static_cast<int>(metrics) << "\n"
57 << "tx_min_peers=" << min << "\n"
58 << "tx_relay_percentage=" << pct << "\n";
59 Config c;
60 try
61 {
62 c.loadFromString(str.str());
63
64 BEAST_EXPECT(c.txReduceRelayEnable == enable);
65 BEAST_EXPECT(c.txReduceRelayMetrics == metrics);
66 BEAST_EXPECT(c.txReduceRelayMinPeers == min);
67 BEAST_EXPECT(c.txRelayPercentage == pct);
68 if (success)
69 {
70 pass();
71 }
72 else
73 {
74 fail();
75 }
76 }
77 catch (...)
78 {
79 if (success)
80 {
81 fail();
82 }
83 else
84 {
85 pass();
86 }
87 }
88 };
89
90 test(true, true, 20, 25);
91 test(false, false, 20, 25);
92 test(false, false, 20, 0, false);
93 test(false, false, 20, 101, false);
94 test(false, false, 9, 10, false);
95 test(false, false, 10, 9, false);
96 });
97 }
98
104 {
105 public:
107
108 void
109 addTxQueue(UInt256 const&) override
110 {
111 ++queued_;
112 }
113
118 queued() const
119 {
120 return queued_;
121 }
122
123 private:
125 };
126
140 void
142 jtx::Env& env,
144 std::uint16_t& nDisabled)
145 {
146 auto& overlay = dynamic_cast<OverlayImpl&>(env.app().getOverlay());
147 PublicKey const key(std::get<0>(randomKeyPair(KeyType::Ed25519)));
148
149 bool const disabled = nDisabled > 0;
150 if (disabled)
151 --nDisabled;
152
153 HttpRequestType request;
154 if (!disabled)
155 request.insert("X-Protocol-Ctl", makeFeaturesRequestHeader(false, false, true, false));
156
157 BEAST_EXPECT(overlay.findPeerByPublicKey(key) == std::shared_ptr<PeerImp>{});
158 auto const peer = makeCapturePeer<TxReducePeer>(env, key, std::move(request));
159 BEAST_EXPECT(overlay.findPeerByPublicKey(key) == peer);
160 peers.emplace_back(peer);
161 }
162
176 void
178 std::string const& test,
179 bool txRREnabled,
180 std::uint16_t nPeers,
181 std::uint16_t nDisabled,
182 std::uint16_t minPeers,
183 std::uint16_t relayPercentage,
184 std::uint16_t expectRelay,
185 std::uint16_t expectQueue,
186 std::size_t nSkip = 0)
187 {
188 testcase(test);
189 jtx::Env env(*this);
191 // `PeerImp` decides `txReduceRelayEnabled()` in its constructor, from
192 // the config and the handshake header, so set these first.
193 env.app().config().txReduceRelayEnable = txRREnabled;
194 env.app().config().txReduceRelayMinPeers = minPeers;
195 env.app().config().txRelayPercentage = relayPercentage;
196 for (int i = 0; i < nPeers; i++)
197 addPeer(env, peers, nDisabled);
198
199 // An under-filled skip set would also fail the relay counts below, for
200 // a reason that looks unrelated.
201 if (!BEAST_EXPECT(nSkip <= peers.size()))
202 return;
203
204 // Skip the peers built first, so the skip set overlaps the disabled
205 // peers as the expected counts assume.
206 std::set<Peer::ID> toSkip;
207 for (std::size_t i = 0; i < nSkip; ++i)
208 toSkip.insert(peers[i]->id());
209
210 auto const jtx = env.jt(noop(env.master));
211 if (BEAST_EXPECT(jtx.stx))
212 {
213 protocol::TMTransaction m;
214 Serializer s;
215 jtx.stx->add(s);
216 m.set_rawtransaction(s.data(), s.size());
217 m.set_deferred(false);
218 m.set_status(protocol::TransactionStatus::tsNEW);
219 env.app().getOverlay().relay(UInt256{0}, m, toSkip);
220
221 std::size_t sendTx = 0;
222 std::size_t queueTx = 0;
223 for (auto const& peer : peers)
224 {
225 sendTx += peer->sent().size();
226 queueTx += peer->queued();
227 }
228 BEAST_EXPECT(sendTx == expectRelay && queueTx == expectQueue);
229 }
230 }
231
247 void
249 std::string const& test,
250 bool txRREnabled,
251 std::uint16_t nPeers,
252 std::uint16_t nDisabled,
253 std::uint16_t expectQueue)
254 {
255 testcase(test);
256 jtx::Env env(*this);
258 // `PeerImp` decides `txReduceRelayEnabled()` in its constructor, from
259 // the config and the handshake header, so set this first.
260 env.app().config().txReduceRelayEnable = txRREnabled;
261 for (int i = 0; i < nPeers; i++)
262 addPeer(env, peers, nDisabled);
263
264 env.app().getOverlay().relay(uint256{0}, std::nullopt, {});
265
266 std::size_t sendTx = 0;
267 std::size_t queueTx = 0;
268 for (auto const& peer : peers)
269 {
270 sendTx += peer->sent().size();
271 queueTx += peer->queued();
272 }
273 BEAST_EXPECT(sendTx == 0 && queueTx == expectQueue);
274 }
275
276 void
277 run() override
278 {
279 bool const log = false;
281 // relay to all peers, no hash queue
282 testRelay("feature disabled", false, 10, 0, 10, 25, 10, 0);
283 // relay to nPeers - skip (10-5=5)
284 testRelay("feature disabled & skip", false, 10, 0, 10, 25, 5, 0, 5);
285 // relay to all peers because min is greater than nPeers
286 testRelay("relay all 1", true, 10, 0, 20, 25, 10, 0);
287 // relay to all peers because min + disabled is greater thant nPeers
288 testRelay("relay all 2", true, 20, 15, 10, 25, 20, 0);
289 // relay to minPeers + 25% of nPeers-minPeers (20+0.25*(60-20)=30),
290 // queue the rest (30)
291 testRelay("relay & queue", true, 60, 0, 20, 25, 30, 30);
292 // relay to minPeers + 25% of (nPeers - nPeers) - skip
293 // (20+0.25*(60-20)-5=25), queue the rest, skip counts towards relayed
294 // (60-25-5=30)
295 testRelay("skip", true, 60, 0, 20, 25, 25, 30, 5);
296 // relay to minPeers + disabled + 25% of (nPeers - minPeers - disabled)
297 // (20+10+0.25*(70-20-10)=40), queue the rest (30)
298 testRelay("disabled", true, 70, 10, 20, 25, 40, 30);
299 // relay to minPeers + disabled-not-in-skip + 25% of (nPeers - minPeers
300 // - disabled) (20+5+0.25*(70-20-10)=35), queue the rest, skip counts
301 // towards relayed (70-35-5=30))
302 testRelay("disabled & skip", true, 70, 10, 20, 25, 35, 30, 5);
303 // relay to minPeers + disabled + 25% of (nPeers - minPeers - disabled)
304 // - skip (10+5+0.25*(15-10-5)-10=5), queue the rest, skip counts
305 // towards relayed (15-5-10=0)
306 testRelay("disabled & skip, no queue", true, 15, 5, 10, 25, 5, 0, 10);
307 // relay to minPeers + disabled + 25% of (nPeers - minPeers - disabled)
308 // - skip (10+2+0.25*(20-10-2)-14=0), queue the rest, skip counts
309 // towards relayed (20-14=6)
310 testRelay("disabled & skip, no relay", true, 20, 2, 10, 25, 0, 6, 14);
311 // nothing to send, so nothing is queued either
312 testQueueOnly("queue only, feature disabled", false, 10, 0, 0);
313 // queue every peer, since all of them negotiated the feature
314 testQueueOnly("queue only", true, 10, 0, 10);
315 // queue the 6 that negotiated it and none of the 4 that did not
316 testQueueOnly("queue only, some disabled", true, 10, 4, 6);
317 // queue nobody, since no peer would understand the announcement
318 testQueueOnly("queue only, all disabled", true, 10, 10, 0);
319 }
320};
321
322BEAST_DEFINE_TESTSUITE(tx_reduce_relay, overlay, xrpl);
323} // namespace xrpl::test
A testsuite class.
Definition suite.h:52
void pass()
Record a successful test condition.
Definition suite.h:532
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:554
LogOs< char > log
Logging output stream.
Definition suite.h:150
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:155
virtual Config & config()=0
std::size_t txReduceRelayMinPeers
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
std::size_t txRelayPercentage
bool txReduceRelayEnable
////////////// END OF TEMPORARY CODE BLOCK /////////////////////
virtual std::set< Peer::ID > relay(protocol::TMProposeSet const &m, UInt256 const &uid, PublicKey const &validator)=0
Relay a proposal.
A public key.
Definition PublicKey.h:53
std::size_t size() const noexcept
Definition Serializer.h:147
void const * data() const noexcept
Definition Serializer.h:153
virtual Overlay & getOverlay()=0
CapturePeer(Application &app, Peer::ID id, std::shared_ptr< peer_finder::Slot > const &slot, HttpRequestType request, PublicKey const &publicKey, ProtocolVersion protocol, resource::Consumer consumer, std::unique_ptr< StreamType > streamPtr, OverlayImpl &overlay)
Takes PeerImp's two rvalue-reference parameters by value instead, so a derived double can inherit thi...
Definition CapturePeer.h:68
A transaction testing environment.
Definition Env.h:161
Application & app()
Definition Env.h:300
Account const & master
Definition Env.h:165
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Definition Env.h:723
void addTxQueue(UInt256 const &) override
Add transaction's hash to the transactions' hashes queue.
CapturePeer(Application &app, Peer::ID id, std::shared_ptr< peer_finder::Slot > const &slot, HttpRequestType request, PublicKey const &publicKey, ProtocolVersion protocol, resource::Consumer consumer, std::unique_ptr< StreamType > streamPtr, OverlayImpl &overlay)
Takes PeerImp's two rvalue-reference parameters by value instead, so a derived double can inherit thi...
Definition CapturePeer.h:68
void testRelay(std::string const &test, bool txRREnabled, std::uint16_t nPeers, std::uint16_t nDisabled, std::uint16_t minPeers, std::uint16_t relayPercentage, std::uint16_t expectRelay, std::uint16_t expectQueue, std::size_t nSkip=0)
Relay one transaction to nPeers peers and check the split.
void run() override
Runs the suite.
void testQueueOnly(std::string const &test, bool txRREnabled, std::uint16_t nPeers, std::uint16_t nDisabled, std::uint16_t expectQueue)
Exercises the branch that only queues, reached when relay() is handed no transaction to send: a pseud...
void doTest(std::string const &msg, bool log, std::function< void(bool)> f)
void addPeer(jtx::Env &env, std::vector< std::shared_ptr< TxReducePeer > > &peers, std::uint16_t &nDisabled)
Build one peer and register it with the overlay.
T insert(T... args)
json::Value noop(Account const &account)
The null transaction.
Definition noop.h:14
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
std::shared_ptr< PeerType > makeCapturePeer(jtx::Env &env, std::optional< PublicKey > key=std::nullopt, HttpRequestType request={})
Build an active CapturePeer and register it with the overlay.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
BaseUInt< 256 > UInt256
Definition base_uint.h:580
boost::beast::http::request< boost::beast::http::dynamic_body > HttpRequestType
Definition Handoff.h:12
std::string makeFeaturesRequestHeader(bool comprEnabled, bool ledgerReplayEnabled, bool txReduceRelayEnabled, bool vpReduceRelayEnabled)
Make request header X-Protocol-Ctl value with supported features.
Definition Handshake.cpp:83
UInt256 uint256
Definition base_uint.h:586
T size(T... args)
T str(T... args)