rippled
Loading...
Searching...
No Matches
LedgerRPC_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-2016 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/Oracle.h>
22#include <test/jtx/attester.h>
23#include <test/jtx/delegate.h>
24#include <test/jtx/multisign.h>
25#include <test/jtx/xchain_bridge.h>
26
27#include <xrpld/app/misc/TxQ.h>
28
29#include <xrpl/beast/unit_test.h>
30#include <xrpl/json/json_value.h>
31#include <xrpl/protocol/ErrorCodes.h>
32#include <xrpl/protocol/jss.h>
33
34namespace ripple {
35
36namespace test {
37
39{
40 void
42 Json::Value const& jv,
43 std::string const& err,
44 std::string const& msg)
45 {
46 if (BEAST_EXPECT(jv.isMember(jss::status)))
47 BEAST_EXPECT(jv[jss::status] == "error");
48 if (BEAST_EXPECT(jv.isMember(jss::error)))
49 BEAST_EXPECT(jv[jss::error] == err);
50 if (msg.empty())
51 {
52 BEAST_EXPECT(
53 jv[jss::error_message] == Json::nullValue ||
54 jv[jss::error_message] == "");
55 }
56 else if (BEAST_EXPECT(jv.isMember(jss::error_message)))
57 BEAST_EXPECT(jv[jss::error_message] == msg);
58 }
59
60 // Corrupt a valid address by replacing the 10th character with '!'.
61 // '!' is not part of the ripple alphabet.
64 {
65 std::string ret = std::move(good);
66 ret.replace(10, 1, 1, '!');
67 return ret;
68 }
69
70 void
72 {
73 testcase("Basic Request");
74 using namespace test::jtx;
75
76 Env env{*this};
77
78 env.close();
79 BEAST_EXPECT(env.current()->info().seq == 4);
80
81 {
82 Json::Value jvParams;
83 // can be either numeric or quoted numeric
84 jvParams[jss::ledger_index] = 1;
85 auto const jrr =
86 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
87 BEAST_EXPECT(jrr[jss::ledger][jss::closed] == true);
88 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "1");
89 }
90
91 {
92 Json::Value jvParams;
93 jvParams[jss::ledger_index] = "1";
94 auto const jrr =
95 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
96 BEAST_EXPECT(jrr[jss::ledger][jss::closed] == true);
97 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "1");
98 }
99
100 {
101 // using current identifier
102 auto const jrr = env.rpc("ledger", "current")[jss::result];
103 BEAST_EXPECT(jrr[jss::ledger][jss::closed] == false);
104 BEAST_EXPECT(
105 jrr[jss::ledger][jss::ledger_index] ==
106 std::to_string(env.current()->info().seq));
107 BEAST_EXPECT(
108 jrr[jss::ledger_current_index] == env.current()->info().seq);
109 }
110 }
111
112 void
114 {
115 testcase("Bad Input");
116 using namespace test::jtx;
117 Env env{*this};
118 Account const gw{"gateway"};
119 auto const USD = gw["USD"];
120 Account const bob{"bob"};
121
122 env.fund(XRP(10000), gw, bob);
123 env.close();
124 env.trust(USD(1000), bob);
125 env.close();
126
127 {
128 // ask for an arbitrary string - index
129 Json::Value jvParams;
130 jvParams[jss::ledger_index] = "potato";
131 auto const jrr =
132 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
133 checkErrorValue(jrr, "invalidParams", "ledgerIndexMalformed");
134 }
135
136 {
137 // ask for a negative index
138 Json::Value jvParams;
139 jvParams[jss::ledger_index] = -1;
140 auto const jrr =
141 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
142 checkErrorValue(jrr, "invalidParams", "ledgerIndexMalformed");
143 }
144
145 {
146 // ask for a bad ledger index
147 Json::Value jvParams;
148 jvParams[jss::ledger_index] = 10u;
149 auto const jrr =
150 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
151 checkErrorValue(jrr, "lgrNotFound", "ledgerNotFound");
152 }
153
154 {
155 // unrecognized string arg -- error
156 auto const jrr = env.rpc("ledger", "arbitrary_text")[jss::result];
157 checkErrorValue(jrr, "lgrNotFound", "ledgerNotFound");
158 }
159
160 {
161 // Request queue for closed ledger
162 Json::Value jvParams;
163 jvParams[jss::ledger_index] = "validated";
164 jvParams[jss::queue] = true;
165 auto const jrr =
166 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
167 checkErrorValue(jrr, "invalidParams", "Invalid parameters.");
168 }
169
170 {
171 // Request a ledger with a very large (double) sequence.
172 auto const ret =
173 env.rpc("json", "ledger", "{ \"ledger_index\" : 2e15 }");
174 BEAST_EXPECT(RPC::contains_error(ret));
175 BEAST_EXPECT(ret[jss::error_message] == "Invalid parameters.");
176 }
177
178 {
179 // Request a ledger with very large (integer) sequence.
180 auto const ret = env.rpc(
181 "json", "ledger", "{ \"ledger_index\" : 1000000000000000 }");
182 checkErrorValue(ret, "invalidParams", "Invalid parameters.");
183 }
184 }
185
186 void
188 {
189 testcase("ledger_current Request");
190 using namespace test::jtx;
191
192 Env env{*this};
193
194 env.close();
195 BEAST_EXPECT(env.current()->info().seq == 4);
196
197 {
198 auto const jrr = env.rpc("ledger_current")[jss::result];
199 BEAST_EXPECT(
200 jrr[jss::ledger_current_index] == env.current()->info().seq);
201 }
202 }
203
204 void
206 {
207 testcase("Ledger Request, Full Option");
208 using namespace test::jtx;
209
210 Env env{*this};
211
212 env.close();
213
214 Json::Value jvParams;
215 jvParams[jss::ledger_index] = 3u;
216 jvParams[jss::full] = true;
217 auto const jrr =
218 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
219 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
220 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
221 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 3u);
222 }
223
224 void
226 {
227 testcase("Ledger Request, Full Option Without Admin");
228 using namespace test::jtx;
229
230 Env env{*this, envconfig(no_admin)};
231
232 // env.close();
233
234 Json::Value jvParams;
235 jvParams[jss::ledger_index] = 1u;
236 jvParams[jss::full] = true;
237 auto const jrr =
238 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
240 jrr, "noPermission", "You don't have permission for this command.");
241 }
242
243 void
245 {
246 testcase("Ledger Request, Accounts Option");
247 using namespace test::jtx;
248
249 Env env{*this};
250
251 env.close();
252
253 Json::Value jvParams;
254 jvParams[jss::ledger_index] = 3u;
255 jvParams[jss::accounts] = true;
256 auto const jrr =
257 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
258 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
259 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
260 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 3u);
261 }
262
267 void
269 {
270 testcase("Lookup ledger");
271 using namespace test::jtx;
272
273 auto cfg = envconfig();
274 cfg->FEES.reference_fee = 10;
275 Env env{
276 *this, std::move(cfg), FeatureBitset{}}; // hashes requested below
277 // assume no amendments
278 env.fund(XRP(10000), "alice");
279 env.close();
280 env.fund(XRP(10000), "bob");
281 env.close();
282 env.fund(XRP(10000), "jim");
283 env.close();
284 env.fund(XRP(10000), "jill");
285
286 {
287 // access via the legacy ledger field, keyword index values
288 Json::Value jvParams;
289 jvParams[jss::ledger] = "closed";
290 auto jrr =
291 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
292 BEAST_EXPECT(jrr.isMember(jss::ledger));
293 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
294 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
295
296 jvParams[jss::ledger] = "validated";
297 jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
298 BEAST_EXPECT(jrr.isMember(jss::ledger));
299 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
300 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
301
302 jvParams[jss::ledger] = "current";
303 jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
304 BEAST_EXPECT(jrr.isMember(jss::ledger));
305 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
306
307 // ask for a bad ledger keyword
308 jvParams[jss::ledger] = "invalid";
309 jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
310 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
311 BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
312
313 // numeric index
314 jvParams[jss::ledger] = 4;
315 jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
316 BEAST_EXPECT(jrr.isMember(jss::ledger));
317 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
318 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "4");
319
320 // numeric index - out of range
321 jvParams[jss::ledger] = 20;
322 jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
323 BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
324 BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
325 }
326
327 {
328 std::string const hash3{
329 "E86DE7F3D7A4D9CE17EF7C8BA08A8F4D"
330 "8F643B9552F0D895A31CDA78F541DE4E"};
331 // access via the ledger_hash field
332 Json::Value jvParams;
333 jvParams[jss::ledger_hash] = hash3;
334 auto jrr =
335 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
336 BEAST_EXPECT(jrr.isMember(jss::ledger));
337 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
338 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "3");
339
340 // extra leading hex chars in hash are not allowed
341 jvParams[jss::ledger_hash] = "DEADBEEF" + hash3;
342 jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
343 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
344 BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
345
346 // request with non-string ledger_hash
347 jvParams[jss::ledger_hash] = 2;
348 jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
349 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
350 BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashNotString");
351
352 // malformed (non hex) hash
353 jvParams[jss::ledger_hash] =
354 "2E81FC6EC0DD943197EGC7E3FBE9AE30"
355 "7F2775F2F7485BB37307984C3C0F2340";
356 jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
357 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
358 BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
359
360 // properly formed, but just doesn't exist
361 jvParams[jss::ledger_hash] =
362 "8C3EEDB3124D92E49E75D81A8826A2E6"
363 "5A75FD71FC3FD6F36FEB803C5F1D812D";
364 jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
365 BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
366 BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
367 }
368
369 {
370 // access via the ledger_index field, keyword index values
371 Json::Value jvParams;
372 jvParams[jss::ledger_index] = "closed";
373 auto jrr =
374 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
375 BEAST_EXPECT(jrr.isMember(jss::ledger));
376 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
377 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
378 BEAST_EXPECT(jrr.isMember(jss::ledger_index));
379
380 jvParams[jss::ledger_index] = "validated";
381 jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
382 BEAST_EXPECT(jrr.isMember(jss::ledger));
383 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
384 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
385
386 jvParams[jss::ledger_index] = "current";
387 jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
388 BEAST_EXPECT(jrr.isMember(jss::ledger));
389 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
390 BEAST_EXPECT(jrr.isMember(jss::ledger_current_index));
391
392 // ask for a bad ledger keyword
393 jvParams[jss::ledger_index] = "invalid";
394 jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
395 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
396 BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
397
398 // numeric index
399 for (auto i : {1, 2, 3, 4, 5, 6})
400 {
401 jvParams[jss::ledger_index] = i;
402 jrr =
403 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
404 BEAST_EXPECT(jrr.isMember(jss::ledger));
405 if (i < 6)
406 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
407 BEAST_EXPECT(
408 jrr[jss::ledger][jss::ledger_index] == std::to_string(i));
409 }
410
411 // numeric index - out of range
412 jvParams[jss::ledger_index] = 7;
413 jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
414 BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
415 BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
416 }
417 }
418
419 void
421 {
422 testcase("Ledger with queueing disabled");
423 using namespace test::jtx;
424 Env env{*this};
425
426 Json::Value jv;
427 jv[jss::ledger_index] = "current";
428 jv[jss::queue] = true;
429 jv[jss::expand] = true;
430
431 auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
432 BEAST_EXPECT(!jrr.isMember(jss::queue_data));
433 }
434
435 void
437 {
438 testcase("Ledger with Queued Transactions");
439 using namespace test::jtx;
440 auto cfg = envconfig([](std::unique_ptr<Config> cfg) {
441 auto& section = cfg->section("transaction_queue");
442 section.set("minimum_txn_in_ledger_standalone", "3");
443 section.set("normal_consensus_increase_percent", "0");
444 return cfg;
445 });
446
447 cfg->FEES.reference_fee = 10;
448 Env env(*this, std::move(cfg));
449
450 Json::Value jv;
451 jv[jss::ledger_index] = "current";
452 jv[jss::queue] = true;
453 jv[jss::expand] = true;
454
455 Account const alice{"alice"};
456 Account const bob{"bob"};
457 Account const charlie{"charlie"};
458 Account const daria{"daria"};
459 env.fund(XRP(10000), alice);
460 env.fund(XRP(10000), bob);
461 env.close();
462 env.fund(XRP(10000), charlie);
463 env.fund(XRP(10000), daria);
464 env.close();
465
466 auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
467 BEAST_EXPECT(!jrr.isMember(jss::queue_data));
468
469 // Fill the open ledger
470 for (;;)
471 {
472 auto metrics = env.app().getTxQ().getMetrics(*env.current());
473 if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
474 break;
475 env(noop(alice));
476 }
477
478 BEAST_EXPECT(env.current()->info().seq == 5);
479 // Put some txs in the queue
480 // Alice
481 auto aliceSeq = env.seq(alice);
482 env(pay(alice, "george", XRP(1000)),
484 ter(terQUEUED));
485 env(offer(alice, XRP(50000), alice["USD"](5000)),
486 seq(aliceSeq + 1),
487 ter(terQUEUED));
488 env(noop(alice), seq(aliceSeq + 2), ter(terQUEUED));
489 // Bob
490 auto batch = [&env](Account a) {
491 auto aSeq = env.seq(a);
492 // Enough fee to get in front of alice in the queue
493 for (int i = 0; i < 10; ++i)
494 {
495 env(noop(a), fee(1000 + i), seq(aSeq + i), ter(terQUEUED));
496 }
497 };
498 batch(bob);
499 // Charlie
500 batch(charlie);
501 // Daria
502 batch(daria);
503
504 jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
505 BEAST_EXPECT(jrr[jss::queue_data].size() == 33);
506
507 // Close enough ledgers so that alice's first tx expires.
508 env.close();
509 env.close();
510 env.close();
511 BEAST_EXPECT(env.current()->info().seq == 8);
512
513 jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
514 BEAST_EXPECT(jrr[jss::queue_data].size() == 11);
515
516 env.close();
517
518 jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
519 std::string const txid0 = [&]() {
520 auto const& parentHash = env.current()->info().parentHash;
521 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
522 {
523 std::string const txid1 = [&]() {
524 auto const& txj = jrr[jss::queue_data][1u];
525 BEAST_EXPECT(txj[jss::account] == alice.human());
526 BEAST_EXPECT(txj[jss::fee_level] == "256");
527 BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
528 BEAST_EXPECT(txj["retries_remaining"] == 10);
529 BEAST_EXPECT(txj.isMember(jss::tx));
530 auto const& tx = txj[jss::tx];
531 BEAST_EXPECT(tx[jss::Account] == alice.human());
532 BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
533 return tx[jss::hash].asString();
534 }();
535
536 auto const& txj = jrr[jss::queue_data][0u];
537 BEAST_EXPECT(txj[jss::account] == alice.human());
538 BEAST_EXPECT(txj[jss::fee_level] == "256");
539 BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
540 BEAST_EXPECT(txj["retries_remaining"] == 10);
541 BEAST_EXPECT(txj.isMember(jss::tx));
542 auto const& tx = txj[jss::tx];
543 BEAST_EXPECT(tx[jss::Account] == alice.human());
544 BEAST_EXPECT(tx[jss::TransactionType] == jss::OfferCreate);
545 auto const txid0 = tx[jss::hash].asString();
546 uint256 tx0, tx1;
547 BEAST_EXPECT(tx0.parseHex(txid0));
548 BEAST_EXPECT(tx1.parseHex(txid1));
549 BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
550 return txid0;
551 }
552 return std::string{};
553 }();
554
555 env.close();
556
557 jv[jss::expand] = false;
558
559 jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
560 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
561 {
562 auto const& parentHash = env.current()->info().parentHash;
563 auto const txid1 = [&]() {
564 auto const& txj = jrr[jss::queue_data][1u];
565 BEAST_EXPECT(txj[jss::account] == alice.human());
566 BEAST_EXPECT(txj[jss::fee_level] == "256");
567 BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
568 BEAST_EXPECT(txj.isMember(jss::tx));
569 return txj[jss::tx].asString();
570 }();
571 auto const& txj = jrr[jss::queue_data][0u];
572 BEAST_EXPECT(txj[jss::account] == alice.human());
573 BEAST_EXPECT(txj[jss::fee_level] == "256");
574 BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
575 BEAST_EXPECT(txj["retries_remaining"] == 9);
576 BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
577 BEAST_EXPECT(txj.isMember(jss::tx));
578 BEAST_EXPECT(txj[jss::tx] == txid0);
579 uint256 tx0, tx1;
580 BEAST_EXPECT(tx0.parseHex(txid0));
581 BEAST_EXPECT(tx1.parseHex(txid1));
582 BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
583 }
584
585 env.close();
586
587 jv[jss::expand] = true;
588 jv[jss::binary] = true;
589
590 jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
591 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
592 {
593 auto const& txj = jrr[jss::queue_data][1u];
594 BEAST_EXPECT(txj[jss::account] == alice.human());
595 BEAST_EXPECT(txj[jss::fee_level] == "256");
596 BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
597 BEAST_EXPECT(txj["retries_remaining"] == 8);
598 BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
599 BEAST_EXPECT(txj.isMember(jss::tx));
600 BEAST_EXPECT(txj[jss::tx].isMember(jss::tx_blob));
601
602 auto const& txj2 = jrr[jss::queue_data][0u];
603 BEAST_EXPECT(txj2[jss::account] == alice.human());
604 BEAST_EXPECT(txj2[jss::fee_level] == "256");
605 BEAST_EXPECT(txj2["preflight_result"] == "tesSUCCESS");
606 BEAST_EXPECT(txj2["retries_remaining"] == 10);
607 BEAST_EXPECT(!txj2.isMember("last_result"));
608 BEAST_EXPECT(txj2.isMember(jss::tx));
609 BEAST_EXPECT(txj2[jss::tx].isMember(jss::tx_blob));
610 }
611
612 for (int i = 0; i != 9; ++i)
613 {
614 env.close();
615 }
616
617 jv[jss::expand] = false;
618 jv[jss::binary] = false;
619
620 jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
621 std::string const txid2 = [&]() {
622 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
623 {
624 auto const& txj = jrr[jss::queue_data][0u];
625 BEAST_EXPECT(txj[jss::account] == alice.human());
626 BEAST_EXPECT(txj[jss::fee_level] == "256");
627 BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
628 BEAST_EXPECT(txj["retries_remaining"] == 1);
629 BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
630 BEAST_EXPECT(txj.isMember(jss::tx));
631 BEAST_EXPECT(txj[jss::tx] != txid0);
632 return txj[jss::tx].asString();
633 }
634 return std::string{};
635 }();
636
637 jv[jss::full] = true;
638
639 jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
640 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
641 {
642 auto const& txj = jrr[jss::queue_data][0u];
643 BEAST_EXPECT(txj[jss::account] == alice.human());
644 BEAST_EXPECT(txj[jss::fee_level] == "256");
645 BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
646 BEAST_EXPECT(txj["retries_remaining"] == 1);
647 BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
648 BEAST_EXPECT(txj.isMember(jss::tx));
649 auto const& tx = txj[jss::tx];
650 BEAST_EXPECT(tx[jss::Account] == alice.human());
651 BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
652 BEAST_EXPECT(tx[jss::hash] == txid2);
653 }
654 }
655
656 void
658 {
659 testcase("Ledger Request, Accounts Hashes");
660 using namespace test::jtx;
661
662 Env env{*this};
663
664 env.close();
665
666 std::string index;
667 int hashesLedgerEntryIndex = -1;
668 {
669 Json::Value jvParams;
670 jvParams[jss::ledger_index] = 3u;
671 jvParams[jss::accounts] = true;
672 jvParams[jss::expand] = true;
673 jvParams[jss::type] = "hashes";
674 auto const jrr =
675 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
676 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
677 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
678
679 for (auto i = 0; i < jrr[jss::ledger][jss::accountState].size();
680 i++)
681 if (jrr[jss::ledger][jss::accountState][i]["LedgerEntryType"] ==
682 jss::LedgerHashes)
683 {
684 index = jrr[jss::ledger][jss::accountState][i]["index"]
685 .asString();
686 hashesLedgerEntryIndex = i;
687 }
688
689 for (auto const& object : jrr[jss::ledger][jss::accountState])
690 if (object["LedgerEntryType"] == jss::LedgerHashes)
691 index = object["index"].asString();
692
693 // jss::type is a deprecated field
694 BEAST_EXPECT(
695 jrr.isMember(jss::warnings) && jrr[jss::warnings].isArray() &&
696 jrr[jss::warnings].size() == 1 &&
697 jrr[jss::warnings][0u][jss::id].asInt() ==
699 }
700 {
701 Json::Value jvParams;
702 jvParams[jss::ledger_index] = 3u;
703 jvParams[jss::accounts] = true;
704 jvParams[jss::expand] = false;
705 jvParams[jss::type] = "hashes";
706 auto const jrr =
707 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
708 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
709 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
710 BEAST_EXPECT(
711 hashesLedgerEntryIndex > 0 &&
712 jrr[jss::ledger][jss::accountState][hashesLedgerEntryIndex] ==
713 index);
714
715 // jss::type is a deprecated field
716 BEAST_EXPECT(
717 jrr.isMember(jss::warnings) && jrr[jss::warnings].isArray() &&
718 jrr[jss::warnings].size() == 1 &&
719 jrr[jss::warnings][0u][jss::id].asInt() ==
721 }
722 }
723
724public:
725 void
739};
740
741BEAST_DEFINE_TESTSUITE(LedgerRPC, rpc, ripple);
742
743} // namespace test
744} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
bool isMember(char const *key) const
Return true if the object has a member named key.
A testsuite class.
Definition suite.h:55
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:155
virtual TxQ & getTxQ()=0
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
Definition TxQ.cpp:1776
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:503
void checkErrorValue(Json::Value const &jv, std::string const &err, std::string const &msg)
void run() override
Runs the suite.
void testLookupLedger()
ledger RPC requests as a way to drive input options to lookupLedger.
std::string makeBadAddress(std::string good)
Immutable cryptographic account descriptor.
Definition Account.h:39
A transaction testing environment.
Definition Env.h:121
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition Env.cpp:269
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition Env.h:331
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:122
Application & app()
Definition Env.h:261
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition Env.h:791
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:290
Set the fee on a JTx.
Definition fee.h:37
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition rpc.h:35
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition ter.h:35
T empty(T... args)
@ nullValue
'null' value
Definition json_value.h:38
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
std::unique_ptr< Config > no_admin(std::unique_ptr< Config >)
adjust config so no admin ports are enabled
Definition envconfig.cpp:76
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition pay.cpp:30
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:54
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
Definition offer.cpp:29
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:111
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
@ warnRPC_FIELDS_DEPRECATED
Definition ErrorCodes.h:177
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:630
@ terQUEUED
Definition TER.h:225
T replace(T... args)
Set the sequence number on a JTx.
Definition seq.h:34
T to_string(T... args)