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/LedgerMaster.h>
8#include <xrpld/overlay/Compression.h>
9#include <xrpld/overlay/Message.h>
10#include <xrpld/overlay/detail/Handshake.h>
11#include <xrpld/overlay/detail/ProtocolMessage.h>
12#include <xrpld/overlay/detail/ZeroCopyStream.h>
13
14#include <xrpl/basics/random.h>
15#include <xrpl/beast/unit_test.h>
16#include <xrpl/beast/utility/Journal.h>
17#include <xrpl/ledger/Ledger.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(
86 boost::asio::buffer_copy(
87 buffers.prepare(slice.size()), boost::asio::buffer(slice)));
88 }
89
90 boost::system::error_code ec;
91 auto header = xrpl::detail::parseMessageHeader(ec, buffers.data(), buffer.size());
92
93 BEAST_EXPECT(header);
94
95 if (!header || header->algorithm == Algorithm::None)
96 return;
97
98 std::vector<std::uint8_t> decompressed;
99 decompressed.resize(header->uncompressed_size);
100
101 BEAST_EXPECT(header->payload_wire_size == buffer.size() - header->header_size);
102
103 ZeroCopyInputStream stream(buffers.data());
104 stream.Skip(header->header_size);
105
106 auto decompressedSize = xrpl::compression::decompress(
107 stream, header->payload_wire_size, decompressed.data(), header->uncompressed_size);
108 BEAST_EXPECT(decompressedSize == header->uncompressed_size);
109 auto const proto1 = std::make_shared<T>();
110
111 BEAST_EXPECT(proto1->ParseFromArray(decompressed.data(), decompressedSize));
112 auto uncompressed = m.getBuffer(Compressed::Off);
113 BEAST_EXPECT(
115 uncompressed.begin() + xrpl::compression::headerBytes,
116 uncompressed.end(),
117 decompressed.begin()));
118 }
119
122 {
124 manifests->mutable_list()->Reserve(n);
125 for (int i = 0; i < n; i++)
126 {
127 auto master = randomKeyPair(KeyType::ed25519);
128 auto signing = randomKeyPair(KeyType::ed25519);
130 st[sfSequence] = i;
131 st[sfPublicKey] = std::get<0>(master);
132 st[sfSigningPubKey] = std::get<0>(signing);
133 st[sfDomain] =
134 makeSlice(std::string("example") + std::to_string(i) + std::string(".com"));
135 sign(
136 st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(master), sfMasterSignature);
138 Serializer s;
139 st.add(s);
140 auto* manifest = manifests->add_list();
141 manifest->set_stobject(s.data(), s.size());
142 }
143 return manifests;
144 }
145
148 {
150 endpoints->mutable_endpoints_v2()->Reserve(n);
151 for (int i = 0; i < n; i++)
152 {
153 auto ep = endpoints->add_endpoints_v2();
154 ep->set_endpoint(std::string("10.0.1.") + std::to_string(i));
155 ep->set_hops(i);
156 }
157 endpoints->set_version(2);
158
159 return endpoints;
160 }
161
164 {
165 Env env(*this, envconfig());
166 int const fund = 10000;
167 auto const alice = Account("alice");
168 auto const bob = Account("bob");
169 env.fund(XRP(fund), "alice", "bob");
170 env.trust(bob["USD"](fund), alice);
171 env.close();
172
173 auto toBinary = [this](std::string const& text) {
174 auto blob = strUnHex(text);
175 BEAST_EXPECT(blob);
176 return std::string{reinterpret_cast<char const*>(blob->data()), blob->size()};
177 };
178
179 std::string usdTxBlob;
180 auto wsc = makeWSClient(env.app().config());
181 {
182 Json::Value requestUSD;
183 requestUSD[jss::secret] = toBase58(generateSeed("bob"));
184 requestUSD[jss::tx_json] = pay("bob", "alice", bob["USD"](fund / 2));
185 Json::Value replyUSD = wsc->invoke("sign", requestUSD);
186
187 usdTxBlob = toBinary(replyUSD[jss::result][jss::tx_blob].asString());
188 }
189
191 transaction->set_rawtransaction(usdTxBlob);
192 transaction->set_status(protocol::tsNEW);
193 transaction->set_receivetimestamp(rand_int<std::uint64_t>());
194 transaction->set_deferred(true);
195
196 return transaction;
197 }
198
201 {
203 getLedger->set_itype(protocol::liTS_CANDIDATE);
204 getLedger->set_ltype(protocol::TMLedgerType::ltACCEPTED);
205 uint256 const hash(xrpl::sha512Half(123456789));
206 getLedger->set_ledgerhash(hash.begin(), hash.size());
207 getLedger->set_ledgerseq(123456789);
208 xrpl::SHAMapNodeID const sha(64, hash);
209 getLedger->add_nodeids(sha.getRawString());
210 getLedger->set_requestcookie(123456789);
211 getLedger->set_querytype(protocol::qtINDIRECT);
212 getLedger->set_querydepth(3);
213 return getLedger;
214 }
215
217 buildLedgerData(uint32_t n, Logs& logs)
218 {
220 uint256 const hash(xrpl::sha512Half(12356789));
221 ledgerData->set_ledgerhash(hash.data(), hash.size());
222 ledgerData->set_ledgerseq(123456789);
223 ledgerData->set_type(protocol::TMLedgerInfoType::liAS_NODE);
224 ledgerData->set_requestcookie(123456789);
225 ledgerData->set_error(protocol::TMReplyError::reNO_LEDGER);
226 ledgerData->mutable_nodes()->Reserve(n);
227 uint256 parentHash(0);
228
229 NetClock::duration const resolution{10};
230 NetClock::time_point ct{resolution};
231
232 for (int i = 0; i < n; i++)
233 {
234 LedgerHeader info;
235 info.seq = i;
236 info.parentCloseTime = ct;
237 info.hash = xrpl::sha512Half(i);
238 info.txHash = xrpl::sha512Half(i + 1);
239 info.accountHash = xrpl::sha512Half(i + 2);
240 info.parentHash = parentHash;
241 info.drops = XRPAmount(10);
242 info.closeTimeResolution = resolution;
243 info.closeTime = ct;
244 ct += resolution;
245 parentHash = ledgerHash(info);
246 Serializer nData;
247 xrpl::addRaw(info, nData);
248 ledgerData->add_nodes()->set_nodedata(nData.getDataPtr(), nData.getLength());
249 }
250
251 return ledgerData;
252 }
253
256 {
258
259 getObject->set_type(
260 protocol::TMGetObjectByHash_ObjectType::TMGetObjectByHash_ObjectType_otTRANSACTION);
261 getObject->set_query(true);
262 getObject->set_seq(123456789);
263 uint256 hash(xrpl::sha512Half(123456789));
264 getObject->set_ledgerhash(hash.data(), hash.size());
265 getObject->set_fat(true);
266 for (int i = 0; i < 100; i++)
267 {
268 uint256 hash(xrpl::sha512Half(i));
269 auto object = getObject->add_objects();
270 object->set_hash(hash.data(), hash.size());
271 xrpl::SHAMapNodeID const sha(64, hash);
272 object->set_nodeid(sha.getRawString());
273 object->set_index("");
274 object->set_data("");
275 object->set_ledgerseq(i);
276 }
277 return getObject;
278 }
279
282 {
284
285 auto master = randomKeyPair(KeyType::ed25519);
286 auto signing = randomKeyPair(KeyType::ed25519);
288 st[sfSequence] = 0;
289 st[sfPublicKey] = std::get<0>(master);
290 st[sfSigningPubKey] = std::get<0>(signing);
291 st[sfDomain] = makeSlice(std::string("example.com"));
292 sign(st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(master), sfMasterSignature);
294 Serializer s;
295 st.add(s);
296 list->set_manifest(s.data(), s.size());
297 list->set_version(3);
298 STObject const signature(sfSignature);
300 Serializer s1;
301 st.add(s1);
302 list->set_signature(s1.data(), s1.size());
303 list->set_blob(strHex(s.slice()));
304 return list;
305 }
306
309 {
311
312 auto master = randomKeyPair(KeyType::ed25519);
313 auto signing = randomKeyPair(KeyType::ed25519);
315 st[sfSequence] = 0;
316 st[sfPublicKey] = std::get<0>(master);
317 st[sfSigningPubKey] = std::get<0>(signing);
318 st[sfDomain] = makeSlice(std::string("example.com"));
319 sign(st, HashPrefix::manifest, KeyType::ed25519, std::get<1>(master), sfMasterSignature);
321 Serializer s;
322 st.add(s);
323 list->set_manifest(s.data(), s.size());
324 list->set_version(4);
325 STObject const signature(sfSignature);
327 Serializer s1;
328 st.add(s1);
329 auto& blob = *list->add_blobs();
330 blob.set_signature(s1.data(), s1.size());
331 blob.set_blob(strHex(s.slice()));
332 return list;
333 }
334
335 void
337 {
339 auto logs = std::make_unique<Logs>(thresh);
340
341 protocol::TMManifests const manifests;
342 protocol::TMEndpoints const endpoints;
343 protocol::TMTransaction const transaction;
344 protocol::TMGetLedger const get_ledger;
345 protocol::TMLedgerData const ledger_data;
346 protocol::TMGetObjectByHash const get_object;
347 protocol::TMValidatorList const validator_list;
348 protocol::TMValidatorListCollection const validator_list_collection;
349
350 // 4.5KB
351 doTest(buildManifests(20), protocol::mtMANIFESTS, 4, "TMManifests20");
352 // 22KB
353 doTest(buildManifests(100), protocol::mtMANIFESTS, 4, "TMManifests100");
354 // 131B
355 doTest(buildEndpoints(10), protocol::mtENDPOINTS, 4, "TMEndpoints10");
356 // 1.3KB
357 doTest(buildEndpoints(100), protocol::mtENDPOINTS, 4, "TMEndpoints100");
358 // 242B
359 doTest(buildTransaction(*logs), protocol::mtTRANSACTION, 1, "TMTransaction");
360 // 87B
361 doTest(buildGetLedger(), protocol::mtGET_LEDGER, 1, "TMGetLedger");
362 // 61KB
363 doTest(buildLedgerData(500, *logs), protocol::mtLEDGER_DATA, 10, "TMLedgerData500");
364 // 122 KB
365 doTest(buildLedgerData(1000, *logs), protocol::mtLEDGER_DATA, 20, "TMLedgerData1000");
366 // 1.2MB
367 doTest(buildLedgerData(10000, *logs), protocol::mtLEDGER_DATA, 50, "TMLedgerData10000");
368 // 12MB
369 doTest(buildLedgerData(100000, *logs), protocol::mtLEDGER_DATA, 100, "TMLedgerData100000");
370 // 61MB
371 doTest(buildLedgerData(500000, *logs), protocol::mtLEDGER_DATA, 100, "TMLedgerData500000");
372 // 7.7KB
373 doTest(buildGetObjectByHash(), protocol::mtGET_OBJECTS, 4, "TMGetObjectByHash");
374 // 895B
375 doTest(buildValidatorList(), protocol::mtVALIDATOR_LIST, 4, "TMValidatorList");
376 doTest(
378 protocol::mtVALIDATOR_LIST_COLLECTION,
379 4,
380 "TMValidatorListCollection");
381 }
382
383 void
385 {
386 testcase("Handshake");
387 auto getEnv = [&](bool enable) {
388 Config c;
390 str << "[reduce_relay]\n"
391 << "vp_base_squelch_enable=1\n"
392 << "[compression]\n"
393 << enable << "\n";
394 c.loadFromString(str.str());
395 auto env = std::make_shared<jtx::Env>(*this);
396 env->app().config().COMPRESSION = c.COMPRESSION;
397 env->app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE =
399 return env;
400 };
401 auto handshake = [&](int outboundEnable, int inboundEnable) {
402 beast::IP::Address const addr = boost::asio::ip::make_address("172.1.1.100");
403
404 auto env = getEnv(outboundEnable);
405 auto request = xrpl::makeRequest(
406 true,
407 env->app().config().COMPRESSION,
408 false,
409 env->app().config().TX_REDUCE_RELAY_ENABLE,
410 env->app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE);
411 http_request_type http_request;
412 http_request.version(request.version());
413 http_request.base() = request.base();
414 // feature enabled on the peer's connection only if both sides are
415 // enabled
416 auto const peerEnabled = inboundEnable && outboundEnable;
417 // inbound is enabled if the request's header has the feature
418 // enabled and the peer's configuration is enabled
419 auto const inboundEnabled =
420 peerFeatureEnabled(http_request, FEATURE_COMPR, "lz4", inboundEnable);
421 BEAST_EXPECT(!(peerEnabled ^ inboundEnabled));
422
423 env.reset();
424 env = getEnv(inboundEnable);
425 auto http_resp = xrpl::makeResponse(
426 true, http_request, addr, addr, uint256{1}, 1, {1, 0}, env->app());
427 // outbound is enabled if the response's header has the feature
428 // enabled and the peer's configuration is enabled
429 auto const outboundEnabled =
430 peerFeatureEnabled(http_resp, FEATURE_COMPR, "lz4", outboundEnable);
431 BEAST_EXPECT(!(peerEnabled ^ outboundEnabled));
432 };
433 handshake(1, 1);
434 handshake(1, 0);
435 handshake(0, 1);
436 handshake(0, 0);
437 }
438
439 void
440 run() override
441 {
442 testProtocol();
444 }
445};
446
447BEAST_DEFINE_TESTSUITE_MANUAL(compression, overlay, xrpl);
448
449} // namespace test
450} // namespace xrpl
T begin(T... args)
Represents a JSON value.
Definition json_value.h:130
A testsuite class.
Definition suite.h:51
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:150
virtual Config & config()=0
bool COMPRESSION
Definition Config.h:205
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition Config.cpp:452
bool VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE
Definition Config.h:233
Manages partitions for logging.
Definition Log.h:32
std::vector< uint8_t > const & getBuffer(Compressed tryCompressed)
Retrieve the packed message data.
Definition Message.cpp:187
Identifies a node inside a SHAMap.
std::string getRawString() const
void add(Serializer &s) const override
Definition STObject.cpp:119
void const * getDataPtr() const
Definition Serializer.h:197
int getLength() const
Definition Serializer.h:207
Slice slice() const noexcept
Definition Serializer.h:44
std::size_t size() const noexcept
Definition Serializer.h:50
void const * data() const noexcept
Definition Serializer.h:56
constexpr value_type drops() const
Returns the number of drops.
Definition XRPAmount.h:157
Implements ZeroCopyInputStream around a buffer sequence.
iterator begin()
Definition base_uint.h:112
pointer data()
Definition base_uint.h:101
static constexpr std::size_t size()
Definition base_uint.h:499
static std::shared_ptr< protocol::TMEndpoints > buildEndpoints(int n)
void doTest(std::shared_ptr< T > proto, protocol::MessageType mt, uint16_t nbuffers, std::string msg)
static std::shared_ptr< protocol::TMValidatorList > buildValidatorList()
static std::shared_ptr< protocol::TMLedgerData > buildLedgerData(uint32_t n, Logs &logs)
std::shared_ptr< protocol::TMTransaction > buildTransaction(Logs &logs)
static std::shared_ptr< protocol::TMValidatorListCollection > buildValidatorListCollection()
static std::shared_ptr< protocol::TMGetLedger > buildGetLedger()
void run() override
Runs the suite.
static std::shared_ptr< protocol::TMGetObjectByHash > buildGetObjectByHash()
static std::shared_ptr< protocol::TMManifests > buildManifests(int n)
Immutable cryptographic account descriptor.
Definition Account.h:19
A transaction testing environment.
Definition Env.h:122
Application & app()
Definition Env.h:259
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:100
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:270
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition Env.cpp:301
T data(T... args)
T equal(T... args)
T is_same_v
boost::asio::ip::address Address
Definition IPAddress.h:19
std::size_t constexpr headerBytes
Definition Compression.h:10
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:29
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:95
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:34
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:296
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.
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition digest.h:204
static constexpr char FEATURE_COMPR[]
Definition Handshake.h:118
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:10
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
Definition Handoff.h:12
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:171
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:215
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)