rippled
Loading...
Searching...
No Matches
tx_reduce_relay_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright 2020 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <test/jtx.h>
21#include <test/jtx/Env.h>
22
23#include <xrpld/overlay/detail/OverlayImpl.h>
24#include <xrpld/overlay/detail/PeerImp.h>
25#include <xrpld/peerfinder/detail/SlotImp.h>
26
27#include <xrpl/basics/make_SSLContext.h>
28#include <xrpl/beast/unit_test.h>
29
30namespace ripple {
31
32namespace test {
33
35{
36public:
37 using socket_type = boost::asio::ip::tcp::socket;
38 using middle_type = boost::beast::tcp_stream;
39 using stream_type = boost::beast::ssl_stream<middle_type>;
41
42private:
43 void
44 doTest(std::string const& msg, bool log, std::function<void(bool)> f)
45 {
46 testcase(msg);
47 f(log);
48 }
49
50 void
52 {
53 doTest("Config Test", log, [&](bool log) {
54 auto test = [&](bool enable,
55 bool metrics,
56 std::uint16_t min,
57 std::uint16_t pct,
58 bool success = true) {
59 std::stringstream str("[reduce_relay]");
60 str << "[reduce_relay]\n"
61 << "tx_enable=" << static_cast<int>(enable) << "\n"
62 << "tx_metrics=" << static_cast<int>(metrics) << "\n"
63 << "tx_min_peers=" << min << "\n"
64 << "tx_relay_percentage=" << pct << "\n";
65 Config c;
66 try
67 {
68 c.loadFromString(str.str());
69
70 BEAST_EXPECT(c.TX_REDUCE_RELAY_ENABLE == enable);
71 BEAST_EXPECT(c.TX_REDUCE_RELAY_METRICS == metrics);
72 BEAST_EXPECT(c.TX_REDUCE_RELAY_MIN_PEERS == min);
73 BEAST_EXPECT(c.TX_RELAY_PERCENTAGE == pct);
74 if (success)
75 pass();
76 else
77 fail();
78 }
79 catch (...)
80 {
81 if (success)
82 fail();
83 else
84 pass();
85 }
86 };
87
88 test(true, true, 20, 25);
89 test(false, false, 20, 25);
90 test(false, false, 20, 0, false);
91 test(false, false, 20, 101, false);
92 test(false, false, 9, 10, false);
93 test(false, false, 10, 9, false);
94 });
95 }
96
97 class PeerTest : public PeerImp
98 {
99 public:
101 Application& app,
103 http_request_type&& request,
104 PublicKey const& publicKey,
106 Resource::Consumer consumer,
108 OverlayImpl& overlay)
109 : PeerImp(
110 app,
111 sid_,
112 slot,
113 std::move(request),
114 publicKey,
115 protocol,
116 consumer,
117 std::move(stream_ptr),
118 overlay)
119 {
120 sid_++;
121 }
122 ~PeerTest() = default;
123
124 void
125 run() override
126 {
127 }
128 void
130 {
131 sendTx_++;
132 }
133 void
134 addTxQueue(uint256 const& hash) override
135 {
136 queueTx_++;
137 }
138 static void
140 {
141 queueTx_ = 0;
142 sendTx_ = 0;
143 sid_ = 0;
144 }
145 inline static std::size_t sid_ = 0;
146 inline static std::uint16_t queueTx_ = 0;
147 inline static std::uint16_t sendTx_ = 0;
148 };
149
154 boost::beast::multi_buffer read_buf_;
155
156public:
159 {
160 }
161
162private:
163 void
165 jtx::Env& env,
167 std::uint16_t& nDisabled)
168 {
169 auto& overlay = dynamic_cast<OverlayImpl&>(env.app().overlay());
170 boost::beast::http::request<boost::beast::http::dynamic_body> request;
171 (nDisabled == 0)
172 ? (void)request.insert(
173 "X-Protocol-Ctl",
174 makeFeaturesRequestHeader(false, false, true, false))
175 : (void)nDisabled--;
176 auto stream_ptr = std::make_unique<stream_type>(
177 socket_type(std::forward<boost::asio::io_service&>(
178 env.app().getIOService())),
179 *context_);
181 beast::IP::Address::from_string("172.1.1." + std::to_string(lid_)));
182 beast::IP::Endpoint remote(
183 beast::IP::Address::from_string("172.1.1." + std::to_string(rid_)));
184 PublicKey key(std::get<0>(randomKeyPair(KeyType::ed25519)));
185 auto consumer = overlay.resourceManager().newInboundEndpoint(remote);
186 auto slot = overlay.peerFinder().new_inbound_slot(local, remote);
187 auto const peer = std::make_shared<PeerTest>(
188 env.app(),
189 slot,
190 std::move(request),
191 key,
193 consumer,
194 std::move(stream_ptr),
195 overlay);
196 BEAST_EXPECT(
197 overlay.findPeerByPublicKey(key) == std::shared_ptr<PeerImp>{});
198 overlay.add_active(peer);
199 BEAST_EXPECT(overlay.findPeerByPublicKey(key) == peer);
200 peers.emplace_back(peer); // overlay stores week ptr to PeerImp
201 lid_ += 2;
202 rid_ += 2;
203 assert(lid_ <= 254);
204 }
205
206 void
208 std::string const& test,
209 bool txRREnabled,
210 std::uint16_t nPeers,
211 std::uint16_t nDisabled,
212 std::uint16_t minPeers,
213 std::uint16_t relayPercentage,
214 std::uint16_t expectRelay,
215 std::uint16_t expectQueue,
216 std::set<Peer::id_t> const& toSkip = {})
217 {
218 testcase(test);
219 jtx::Env env(*this);
221 env.app().config().TX_REDUCE_RELAY_ENABLE = txRREnabled;
222 env.app().config().TX_REDUCE_RELAY_MIN_PEERS = minPeers;
223 env.app().config().TX_RELAY_PERCENTAGE = relayPercentage;
225 lid_ = 0;
226 rid_ = 0;
227 for (int i = 0; i < nPeers; i++)
228 addPeer(env, peers, nDisabled);
229
230 auto const jtx = env.jt(noop(env.master));
231 if (BEAST_EXPECT(jtx.stx))
232 {
233 protocol::TMTransaction m;
234 Serializer s;
235 jtx.stx->add(s);
236 m.set_rawtransaction(s.data(), s.size());
237 m.set_deferred(false);
238 m.set_status(protocol::TransactionStatus::tsNEW);
239 env.app().overlay().relay(uint256{0}, m, toSkip);
240 BEAST_EXPECT(
241 PeerTest::sendTx_ == expectRelay &&
242 PeerTest::queueTx_ == expectQueue);
243 }
244 }
245
246 void
247 run() override
248 {
249 bool log = false;
250 std::set<Peer::id_t> skip = {0, 1, 2, 3, 4};
252 // relay to all peers, no hash queue
253 testRelay("feature disabled", false, 10, 0, 10, 25, 10, 0);
254 // relay to nPeers - skip (10-5=5)
255 testRelay("feature disabled & skip", false, 10, 0, 10, 25, 5, 0, skip);
256 // relay to all peers because min is greater than nPeers
257 testRelay("relay all 1", true, 10, 0, 20, 25, 10, 0);
258 // relay to all peers because min + disabled is greater thant nPeers
259 testRelay("relay all 2", true, 20, 15, 10, 25, 20, 0);
260 // relay to minPeers + 25% of nPeers-minPeers (20+0.25*(60-20)=30),
261 // queue the rest (30)
262 testRelay("relay & queue", true, 60, 0, 20, 25, 30, 30);
263 // relay to minPeers + 25% of (nPeers - nPeers) - skip
264 // (20+0.25*(60-20)-5=25), queue the rest, skip counts towards relayed
265 // (60-25-5=30)
266 testRelay("skip", true, 60, 0, 20, 25, 25, 30, skip);
267 // relay to minPeers + disabled + 25% of (nPeers - minPeers - disalbed)
268 // (20+10+0.25*(70-20-10)=40), queue the rest (30)
269 testRelay("disabled", true, 70, 10, 20, 25, 40, 30);
270 // relay to minPeers + disabled-not-in-skip + 25% of (nPeers - minPeers
271 // - disabled) (20+5+0.25*(70-20-10)=35), queue the rest, skip counts
272 // towards relayed (70-35-5=30))
273 testRelay("disabled & skip", true, 70, 10, 20, 25, 35, 30, skip);
274 // relay to minPeers + disabled + 25% of (nPeers - minPeers - disabled)
275 // - skip (10+5+0.25*(15-10-5)-10=5), queue the rest, skip counts
276 // towards relayed (15-5-10=0)
277 skip = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
278 testRelay("disabled & skip, no queue", true, 15, 5, 10, 25, 5, 0, skip);
279 // relay to minPeers + disabled + 25% of (nPeers - minPeers - disabled)
280 // - skip (10+2+0.25*(20-10-2)-14=0), queue the rest, skip counts
281 // towards relayed (20-14=6)
282 skip = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
283 testRelay("disabled & skip, no relay", true, 20, 2, 10, 25, 0, 6, skip);
284 }
285};
286
287BEAST_DEFINE_TESTSUITE(tx_reduce_relay, ripple_data, ripple);
288} // namespace test
289} // namespace ripple
A version-independent IP address and port combination.
Definition: IPEndpoint.h:39
A testsuite class.
Definition: suite.h:55
log_os< char > log
Logging output stream.
Definition: suite.h:152
void pass()
Record a successful test condition.
Definition: suite.h:511
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:155
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition: suite.h:533
virtual Overlay & overlay()=0
virtual boost::asio::io_service & getIOService()=0
std::size_t TX_REDUCE_RELAY_MIN_PEERS
Definition: Config.h:269
bool TX_REDUCE_RELAY_ENABLE
Definition: Config.h:259
bool TX_REDUCE_RELAY_METRICS
Definition: Config.h:266
std::size_t TX_RELAY_PERCENTAGE
Definition: Config.h:272
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition: Config.cpp:478
std::shared_ptr< PeerFinder::Slot > const & slot()
Definition: PeerImp.h:275
A public key.
Definition: PublicKey.h:62
An endpoint that consumes resources.
Definition: Consumer.h:35
std::size_t size() const noexcept
Definition: Serializer.h:73
void const * data() const noexcept
Definition: Serializer.h:79
A transaction testing environment.
Definition: Env.h:121
Application & app()
Definition: Env.h:261
void send(std::shared_ptr< Message > const &) override
void addTxQueue(uint256 const &hash) override
Aggregate transaction's hash.
PeerTest(Application &app, std::shared_ptr< PeerFinder::Slot > const &slot, http_request_type &&request, PublicKey const &publicKey, ProtocolVersion protocol, Resource::Consumer consumer, std::unique_ptr< tx_reduce_relay_test::stream_type > &&stream_ptr, OverlayImpl &overlay)
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::set< Peer::id_t > const &toSkip={})
void addPeer(jtx::Env &env, std::vector< std::shared_ptr< PeerTest > > &peers, std::uint16_t &nDisabled)
void doTest(std::string const &msg, bool log, std::function< void(bool)> f)
boost::beast::ssl_stream< middle_type > stream_type
void run() override
Runs the suite.
boost::asio::ip::tcp::socket socket_type
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::string makeFeaturesRequestHeader(bool comprEnabled, bool ledgerReplayEnabled, bool txReduceRelayEnabled, bool vpReduceRelayEnabled)
Make request header X-Protocol-Ctl value with supported features.
Definition: Handshake.cpp:75
std::shared_ptr< boost::asio::ssl::context > make_SSLContext(std::string const &cipherList)
Create a self-signed SSL context that allows anonymous Diffie Hellman.
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
Definition: Handoff.h:33
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:386
STL namespace.
T str(T... args)
T to_string(T... args)