20 #include <ripple/app/rdb/backend/SQLiteDatabase.h>
21 #include <ripple/protocol/ErrorCodes.h>
22 #include <ripple/protocol/jss.h>
23 #include <ripple/rpc/CTID.h>
26 #include <test/jtx/Env.h>
27 #include <test/jtx/envconfig.h>
37 using namespace test::jtx;
39 cfg->NETWORK_ID = networkID;
47 testcase(
"Test Range Request");
49 using namespace test::jtx;
52 const char* COMMAND = jss::tx.c_str();
53 const char* BINARY = jss::binary.c_str();
56 const char* EXCESSIVE =
59 Env env{*
this, features};
60 auto const alice = Account(
"alice");
61 env.fund(XRP(1000), alice);
66 auto const startLegSeq = env.current()->info().seq;
67 for (
int i = 0; i < 750; ++i)
73 env.closed()->txRead(env.tx()->getTransactionID()).second);
75 auto const endLegSeq = env.closed()->info().seq;
78 for (
size_t i = 0; i < txns.
size(); ++i)
80 auto const& tx = txns[i];
81 auto const& meta = metas[i];
82 auto const result = env.rpc(
89 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
91 result[jss::result][jss::tx] ==
92 strHex(tx->getSerializer().getData()));
94 result[jss::result][jss::meta] ==
95 strHex(meta->getSerializer().getData()));
98 auto const tx = env.jt(noop(alice), seq(env.seq(alice))).stx;
99 for (
int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
101 auto const result = env.rpc(
109 result[jss::result][jss::status] == jss::error &&
110 result[jss::result][jss::error] == NOT_FOUND);
113 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
115 BEAST_EXPECT(result[jss::result][jss::searched_all].asBool());
119 for (
auto&& tx : txns)
121 auto const result = env.rpc(
128 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
129 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
132 const auto deletedLedger = (startLegSeq + endLegSeq) / 2;
136 ->deleteTransactionByLedgerSeq(deletedLedger);
139 for (
int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
141 auto const result = env.rpc(
149 result[jss::result][jss::status] == jss::error &&
150 result[jss::result][jss::error] == NOT_FOUND);
151 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
157 auto const result = env.rpc(
164 result[jss::result][jss::status] == jss::error &&
165 result[jss::result][jss::error] == NOT_FOUND);
167 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
173 auto const result = env.rpc(
180 result[jss::result][jss::status] == jss::error &&
181 result[jss::result][jss::error] == NOT_FOUND);
183 BEAST_EXPECT(result[jss::result][jss::searched_all].asBool());
189 auto const result = env.rpc(
195 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
196 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
201 auto const result = env.rpc(
209 result[jss::result][jss::status] == jss::error &&
210 result[jss::result][jss::error] ==
INVALID);
212 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
217 auto const result = env.rpc(
225 result[jss::result][jss::status] == jss::error &&
226 result[jss::result][jss::error] ==
INVALID);
228 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
233 auto const result = env.rpc(
241 result[jss::result][jss::status] == jss::error &&
242 result[jss::result][jss::error] ==
INVALID);
244 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
249 auto const result = env.rpc(
256 result[jss::result][jss::status] == jss::error &&
257 result[jss::result][jss::error] ==
INVALID);
259 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
264 auto const result = env.rpc(
272 BEAST_EXPECT(result[jss::result][jss::status] == jss::error);
274 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
279 auto const result = env.rpc(
287 result[jss::result][jss::status] == jss::error &&
288 result[jss::result][jss::error] == EXCESSIVE);
290 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
297 testcase(
"ctid_range");
299 using namespace test::jtx;
302 const char* COMMAND = jss::tx.c_str();
303 const char* BINARY = jss::binary.c_str();
306 const char* EXCESSIVE =
310 uint32_t netID = env.app().config().NETWORK_ID;
312 auto const alice = Account(
"alice");
313 env.fund(XRP(1000), alice);
318 auto const startLegSeq = env.current()->info().seq;
319 for (
int i = 0; i < 750; ++i)
325 env.closed()->txRead(env.tx()->getTransactionID()).second);
327 auto const endLegSeq = env.closed()->info().seq;
330 for (
size_t i = 0; i < txns.
size(); ++i)
332 auto const& tx = txns[i];
333 auto const& meta = metas[i];
335 auto const result = env.rpc(
342 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
344 result[jss::result][jss::tx] ==
345 strHex(tx->getSerializer().getData()));
347 result[jss::result][jss::meta] ==
348 strHex(meta->getSerializer().getData()));
351 auto const tx = env.jt(noop(alice), seq(env.seq(alice))).stx;
354 for (
int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
356 auto const result = env.rpc(
364 result[jss::result][jss::status] == jss::error &&
365 result[jss::result][jss::error] == NOT_FOUND);
368 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
370 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
374 for (
size_t i = 0; i < txns.
size(); ++i)
377 auto const& meta = metas[i];
379 auto const result = env.rpc(
386 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
387 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
390 const auto deletedLedger = (startLegSeq + endLegSeq) / 2;
394 ->deleteTransactionByLedgerSeq(deletedLedger);
397 for (
int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
399 auto const result = env.rpc(
407 result[jss::result][jss::status] == jss::error &&
408 result[jss::result][jss::error] == NOT_FOUND);
409 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
415 auto const result = env.rpc(
419 result[jss::result][jss::status] == jss::error &&
420 result[jss::result][jss::error] == NOT_FOUND);
422 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
428 auto const result = env.rpc(
435 result[jss::result][jss::status] == jss::error &&
436 result[jss::result][jss::error] == NOT_FOUND);
438 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
444 auto const& meta = metas[0];
446 auto const result = env.rpc(
452 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
453 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
458 auto const result = env.rpc(
466 result[jss::result][jss::status] == jss::error &&
467 result[jss::result][jss::error] ==
INVALID);
469 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
474 auto const result = env.rpc(
482 result[jss::result][jss::status] == jss::error &&
483 result[jss::result][jss::error] ==
INVALID);
485 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
494 result[jss::result][jss::status] == jss::error &&
495 result[jss::result][jss::error] ==
INVALID);
497 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
502 auto const result = env.rpc(COMMAND, ctid, BINARY,
to_string(20));
505 result[jss::result][jss::status] == jss::error &&
506 result[jss::result][jss::error] ==
INVALID);
508 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
513 auto const result = env.rpc(COMMAND, ctid,
to_string(20));
520 BEAST_EXPECT(result[jss::result][jss::status] == jss::error);
522 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
527 auto const result = env.rpc(
535 result[jss::result][jss::status] == jss::error &&
536 result[jss::result][jss::error] == EXCESSIVE);
538 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
545 testcase(
"ctid_validation");
547 using namespace test::jtx;
556 auto const expected12 = std::optional<std::string>("C000000000000000");
557 BEAST_EXPECT(RPC::encodeCTID(0, 0, 0) == expected12);
558 auto const expected13 = std::optional<std::string>("C000000100020003");
559 BEAST_EXPECT(RPC::encodeCTID(1U, 2U, 3U) == expected13);
560 auto const expected14 = std::optional<std::string>("C0CA2AA7326FFFFF");
561 BEAST_EXPECT(RPC::encodeCTID(13249191UL, 12911U, 65535U) == expected14);
563 // Test case 2: ledger_seq greater than 0xFFFFFFF
564 BEAST_EXPECT(!RPC::encodeCTID(0x1000'0000UL, 0xFFFFU, 0xFFFFU));
574 // Test case 4: network_id greater than 0xFFFF
575 // this test case is impossible in c++ due to the type, left in for
577 auto const expected4 = std::optional<std::string>("CFFFFFFFFFFF0000");
579 RPC::encodeCTID(0x0FFF'FFFFUL, 0xFFFFU, (uint16_t)0x1000
'0U) ==
582 // Test case 5: Valid input values
583 auto const expected51 =
584 std::optional<std::tuple<int32_t, uint16_t, uint16_t>>(
585 std::make_tuple(0, 0, 0));
586 BEAST_EXPECT(RPC::decodeCTID("C000000000000000") == expected51);
587 auto const expected52 =
588 std::optional<std::tuple<int32_t, uint16_t, uint16_t>>(
589 std::make_tuple(1U, 2U, 3U));
590 BEAST_EXPECT(RPC::decodeCTID("C000000100020003") == expected52);
591 auto const expected53 =
592 std::optional<std::tuple<int32_t, uint16_t, uint16_t>>(
593 std::make_tuple(13249191UL, 12911U, 49221U));
594 BEAST_EXPECT(RPC::decodeCTID("C0CA2AA7326FC045") == expected53);
596 // Test case 6: ctid not a string or big int
597 BEAST_EXPECT(!RPC::decodeCTID(0xCFF));
599 // Test case 7: ctid not a hexadecimal string
600 BEAST_EXPECT(!RPC::decodeCTID("C003FFFFFFFFFFFG"));
602 // Test case 8: ctid not exactly 16 nibbles
603 BEAST_EXPECT(!RPC::decodeCTID("C003FFFFFFFFFFF"));
605 // Test case 9: ctid too large to be a valid CTID value
606 BEAST_EXPECT(!RPC::decodeCTID("CFFFFFFFFFFFFFFFF"));
608 // Test case 10: ctid doesn't start with a C nibble
614 std::optional<std::tuple<int32_t, uint16_t, uint16_t>>(
615 std::make_tuple(0x0FFF'FFFFUL, 0xFFFFU, 0xFFFFU))));
618 std::optional<std::tuple<int32_t, uint16_t, uint16_t>>(
619 std::make_tuple(0, 0, 0))));
621 (RPC::decodeCTID(0xC000'0001
'0002'0003ULL) ==
626 std::optional<std::tuple<int32_t, uint16_t, uint16_t>>(
627 std::make_tuple(1324'9191UL, 12911U, 49221U))));
632 // Test case 13: ctid too large to be a valid CTID value
633 // this test case is not possible in c++ because it would overflow the
634 // type, left in for completeness
635 // BEAST_EXPECT(!RPC::decodeCTID(0xCFFFFFFFFFFFFFFFFULL));
637 // Test case 14: ctid doesn't start with a C nibble
642 testCTIDRPC(FeatureBitset features)
644 testcase("ctid_rpc");
646 using namespace test::jtx;
648 // test that the ctid AND the hash are in the response
650 Env env{*this, makeNetworkConfig(11111)};
651 uint32_t netID = env.app().config().NETWORK_ID;
653 auto const alice = Account("alice");
654 auto const bob = Account("bob");
656 auto const startLegSeq = env.current()->info().seq;
657 env.fund(XRP(10000), alice, bob);
658 env(pay(alice, bob, XRP(10)));
661 auto const ctid = *RPC::encodeCTID(startLegSeq, 0, netID);
663 jsonTx[jss::binary] = false;
664 jsonTx[jss::ctid] = ctid;
666 auto jrr = env.rpc("json", "tx", to_string(jsonTx))[jss::result];
667 BEAST_EXPECT(jrr[jss::ctid] == ctid);
668 BEAST_EXPECT(jrr[jss::hash]);
671 // test that if the network is 65535 the ctid is not in the response
673 Env env{*this, makeNetworkConfig(65535)};
674 uint32_t netID = env.app().config().NETWORK_ID;
676 auto const alice = Account("alice");
677 auto const bob = Account("bob");
679 auto const startLegSeq = env.current()->info().seq;
680 env.fund(XRP(10000), alice, bob);
681 env(pay(alice, bob, XRP(10)));
684 auto const ctid = *RPC::encodeCTID(startLegSeq, 0, netID);
686 jsonTx[jss::binary] = false;
687 jsonTx[jss::ctid] = ctid;
689 auto jrr = env.rpc("json", "tx", to_string(jsonTx))[jss::result];
690 BEAST_EXPECT(!jrr[jss::ctid]);
691 BEAST_EXPECT(jrr[jss::hash]);
699 using namespace test::jtx;
700 FeatureBitset const all{supported_amendments()};
705 testWithFeats(FeatureBitset features)
707 testRangeRequest(features);
708 testRangeCTIDRequest(features);
709 testCTIDValidation(features);
710 testCTIDRPC(features);
714 BEAST_DEFINE_TESTSUITE(Transaction, rpc, ripple);
716 } // namespace ripple