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#include <test/jtx.h>
20#include <test/jtx/Env.h>
21#include <xrpld/overlay/detail/OverlayImpl.h>
22#include <xrpld/overlay/detail/PeerImp.h>
23#include <xrpld/peerfinder/detail/SlotImp.h>
24#include <xrpl/basics/make_SSLContext.h>
25#include <xrpl/beast/unit_test.h>
26
27namespace ripple {
28
29namespace test {
30
32{
33public:
34 using socket_type = boost::asio::ip::tcp::socket;
35 using middle_type = boost::beast::tcp_stream;
36 using stream_type = boost::beast::ssl_stream<middle_type>;
38
39private:
40 void
41 doTest(const std::string& msg, bool log, std::function<void(bool)> f)
42 {
43 testcase(msg);
44 f(log);
45 }
46
47 void
49 {
50 doTest("Config Test", log, [&](bool log) {
51 auto test = [&](bool enable,
52 bool metrics,
53 std::uint16_t min,
54 std::uint16_t pct,
55 bool success = true) {
56 std::stringstream str("[reduce_relay]");
57 str << "[reduce_relay]\n"
58 << "tx_enable=" << static_cast<int>(enable) << "\n"
59 << "tx_metrics=" << static_cast<int>(metrics) << "\n"
60 << "tx_min_peers=" << min << "\n"
61 << "tx_relay_percentage=" << pct << "\n";
62 Config c;
63 try
64 {
65 c.loadFromString(str.str());
66
67 BEAST_EXPECT(c.TX_REDUCE_RELAY_ENABLE == enable);
68 BEAST_EXPECT(c.TX_REDUCE_RELAY_METRICS == metrics);
69 BEAST_EXPECT(c.TX_REDUCE_RELAY_MIN_PEERS == min);
70 BEAST_EXPECT(c.TX_RELAY_PERCENTAGE == pct);
71 if (success)
72 pass();
73 else
74 fail();
75 }
76 catch (...)
77 {
78 if (success)
79 fail();
80 else
81 pass();
82 }
83 };
84
85 test(true, true, 20, 25);
86 test(false, false, 20, 25);
87 test(false, false, 20, 0, false);
88 test(false, false, 20, 101, false);
89 test(false, false, 9, 10, false);
90 test(false, false, 10, 9, false);
91 });
92 }
93
94 class PeerTest : public PeerImp
95 {
96 public:
98 Application& app,
100 http_request_type&& request,
101 PublicKey const& publicKey,
103 Resource::Consumer consumer,
105 OverlayImpl& overlay)
106 : PeerImp(
107 app,
108 sid_,
109 slot,
110 std::move(request),
111 publicKey,
112 protocol,
113 consumer,
114 std::move(stream_ptr),
115 overlay)
116 {
117 sid_++;
118 }
119 ~PeerTest() = default;
120
121 void
122 run() override
123 {
124 }
125 void
127 {
128 sendTx_++;
129 }
130 void
131 addTxQueue(const uint256& hash) override
132 {
133 queueTx_++;
134 }
135 static void
137 {
138 queueTx_ = 0;
139 sendTx_ = 0;
140 sid_ = 0;
141 }
142 inline static std::size_t sid_ = 0;
143 inline static std::uint16_t queueTx_ = 0;
144 inline static std::uint16_t sendTx_ = 0;
145 };
146
151 boost::beast::multi_buffer read_buf_;
152
153public:
156 {
157 }
158
159private:
160 void
162 jtx::Env& env,
164 std::uint16_t& nDisabled)
165 {
166 auto& overlay = dynamic_cast<OverlayImpl&>(env.app().overlay());
167 boost::beast::http::request<boost::beast::http::dynamic_body> request;
168 (nDisabled == 0)
169 ? (void)request.insert(
170 "X-Protocol-Ctl",
171 makeFeaturesRequestHeader(false, false, true, false))
172 : (void)nDisabled--;
173 auto stream_ptr = std::make_unique<stream_type>(
174 socket_type(std::forward<boost::asio::io_service&>(
175 env.app().getIOService())),
176 *context_);
178 beast::IP::Address::from_string("172.1.1." + std::to_string(lid_)));
179 beast::IP::Endpoint remote(
180 beast::IP::Address::from_string("172.1.1." + std::to_string(rid_)));
181 PublicKey key(std::get<0>(randomKeyPair(KeyType::ed25519)));
182 auto consumer = overlay.resourceManager().newInboundEndpoint(remote);
183 auto slot = overlay.peerFinder().new_inbound_slot(local, remote);
184 auto const peer = std::make_shared<PeerTest>(
185 env.app(),
186 slot,
187 std::move(request),
188 key,
190 consumer,
191 std::move(stream_ptr),
192 overlay);
193 BEAST_EXPECT(
194 overlay.findPeerByPublicKey(key) == std::shared_ptr<PeerImp>{});
195 overlay.add_active(peer);
196 BEAST_EXPECT(overlay.findPeerByPublicKey(key) == peer);
197 peers.emplace_back(peer); // overlay stores week ptr to PeerImp
198 lid_ += 2;
199 rid_ += 2;
200 assert(lid_ <= 254);
201 }
202
203 void
205 std::string const& test,
206 bool txRREnabled,
207 std::uint16_t nPeers,
208 std::uint16_t nDisabled,
209 std::uint16_t minPeers,
210 std::uint16_t relayPercentage,
211 std::uint16_t expectRelay,
212 std::uint16_t expectQueue,
213 std::set<Peer::id_t> const& toSkip = {})
214 {
215 testcase(test);
216 jtx::Env env(*this);
218 env.app().config().TX_REDUCE_RELAY_ENABLE = txRREnabled;
219 env.app().config().TX_REDUCE_RELAY_MIN_PEERS = minPeers;
220 env.app().config().TX_RELAY_PERCENTAGE = relayPercentage;
222 lid_ = 0;
223 rid_ = 0;
224 for (int i = 0; i < nPeers; i++)
225 addPeer(env, peers, nDisabled);
226
227 auto const jtx = env.jt(noop(env.master));
228 if (BEAST_EXPECT(jtx.stx))
229 {
230 protocol::TMTransaction m;
231 Serializer s;
232 jtx.stx->add(s);
233 m.set_rawtransaction(s.data(), s.size());
234 m.set_deferred(false);
235 m.set_status(protocol::TransactionStatus::tsNEW);
236 env.app().overlay().relay(uint256{0}, m, toSkip);
237 BEAST_EXPECT(
238 PeerTest::sendTx_ == expectRelay &&
239 PeerTest::queueTx_ == expectQueue);
240 }
241 }
242
243 void
244 run() override
245 {
246 bool log = false;
247 std::set<Peer::id_t> skip = {0, 1, 2, 3, 4};
249 // relay to all peers, no hash queue
250 testRelay("feature disabled", false, 10, 0, 10, 25, 10, 0);
251 // relay to nPeers - skip (10-5=5)
252 testRelay("feature disabled & skip", false, 10, 0, 10, 25, 5, 0, skip);
253 // relay to all peers because min is greater than nPeers
254 testRelay("relay all 1", true, 10, 0, 20, 25, 10, 0);
255 // relay to all peers because min + disabled is greater thant nPeers
256 testRelay("relay all 2", true, 20, 15, 10, 25, 20, 0);
257 // relay to minPeers + 25% of nPeers-minPeers (20+0.25*(60-20)=30),
258 // queue the rest (30)
259 testRelay("relay & queue", true, 60, 0, 20, 25, 30, 30);
260 // relay to minPeers + 25% of (nPeers - nPeers) - skip
261 // (20+0.25*(60-20)-5=25), queue the rest, skip counts towards relayed
262 // (60-25-5=30)
263 testRelay("skip", true, 60, 0, 20, 25, 25, 30, skip);
264 // relay to minPeers + disabled + 25% of (nPeers - minPeers - disalbed)
265 // (20+10+0.25*(70-20-10)=40), queue the rest (30)
266 testRelay("disabled", true, 70, 10, 20, 25, 40, 30);
267 // relay to minPeers + disabled-not-in-skip + 25% of (nPeers - minPeers
268 // - disabled) (20+5+0.25*(70-20-10)=35), queue the rest, skip counts
269 // towards relayed (70-35-5=30))
270 testRelay("disabled & skip", true, 70, 10, 20, 25, 35, 30, skip);
271 // relay to minPeers + disabled + 25% of (nPeers - minPeers - disabled)
272 // - skip (10+5+0.25*(15-10-5)-10=5), queue the rest, skip counts
273 // towards relayed (15-5-10=0)
274 skip = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
275 testRelay("disabled & skip, no queue", true, 15, 5, 10, 25, 5, 0, skip);
276 // relay to minPeers + disabled + 25% of (nPeers - minPeers - disabled)
277 // - skip (10+2+0.25*(20-10-2)-14=0), queue the rest, skip counts
278 // towards relayed (20-14=6)
279 skip = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
280 testRelay("disabled & skip, no relay", true, 20, 2, 10, 25, 0, 6, skip);
281 }
282};
283
284BEAST_DEFINE_TESTSUITE(tx_reduce_relay, ripple_data, ripple);
285} // namespace test
286} // namespace ripple
A version-independent IP address and port combination.
Definition: IPEndpoint.h:39
A testsuite class.
Definition: suite.h:53
log_os< char > log
Logging output stream.
Definition: suite.h:150
void pass()
Record a successful test condition.
Definition: suite.h:509
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:153
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition: suite.h:531
virtual Overlay & overlay()=0
virtual boost::asio::io_service & getIOService()=0
std::size_t TX_REDUCE_RELAY_MIN_PEERS
Definition: Config.h:276
bool TX_REDUCE_RELAY_ENABLE
Definition: Config.h:266
bool TX_REDUCE_RELAY_METRICS
Definition: Config.h:273
std::size_t TX_RELAY_PERCENTAGE
Definition: Config.h:279
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition: Config.cpp:476
std::shared_ptr< PeerFinder::Slot > const & slot()
Definition: PeerImp.h:274
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:72
void const * data() const noexcept
Definition: Serializer.h:78
A transaction testing environment.
Definition: Env.h:117
Application & app()
Definition: Env.h:255
void send(std::shared_ptr< Message > const &) override
void addTxQueue(const uint256 &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 doTest(const std::string &msg, bool log, std::function< void(bool)> f)
void addPeer(jtx::Env &env, std::vector< std::shared_ptr< PeerTest > > &peers, std::uint16_t &nDisabled)
boost::beast::ssl_stream< middle_type > stream_type
void run() override
Runs the suite.
boost::asio::ip::tcp::socket socket_type
Json::Value noop(Account const &account)
The null transaction.
Definition: noop.h:31
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:72
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:31
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:368
STL namespace.
T str(T... args)
T to_string(T... args)