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 xrpl {
34
35namespace test {
36
37using namespace xrpl::test;
38using namespace xrpl::test::jtx;
39
40static uint256
55
57{
60
61public:
63 {
64 }
65
66 template <typename T>
67 void
68 doTest(std::shared_ptr<T> proto, protocol::MessageType mt, uint16_t nbuffers, std::string msg)
69 {
70 testcase("Compress/Decompress: " + msg);
71
72 Message m(*proto, mt);
73
74 auto& buffer = m.getBuffer(Compressed::On);
75
76 boost::beast::multi_buffer buffers;
77
78 // simulate multi-buffer
79 auto sz = buffer.size() / nbuffers;
80 for (int i = 0; i < nbuffers; i++)
81 {
82 auto start = buffer.begin() + sz * i;
83 auto end = i < nbuffers - 1 ? (buffer.begin() + sz * (i + 1)) : buffer.end();
84 std::vector<std::uint8_t> slice(start, end);
85 buffers.commit(boost::asio::buffer_copy(buffers.prepare(slice.size()), boost::asio::buffer(slice)));
86 }
87
88 boost::system::error_code ec;
89 auto header = xrpl::detail::parseMessageHeader(ec, buffers.data(), buffer.size());
90
91 BEAST_EXPECT(header);
92
93 if (!header || header->algorithm == Algorithm::None)
94 return;
95
96 std::vector<std::uint8_t> decompressed;
97 decompressed.resize(header->uncompressed_size);
98
99 BEAST_EXPECT(header->payload_wire_size == buffer.size() - header->header_size);
100
101 ZeroCopyInputStream stream(buffers.data());
102 stream.Skip(header->header_size);
103
104 auto decompressedSize = xrpl::compression::decompress(
105 stream, header->payload_wire_size, decompressed.data(), header->uncompressed_size);
106 BEAST_EXPECT(decompressedSize == header->uncompressed_size);
107 auto const proto1 = std::make_shared<T>();
108
109 BEAST_EXPECT(proto1->ParseFromArray(decompressed.data(), decompressedSize));
110 auto uncompressed = m.getBuffer(Compressed::Off);
111 BEAST_EXPECT(std::equal(
112 uncompressed.begin() + xrpl::compression::headerBytes, uncompressed.end(), decompressed.begin()));
113 }
114
117 {
119 manifests->mutable_list()->Reserve(n);
120 for (int i = 0; i < n; i++)
121 {
122 auto master = randomKeyPair(KeyType::ed25519);
123 auto signing = randomKeyPair(KeyType::ed25519);
125 st[sfSequence] = i;
126 st[sfPublicKey] = std::get<0>(master);
127 st[sfSigningPubKey] = std::get<0>(signing);
128 st[sfDomain] = makeSlice(std::string("example") + std::to_string(i) + std::string(".com"));
129 sign(st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(master), sfMasterSignature);
131 Serializer s;
132 st.add(s);
133 auto* manifest = manifests->add_list();
134 manifest->set_stobject(s.data(), s.size());
135 }
136 return manifests;
137 }
138
141 {
143 endpoints->mutable_endpoints_v2()->Reserve(n);
144 for (int i = 0; i < n; i++)
145 {
146 auto ep = endpoints->add_endpoints_v2();
147 ep->set_endpoint(std::string("10.0.1.") + std::to_string(i));
148 ep->set_hops(i);
149 }
150 endpoints->set_version(2);
151
152 return endpoints;
153 }
154
157 {
158 Env env(*this, envconfig());
159 int fund = 10000;
160 auto const alice = Account("alice");
161 auto const bob = Account("bob");
162 env.fund(XRP(fund), "alice", "bob");
163 env.trust(bob["USD"](fund), alice);
164 env.close();
165
166 auto toBinary = [this](std::string const& text) {
167 auto blob = strUnHex(text);
168 BEAST_EXPECT(blob);
169 return std::string{reinterpret_cast<char const*>(blob->data()), blob->size()};
170 };
171
172 std::string usdTxBlob = "";
173 auto wsc = makeWSClient(env.app().config());
174 {
175 Json::Value jrequestUsd;
176 jrequestUsd[jss::secret] = toBase58(generateSeed("bob"));
177 jrequestUsd[jss::tx_json] = pay("bob", "alice", bob["USD"](fund / 2));
178 Json::Value jreply_usd = wsc->invoke("sign", jrequestUsd);
179
180 usdTxBlob = toBinary(jreply_usd[jss::result][jss::tx_blob].asString());
181 }
182
184 transaction->set_rawtransaction(usdTxBlob);
185 transaction->set_status(protocol::tsNEW);
186 transaction->set_receivetimestamp(rand_int<std::uint64_t>());
187 transaction->set_deferred(true);
188
189 return transaction;
190 }
191
194 {
196 getLedger->set_itype(protocol::liTS_CANDIDATE);
197 getLedger->set_ltype(protocol::TMLedgerType::ltACCEPTED);
198 uint256 const hash(xrpl::sha512Half(123456789));
199 getLedger->set_ledgerhash(hash.begin(), hash.size());
200 getLedger->set_ledgerseq(123456789);
201 xrpl::SHAMapNodeID sha(64, hash);
202 getLedger->add_nodeids(sha.getRawString());
203 getLedger->set_requestcookie(123456789);
204 getLedger->set_querytype(protocol::qtINDIRECT);
205 getLedger->set_querydepth(3);
206 return getLedger;
207 }
208
210 buildLedgerData(uint32_t n, Logs& logs)
211 {
213 uint256 const hash(xrpl::sha512Half(12356789));
214 ledgerData->set_ledgerhash(hash.data(), hash.size());
215 ledgerData->set_ledgerseq(123456789);
216 ledgerData->set_type(protocol::TMLedgerInfoType::liAS_NODE);
217 ledgerData->set_requestcookie(123456789);
218 ledgerData->set_error(protocol::TMReplyError::reNO_LEDGER);
219 ledgerData->mutable_nodes()->Reserve(n);
220 uint256 parentHash(0);
221
222 NetClock::duration const resolution{10};
223 NetClock::time_point ct{resolution};
224
225 for (int i = 0; i < n; i++)
226 {
227 LedgerHeader info;
228 info.seq = i;
229 info.parentCloseTime = ct;
230 info.hash = xrpl::sha512Half(i);
231 info.txHash = xrpl::sha512Half(i + 1);
232 info.accountHash = xrpl::sha512Half(i + 2);
233 info.parentHash = parentHash;
234 info.drops = XRPAmount(10);
235 info.closeTimeResolution = resolution;
236 info.closeTime = ct;
237 ct += resolution;
238 parentHash = ledgerHash(info);
239 Serializer nData;
240 xrpl::addRaw(info, nData);
241 ledgerData->add_nodes()->set_nodedata(nData.getDataPtr(), nData.getLength());
242 }
243
244 return ledgerData;
245 }
246
249 {
251
252 getObject->set_type(protocol::TMGetObjectByHash_ObjectType::TMGetObjectByHash_ObjectType_otTRANSACTION);
253 getObject->set_query(true);
254 getObject->set_seq(123456789);
255 uint256 hash(xrpl::sha512Half(123456789));
256 getObject->set_ledgerhash(hash.data(), hash.size());
257 getObject->set_fat(true);
258 for (int i = 0; i < 100; i++)
259 {
260 uint256 hash(xrpl::sha512Half(i));
261 auto object = getObject->add_objects();
262 object->set_hash(hash.data(), hash.size());
263 xrpl::SHAMapNodeID sha(64, hash);
264 object->set_nodeid(sha.getRawString());
265 object->set_index("");
266 object->set_data("");
267 object->set_ledgerseq(i);
268 }
269 return getObject;
270 }
271
274 {
276
277 auto master = randomKeyPair(KeyType::ed25519);
278 auto signing = randomKeyPair(KeyType::ed25519);
280 st[sfSequence] = 0;
281 st[sfPublicKey] = std::get<0>(master);
282 st[sfSigningPubKey] = std::get<0>(signing);
283 st[sfDomain] = makeSlice(std::string("example.com"));
284 sign(st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(master), sfMasterSignature);
286 Serializer s;
287 st.add(s);
288 list->set_manifest(s.data(), s.size());
289 list->set_version(3);
290 STObject signature(sfSignature);
292 Serializer s1;
293 st.add(s1);
294 list->set_signature(s1.data(), s1.size());
295 list->set_blob(strHex(s.slice()));
296 return list;
297 }
298
301 {
303
304 auto master = randomKeyPair(KeyType::ed25519);
305 auto signing = randomKeyPair(KeyType::ed25519);
307 st[sfSequence] = 0;
308 st[sfPublicKey] = std::get<0>(master);
309 st[sfSigningPubKey] = std::get<0>(signing);
310 st[sfDomain] = makeSlice(std::string("example.com"));
311 sign(st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(master), sfMasterSignature);
313 Serializer s;
314 st.add(s);
315 list->set_manifest(s.data(), s.size());
316 list->set_version(4);
317 STObject signature(sfSignature);
319 Serializer s1;
320 st.add(s1);
321 auto& blob = *list->add_blobs();
322 blob.set_signature(s1.data(), s1.size());
323 blob.set_blob(strHex(s.slice()));
324 return list;
325 }
326
327 void
329 {
331 auto logs = std::make_unique<Logs>(thresh);
332
333 protocol::TMManifests manifests;
334 protocol::TMEndpoints endpoints;
335 protocol::TMTransaction transaction;
336 protocol::TMGetLedger get_ledger;
337 protocol::TMLedgerData ledger_data;
338 protocol::TMGetObjectByHash get_object;
339 protocol::TMValidatorList validator_list;
340 protocol::TMValidatorListCollection validator_list_collection;
341
342 // 4.5KB
343 doTest(buildManifests(20), protocol::mtMANIFESTS, 4, "TMManifests20");
344 // 22KB
345 doTest(buildManifests(100), protocol::mtMANIFESTS, 4, "TMManifests100");
346 // 131B
347 doTest(buildEndpoints(10), protocol::mtENDPOINTS, 4, "TMEndpoints10");
348 // 1.3KB
349 doTest(buildEndpoints(100), protocol::mtENDPOINTS, 4, "TMEndpoints100");
350 // 242B
351 doTest(buildTransaction(*logs), protocol::mtTRANSACTION, 1, "TMTransaction");
352 // 87B
353 doTest(buildGetLedger(), protocol::mtGET_LEDGER, 1, "TMGetLedger");
354 // 61KB
355 doTest(buildLedgerData(500, *logs), protocol::mtLEDGER_DATA, 10, "TMLedgerData500");
356 // 122 KB
357 doTest(buildLedgerData(1000, *logs), protocol::mtLEDGER_DATA, 20, "TMLedgerData1000");
358 // 1.2MB
359 doTest(buildLedgerData(10000, *logs), protocol::mtLEDGER_DATA, 50, "TMLedgerData10000");
360 // 12MB
361 doTest(buildLedgerData(100000, *logs), protocol::mtLEDGER_DATA, 100, "TMLedgerData100000");
362 // 61MB
363 doTest(buildLedgerData(500000, *logs), protocol::mtLEDGER_DATA, 100, "TMLedgerData500000");
364 // 7.7KB
365 doTest(buildGetObjectByHash(), protocol::mtGET_OBJECTS, 4, "TMGetObjectByHash");
366 // 895B
367 doTest(buildValidatorList(), protocol::mtVALIDATOR_LIST, 4, "TMValidatorList");
368 doTest(buildValidatorListCollection(), protocol::mtVALIDATOR_LIST_COLLECTION, 4, "TMValidatorListCollection");
369 }
370
371 void
373 {
374 testcase("Handshake");
375 auto getEnv = [&](bool enable) {
376 Config c;
378 str << "[reduce_relay]\n"
379 << "vp_base_squelch_enable=1\n"
380 << "[compression]\n"
381 << enable << "\n";
382 c.loadFromString(str.str());
383 auto env = std::make_shared<jtx::Env>(*this);
384 env->app().config().COMPRESSION = c.COMPRESSION;
385 env->app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = c.VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE;
386 return env;
387 };
388 auto handshake = [&](int outboundEnable, int inboundEnable) {
389 beast::IP::Address addr = boost::asio::ip::make_address("172.1.1.100");
390
391 auto env = getEnv(outboundEnable);
392 auto request = xrpl::makeRequest(
393 true,
394 env->app().config().COMPRESSION,
395 false,
396 env->app().config().TX_REDUCE_RELAY_ENABLE,
397 env->app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE);
398 http_request_type http_request;
399 http_request.version(request.version());
400 http_request.base() = request.base();
401 // feature enabled on the peer's connection only if both sides are
402 // enabled
403 auto const peerEnabled = inboundEnable && outboundEnable;
404 // inbound is enabled if the request's header has the feature
405 // enabled and the peer's configuration is enabled
406 auto const inboundEnabled = peerFeatureEnabled(http_request, FEATURE_COMPR, "lz4", inboundEnable);
407 BEAST_EXPECT(!(peerEnabled ^ inboundEnabled));
408
409 env.reset();
410 env = getEnv(inboundEnable);
411 auto http_resp = xrpl::makeResponse(true, http_request, addr, addr, uint256{1}, 1, {1, 0}, env->app());
412 // outbound is enabled if the response's header has the feature
413 // enabled and the peer's configuration is enabled
414 auto const outboundEnabled = peerFeatureEnabled(http_resp, FEATURE_COMPR, "lz4", outboundEnable);
415 BEAST_EXPECT(!(peerEnabled ^ outboundEnabled));
416 };
417 handshake(1, 1);
418 handshake(1, 0);
419 handshake(0, 1);
420 handshake(0, 0);
421 }
422
423 void
424 run() override
425 {
426 testProtocol();
428 }
429};
430
431BEAST_DEFINE_TESTSUITE_MANUAL(compression, overlay, xrpl);
432
433} // namespace test
434} // namespace xrpl
T begin(T... args)
Represents a JSON value.
Definition json_value.h:131
A testsuite class.
Definition suite.h:52
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:148
virtual Config & config()=0
bool COMPRESSION
Definition Config.h:201
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition Config.cpp:440
bool VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE
Definition Config.h:229
Manages partitions for logging.
Definition Log.h:33
std::vector< uint8_t > const & getBuffer(Compressed tryCompressed)
Retrieve the packed message data.
Definition Message.cpp:180
Identifies a node inside a SHAMap.
std::string getRawString() const
void add(Serializer &s) const override
Definition STObject.cpp:117
void const * getDataPtr() const
Definition Serializer.h:198
int getLength() const
Definition Serializer.h:208
Slice slice() const noexcept
Definition Serializer.h:45
std::size_t size() const noexcept
Definition Serializer.h:51
void const * data() const noexcept
Definition Serializer.h:57
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:113
pointer data()
Definition base_uint.h:102
static constexpr std::size_t size()
Definition base_uint.h:495
std::shared_ptr< protocol::TMLedgerData > buildLedgerData(uint32_t n, Logs &logs)
void doTest(std::shared_ptr< T > proto, protocol::MessageType mt, uint16_t nbuffers, std::string msg)
std::shared_ptr< protocol::TMValidatorListCollection > buildValidatorListCollection()
std::shared_ptr< protocol::TMValidatorList > buildValidatorList()
std::shared_ptr< protocol::TMManifests > buildManifests(int n)
std::shared_ptr< protocol::TMTransaction > buildTransaction(Logs &logs)
std::shared_ptr< protocol::TMEndpoints > buildEndpoints(int n)
void run() override
Runs the suite.
std::shared_ptr< protocol::TMGetObjectByHash > buildGetObjectByHash()
std::shared_ptr< protocol::TMGetLedger > buildGetLedger()
Immutable cryptographic account descriptor.
Definition Account.h:20
A transaction testing environment.
Definition Env.h:98
Application & app()
Definition Env.h:230
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:97
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:260
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition Env.cpp:283
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.
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
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:90
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition pay.cpp:11
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:27
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:35
static uint256 ledgerHash(LedgerHeader 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:285
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition digest.h:205
static constexpr char FEATURE_COMPR[]
Definition Handshake.h:119
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:11
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
Definition Handoff.h:13
SField const sfGeneric
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:92
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
Definition Seed.cpp:57
auto makeRequest(bool crawlPublic, bool comprEnabled, bool ledgerReplayEnabled, bool txReduceRelayEnabled, bool vpReduceRelayEnabled) -> request_type
Make outbound http request.
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
void addRaw(LedgerHeader const &, Serializer &, bool includeHash=false)
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:169
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.
@ manifest
Manifest.
@ ledgerMaster
ledger master data for signing
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &message)
Generate a signature for a message.
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:214
T resize(T... args)
T size(T... args)
T str(T... args)
Information about the notional ledger backing the view.
NetClock::time_point parentCloseTime
NetClock::duration closeTimeResolution
NetClock::time_point closeTime
T time_since_epoch(T... args)
T to_string(T... args)