rippled
Loading...
Searching...
No Matches
compression_test.cpp
1#include <test/jtx/Account.h>
2#include <test/jtx/Env.h>
3#include <test/jtx/WSClient.h>
4#include <test/jtx/amount.h>
5#include <test/jtx/pay.h>
6
7#include <xrpld/app/ledger/Ledger.h>
8#include <xrpld/app/ledger/LedgerMaster.h>
9#include <xrpld/overlay/Compression.h>
10#include <xrpld/overlay/Message.h>
11#include <xrpld/overlay/detail/Handshake.h>
12#include <xrpld/overlay/detail/ProtocolMessage.h>
13#include <xrpld/overlay/detail/ZeroCopyStream.h>
14
15#include <xrpl/basics/random.h>
16#include <xrpl/beast/unit_test.h>
17#include <xrpl/beast/utility/Journal.h>
18#include <xrpl/protocol/HashPrefix.h>
19#include <xrpl/protocol/PublicKey.h>
20#include <xrpl/protocol/SecretKey.h>
21#include <xrpl/protocol/Sign.h>
22#include <xrpl/protocol/digest.h>
23#include <xrpl/protocol/jss.h>
24#include <xrpl/protocol/messages.h>
25#include <xrpl/shamap/SHAMapNodeID.h>
26
27#include <boost/asio/ip/address_v4.hpp>
28#include <boost/beast/core/multi_buffer.hpp>
29#include <boost/endian/conversion.hpp>
30
31#include <algorithm>
32
33namespace ripple {
34
35namespace test {
36
37using namespace ripple::test;
38using namespace ripple::test::jtx;
39
40static uint256
55
57{
60
61public:
63 {
64 }
65
66 template <typename T>
67 void
70 protocol::MessageType mt,
71 uint16_t nbuffers,
72 std::string msg)
73 {
74 testcase("Compress/Decompress: " + msg);
75
76 Message m(*proto, mt);
77
78 auto& buffer = m.getBuffer(Compressed::On);
79
80 boost::beast::multi_buffer buffers;
81
82 // simulate multi-buffer
83 auto sz = buffer.size() / nbuffers;
84 for (int i = 0; i < nbuffers; i++)
85 {
86 auto start = buffer.begin() + sz * i;
87 auto end = i < nbuffers - 1 ? (buffer.begin() + sz * (i + 1))
88 : buffer.end();
89 std::vector<std::uint8_t> slice(start, end);
90 buffers.commit(boost::asio::buffer_copy(
91 buffers.prepare(slice.size()), boost::asio::buffer(slice)));
92 }
93
94 boost::system::error_code ec;
96 ec, buffers.data(), buffer.size());
97
98 BEAST_EXPECT(header);
99
100 if (!header || header->algorithm == Algorithm::None)
101 return;
102
103 std::vector<std::uint8_t> decompressed;
104 decompressed.resize(header->uncompressed_size);
105
106 BEAST_EXPECT(
107 header->payload_wire_size == buffer.size() - header->header_size);
108
109 ZeroCopyInputStream stream(buffers.data());
110 stream.Skip(header->header_size);
111
112 auto decompressedSize = ripple::compression::decompress(
113 stream,
114 header->payload_wire_size,
115 decompressed.data(),
116 header->uncompressed_size);
117 BEAST_EXPECT(decompressedSize == header->uncompressed_size);
118 auto const proto1 = std::make_shared<T>();
119
120 BEAST_EXPECT(
121 proto1->ParseFromArray(decompressed.data(), decompressedSize));
122 auto uncompressed = m.getBuffer(Compressed::Off);
123 BEAST_EXPECT(std::equal(
124 uncompressed.begin() + ripple::compression::headerBytes,
125 uncompressed.end(),
126 decompressed.begin()));
127 }
128
131 {
133 manifests->mutable_list()->Reserve(n);
134 for (int i = 0; i < n; i++)
135 {
136 auto master = randomKeyPair(KeyType::ed25519);
137 auto signing = randomKeyPair(KeyType::ed25519);
139 st[sfSequence] = i;
140 st[sfPublicKey] = std::get<0>(master);
141 st[sfSigningPubKey] = std::get<0>(signing);
142 st[sfDomain] = makeSlice(
143 std::string("example") + std::to_string(i) +
144 std::string(".com"));
145 sign(
146 st,
149 std::get<1>(master),
150 sfMasterSignature);
151 sign(
152 st,
155 std::get<1>(signing));
156 Serializer s;
157 st.add(s);
158 auto* manifest = manifests->add_list();
159 manifest->set_stobject(s.data(), s.size());
160 }
161 return manifests;
162 }
163
166 {
168 endpoints->mutable_endpoints_v2()->Reserve(n);
169 for (int i = 0; i < n; i++)
170 {
171 auto ep = endpoints->add_endpoints_v2();
172 ep->set_endpoint(std::string("10.0.1.") + std::to_string(i));
173 ep->set_hops(i);
174 }
175 endpoints->set_version(2);
176
177 return endpoints;
178 }
179
182 {
183 Env env(*this, envconfig());
184 int fund = 10000;
185 auto const alice = Account("alice");
186 auto const bob = Account("bob");
187 env.fund(XRP(fund), "alice", "bob");
188 env.trust(bob["USD"](fund), alice);
189 env.close();
190
191 auto toBinary = [this](std::string const& text) {
192 auto blob = strUnHex(text);
193 BEAST_EXPECT(blob);
194 return std::string{
195 reinterpret_cast<char const*>(blob->data()), blob->size()};
196 };
197
198 std::string usdTxBlob = "";
199 auto wsc = makeWSClient(env.app().config());
200 {
201 Json::Value jrequestUsd;
202 jrequestUsd[jss::secret] = toBase58(generateSeed("bob"));
203 jrequestUsd[jss::tx_json] =
204 pay("bob", "alice", bob["USD"](fund / 2));
205 Json::Value jreply_usd = wsc->invoke("sign", jrequestUsd);
206
207 usdTxBlob =
208 toBinary(jreply_usd[jss::result][jss::tx_blob].asString());
209 }
210
212 transaction->set_rawtransaction(usdTxBlob);
213 transaction->set_status(protocol::tsNEW);
214 transaction->set_receivetimestamp(rand_int<std::uint64_t>());
215 transaction->set_deferred(true);
216
217 return transaction;
218 }
219
222 {
224 getLedger->set_itype(protocol::liTS_CANDIDATE);
225 getLedger->set_ltype(protocol::TMLedgerType::ltACCEPTED);
226 uint256 const hash(ripple::sha512Half(123456789));
227 getLedger->set_ledgerhash(hash.begin(), hash.size());
228 getLedger->set_ledgerseq(123456789);
229 ripple::SHAMapNodeID sha(64, hash);
230 getLedger->add_nodeids(sha.getRawString());
231 getLedger->set_requestcookie(123456789);
232 getLedger->set_querytype(protocol::qtINDIRECT);
233 getLedger->set_querydepth(3);
234 return getLedger;
235 }
236
238 buildLedgerData(uint32_t n, Logs& logs)
239 {
241 uint256 const hash(ripple::sha512Half(12356789));
242 ledgerData->set_ledgerhash(hash.data(), hash.size());
243 ledgerData->set_ledgerseq(123456789);
244 ledgerData->set_type(protocol::TMLedgerInfoType::liAS_NODE);
245 ledgerData->set_requestcookie(123456789);
246 ledgerData->set_error(protocol::TMReplyError::reNO_LEDGER);
247 ledgerData->mutable_nodes()->Reserve(n);
248 uint256 parentHash(0);
249
250 NetClock::duration const resolution{10};
251 NetClock::time_point ct{resolution};
252
253 for (int i = 0; i < n; i++)
254 {
255 LedgerInfo info;
256 info.seq = i;
257 info.parentCloseTime = ct;
258 info.hash = ripple::sha512Half(i);
259 info.txHash = ripple::sha512Half(i + 1);
260 info.accountHash = ripple::sha512Half(i + 2);
261 info.parentHash = parentHash;
262 info.drops = XRPAmount(10);
263 info.closeTimeResolution = resolution;
264 info.closeTime = ct;
265 ct += resolution;
266 parentHash = ledgerHash(info);
267 Serializer nData;
268 ripple::addRaw(info, nData);
269 ledgerData->add_nodes()->set_nodedata(
270 nData.getDataPtr(), nData.getLength());
271 }
272
273 return ledgerData;
274 }
275
278 {
280
281 getObject->set_type(protocol::TMGetObjectByHash_ObjectType::
282 TMGetObjectByHash_ObjectType_otTRANSACTION);
283 getObject->set_query(true);
284 getObject->set_seq(123456789);
285 uint256 hash(ripple::sha512Half(123456789));
286 getObject->set_ledgerhash(hash.data(), hash.size());
287 getObject->set_fat(true);
288 for (int i = 0; i < 100; i++)
289 {
291 auto object = getObject->add_objects();
292 object->set_hash(hash.data(), hash.size());
293 ripple::SHAMapNodeID sha(64, hash);
294 object->set_nodeid(sha.getRawString());
295 object->set_index("");
296 object->set_data("");
297 object->set_ledgerseq(i);
298 }
299 return getObject;
300 }
301
304 {
306
307 auto master = randomKeyPair(KeyType::ed25519);
308 auto signing = randomKeyPair(KeyType::ed25519);
310 st[sfSequence] = 0;
311 st[sfPublicKey] = std::get<0>(master);
312 st[sfSigningPubKey] = std::get<0>(signing);
313 st[sfDomain] = makeSlice(std::string("example.com"));
314 sign(
315 st,
318 std::get<1>(master),
319 sfMasterSignature);
321 Serializer s;
322 st.add(s);
323 list->set_manifest(s.data(), s.size());
324 list->set_version(3);
325 STObject signature(sfSignature);
328 Serializer s1;
329 st.add(s1);
330 list->set_signature(s1.data(), s1.size());
331 list->set_blob(strHex(s.slice()));
332 return list;
333 }
334
337 {
339
340 auto master = randomKeyPair(KeyType::ed25519);
341 auto signing = randomKeyPair(KeyType::ed25519);
343 st[sfSequence] = 0;
344 st[sfPublicKey] = std::get<0>(master);
345 st[sfSigningPubKey] = std::get<0>(signing);
346 st[sfDomain] = makeSlice(std::string("example.com"));
347 sign(
348 st,
351 std::get<1>(master),
352 sfMasterSignature);
354 Serializer s;
355 st.add(s);
356 list->set_manifest(s.data(), s.size());
357 list->set_version(4);
358 STObject signature(sfSignature);
361 Serializer s1;
362 st.add(s1);
363 auto& blob = *list->add_blobs();
364 blob.set_signature(s1.data(), s1.size());
365 blob.set_blob(strHex(s.slice()));
366 return list;
367 }
368
369 void
371 {
373 auto logs = std::make_unique<Logs>(thresh);
374
375 protocol::TMManifests manifests;
376 protocol::TMEndpoints endpoints;
377 protocol::TMTransaction transaction;
378 protocol::TMGetLedger get_ledger;
379 protocol::TMLedgerData ledger_data;
380 protocol::TMGetObjectByHash get_object;
381 protocol::TMValidatorList validator_list;
382 protocol::TMValidatorListCollection validator_list_collection;
383
384 // 4.5KB
385 doTest(buildManifests(20), protocol::mtMANIFESTS, 4, "TMManifests20");
386 // 22KB
387 doTest(buildManifests(100), protocol::mtMANIFESTS, 4, "TMManifests100");
388 // 131B
389 doTest(buildEndpoints(10), protocol::mtENDPOINTS, 4, "TMEndpoints10");
390 // 1.3KB
391 doTest(buildEndpoints(100), protocol::mtENDPOINTS, 4, "TMEndpoints100");
392 // 242B
393 doTest(
394 buildTransaction(*logs),
395 protocol::mtTRANSACTION,
396 1,
397 "TMTransaction");
398 // 87B
399 doTest(buildGetLedger(), protocol::mtGET_LEDGER, 1, "TMGetLedger");
400 // 61KB
401 doTest(
402 buildLedgerData(500, *logs),
403 protocol::mtLEDGER_DATA,
404 10,
405 "TMLedgerData500");
406 // 122 KB
407 doTest(
408 buildLedgerData(1000, *logs),
409 protocol::mtLEDGER_DATA,
410 20,
411 "TMLedgerData1000");
412 // 1.2MB
413 doTest(
414 buildLedgerData(10000, *logs),
415 protocol::mtLEDGER_DATA,
416 50,
417 "TMLedgerData10000");
418 // 12MB
419 doTest(
420 buildLedgerData(100000, *logs),
421 protocol::mtLEDGER_DATA,
422 100,
423 "TMLedgerData100000");
424 // 61MB
425 doTest(
426 buildLedgerData(500000, *logs),
427 protocol::mtLEDGER_DATA,
428 100,
429 "TMLedgerData500000");
430 // 7.7KB
431 doTest(
433 protocol::mtGET_OBJECTS,
434 4,
435 "TMGetObjectByHash");
436 // 895B
437 doTest(
439 protocol::mtVALIDATORLIST,
440 4,
441 "TMValidatorList");
442 doTest(
444 protocol::mtVALIDATORLISTCOLLECTION,
445 4,
446 "TMValidatorListCollection");
447 }
448
449 void
451 {
452 testcase("Handshake");
453 auto getEnv = [&](bool enable) {
454 Config c;
456 str << "[reduce_relay]\n"
457 << "vp_base_squelch_enable=1\n"
458 << "[compression]\n"
459 << enable << "\n";
460 c.loadFromString(str.str());
461 auto env = std::make_shared<jtx::Env>(*this);
462 env->app().config().COMPRESSION = c.COMPRESSION;
463 env->app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE =
465 return env;
466 };
467 auto handshake = [&](int outboundEnable, int inboundEnable) {
468 beast::IP::Address addr =
469 boost::asio::ip::make_address("172.1.1.100");
470
471 auto env = getEnv(outboundEnable);
472 auto request = ripple::makeRequest(
473 true,
474 env->app().config().COMPRESSION,
475 false,
476 env->app().config().TX_REDUCE_RELAY_ENABLE,
477 env->app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE);
478 http_request_type http_request;
479 http_request.version(request.version());
480 http_request.base() = request.base();
481 // feature enabled on the peer's connection only if both sides are
482 // enabled
483 auto const peerEnabled = inboundEnable && outboundEnable;
484 // inbound is enabled if the request's header has the feature
485 // enabled and the peer's configuration is enabled
486 auto const inboundEnabled = peerFeatureEnabled(
487 http_request, FEATURE_COMPR, "lz4", inboundEnable);
488 BEAST_EXPECT(!(peerEnabled ^ inboundEnabled));
489
490 env.reset();
491 env = getEnv(inboundEnable);
492 auto http_resp = ripple::makeResponse(
493 true,
494 http_request,
495 addr,
496 addr,
497 uint256{1},
498 1,
499 {1, 0},
500 env->app());
501 // outbound is enabled if the response's header has the feature
502 // enabled and the peer's configuration is enabled
503 auto const outboundEnabled = peerFeatureEnabled(
504 http_resp, FEATURE_COMPR, "lz4", outboundEnable);
505 BEAST_EXPECT(!(peerEnabled ^ outboundEnabled));
506 };
507 handshake(1, 1);
508 handshake(1, 0);
509 handshake(0, 1);
510 handshake(0, 0);
511 }
512
513 void
514 run() override
515 {
516 testProtocol();
518 }
519};
520
521BEAST_DEFINE_TESTSUITE_MANUAL(compression, overlay, ripple);
522
523} // namespace test
524} // namespace ripple
T begin(T... args)
Represents a JSON value.
Definition json_value.h:130
A testsuite class.
Definition suite.h:52
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:152
virtual Config & config()=0
bool VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE
Definition Config.h:229
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition Config.cpp:460
bool COMPRESSION
Definition Config.h:201
Manages partitions for logging.
Definition Log.h:33
std::vector< uint8_t > const & getBuffer(Compressed tryCompressed)
Retrieve the packed message data.
Definition Message.cpp:191
Identifies a node inside a SHAMap.
std::string getRawString() const
void add(Serializer &s) const override
Definition STObject.cpp:122
std::size_t size() const noexcept
Definition Serializer.h:53
void const * data() const noexcept
Definition Serializer.h:59
Slice slice() const noexcept
Definition Serializer.h:47
int getLength() const
Definition Serializer.h:214
void const * getDataPtr() const
Definition Serializer.h:204
constexpr value_type drops() const
Returns the number of drops.
Definition XRPAmount.h:158
Implements ZeroCopyInputStream around a buffer sequence.
iterator begin()
Definition base_uint.h:117
static constexpr std::size_t size()
Definition base_uint.h:507
std::shared_ptr< protocol::TMGetObjectByHash > buildGetObjectByHash()
void run() override
Runs the suite.
std::shared_ptr< protocol::TMManifests > buildManifests(int n)
std::shared_ptr< protocol::TMLedgerData > buildLedgerData(uint32_t n, Logs &logs)
std::shared_ptr< protocol::TMValidatorListCollection > buildValidatorListCollection()
void doTest(std::shared_ptr< T > proto, protocol::MessageType mt, uint16_t nbuffers, std::string msg)
std::shared_ptr< protocol::TMValidatorList > buildValidatorList()
std::shared_ptr< protocol::TMGetLedger > buildGetLedger()
std::shared_ptr< protocol::TMTransaction > buildTransaction(Logs &logs)
std::shared_ptr< protocol::TMEndpoints > buildEndpoints(int n)
Immutable cryptographic account descriptor.
Definition Account.h:20
A transaction testing environment.
Definition Env.h:102
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:103
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition Env.cpp:302
Application & app()
Definition Env.h:242
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:271
T data(T... args)
T equal(T... args)
T is_same_v
boost::asio::ip::address Address
Definition IPAddress.h:20
std::size_t constexpr headerBytes
Definition Compression.h:11
std::size_t decompress(InputStream &in, std::size_t inSize, std::uint8_t *decompressed, std::size_t decompressedSize, Algorithm algorithm=Algorithm::LZ4)
Decompress input stream.
Definition Compression.h:30
std::optional< MessageHeader > parseMessageHeader(boost::system::error_code &ec, BufferSequence const &bufs, std::size_t size)
Parse a message header.
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition pay.cpp:11
void fund(jtx::Env &env, jtx::Account const &gw, std::vector< jtx::Account > const &accounts, std::vector< STAmount > const &amts, Fund how)
Definition AMMTest.cpp:18
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:35
void sign(Json::Value &jv, Account const &account, Json::Value &sigObject)
Sign automatically into a specific Json field of the jv object.
Definition utility.cpp:28
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:92
static uint256 ledgerHash(LedgerInfo const &info)
std::unique_ptr< WSClient > makeWSClient(Config const &cfg, bool v2, unsigned rpc_version, std::unordered_map< std::string, std::string > const &headers)
Returns a client operating through WebSockets/S.
Definition WSClient.cpp:304
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:95
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
static constexpr char FEATURE_COMPR[]
Definition Handshake.h:122
http_response_type makeResponse(bool crawlPublic, http_request_type const &req, beast::IP::Address public_ip, beast::IP::Address remote_ip, uint256 const &sharedValue, std::optional< std::uint32_t > networkID, ProtocolVersion protocol, Application &app)
Make http response.
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &message)
Generate a signature for a message.
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:11
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition Slice.h:225
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
Definition Handoff.h:14
bool peerFeatureEnabled(headers const &request, std::string const &feature, std::string value, bool config)
Check if a feature should be enabled for a peer.
Definition Handshake.h:179
auto makeRequest(bool crawlPublic, bool comprEnabled, bool ledgerReplayEnabled, bool txReduceRelayEnabled, bool vpReduceRelayEnabled) -> request_type
Make outbound http request.
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
SField const sfGeneric
@ manifest
Manifest.
@ ledgerMaster
ledger master data for signing
void addRaw(LedgerHeader const &, Serializer &, bool includeHash=false)
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
Definition Seed.cpp:57
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition digest.h:205
T resize(T... args)
T size(T... args)
T str(T... args)
Information about the notional ledger backing the view.
NetClock::time_point closeTime
NetClock::duration closeTimeResolution
NetClock::time_point parentCloseTime
T time_since_epoch(T... args)
T to_string(T... args)