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