21#include <test/jtx/Env.h>
22#include <test/jtx/envconfig.h>
24#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
25#include <xrpld/rpc/CTID.h>
27#include <xrpl/protocol/ErrorCodes.h>
28#include <xrpl/protocol/STBase.h>
29#include <xrpl/protocol/jss.h>
30#include <xrpl/protocol/serialize.h>
43 using namespace test::jtx;
45 cfg->NETWORK_ID = networkID;
55 using namespace test::jtx;
58 const char* COMMAND = jss::tx.c_str();
59 const char* BINARY = jss::binary.c_str();
62 const char* EXCESSIVE =
65 Env env{*
this, features};
66 auto const alice = Account(
"alice");
67 env.fund(XRP(1000), alice);
72 auto const startLegSeq = env.current()->info().seq;
73 for (
int i = 0; i < 750; ++i)
79 env.closed()->txRead(env.tx()->getTransactionID()).second);
81 auto const endLegSeq = env.closed()->info().seq;
84 for (
size_t i = 0; i < txns.
size(); ++i)
86 auto const& tx = txns[i];
87 auto const& meta = metas[i];
88 auto const result = env.rpc(
95 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
97 result[jss::result][jss::tx] ==
98 strHex(tx->getSerializer().getData()));
100 result[jss::result][jss::meta] ==
101 strHex(meta->getSerializer().getData()));
104 auto const tx = env.jt(noop(alice), seq(env.seq(alice))).stx;
105 for (
int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
107 auto const result = env.rpc(
115 result[jss::result][jss::status] == jss::error &&
116 result[jss::result][jss::error] == NOT_FOUND);
119 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
121 BEAST_EXPECT(result[jss::result][jss::searched_all].asBool());
125 for (
auto&& tx : txns)
127 auto const result = env.rpc(
134 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
135 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
138 const auto deletedLedger = (startLegSeq + endLegSeq) / 2;
142 ->deleteTransactionByLedgerSeq(deletedLedger);
145 for (
int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
147 auto const result = env.rpc(
155 result[jss::result][jss::status] == jss::error &&
156 result[jss::result][jss::error] == NOT_FOUND);
157 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
163 auto const result = env.rpc(
170 result[jss::result][jss::status] == jss::error &&
171 result[jss::result][jss::error] == NOT_FOUND);
173 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
179 auto const result = env.rpc(
186 result[jss::result][jss::status] == jss::error &&
187 result[jss::result][jss::error] == NOT_FOUND);
189 BEAST_EXPECT(result[jss::result][jss::searched_all].asBool());
195 auto const result = env.rpc(
201 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
202 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
207 auto const result = env.rpc(
215 result[jss::result][jss::status] == jss::error &&
216 result[jss::result][jss::error] ==
INVALID);
218 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
223 auto const result = env.rpc(
231 result[jss::result][jss::status] == jss::error &&
232 result[jss::result][jss::error] ==
INVALID);
234 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
239 auto const result = env.rpc(
247 result[jss::result][jss::status] == jss::error &&
248 result[jss::result][jss::error] ==
INVALID);
250 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
255 auto const result = env.rpc(
262 result[jss::result][jss::status] == jss::error &&
263 result[jss::result][jss::error] ==
INVALID);
265 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
270 auto const result = env.rpc(
278 BEAST_EXPECT(result[jss::result][jss::status] == jss::error);
280 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
285 auto const result = env.rpc(
293 result[jss::result][jss::status] == jss::error &&
294 result[jss::result][jss::error] == EXCESSIVE);
296 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
305 using namespace test::jtx;
308 const char* COMMAND = jss::tx.c_str();
309 const char* BINARY = jss::binary.c_str();
312 const char* EXCESSIVE =
316 uint32_t netID = env.app().config().NETWORK_ID;
318 auto const alice = Account(
"alice");
319 env.fund(XRP(1000), alice);
324 auto const startLegSeq = env.current()->info().seq;
325 for (
int i = 0; i < 750; ++i)
331 env.closed()->txRead(env.tx()->getTransactionID()).second);
333 auto const endLegSeq = env.closed()->info().seq;
336 for (
size_t i = 0; i < txns.
size(); ++i)
338 auto const& tx = txns[i];
339 auto const& meta = metas[i];
340 uint32_t txnIdx = meta->getFieldU32(sfTransactionIndex);
341 auto const result = env.rpc(
348 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
350 result[jss::result][jss::tx] ==
351 strHex(tx->getSerializer().getData()));
353 result[jss::result][jss::meta] ==
354 strHex(meta->getSerializer().getData()));
357 auto const tx = env.jt(noop(alice), seq(env.seq(alice))).stx;
360 for (
int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
362 auto const result = env.rpc(
370 result[jss::result][jss::status] == jss::error &&
371 result[jss::result][jss::error] == NOT_FOUND);
374 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
376 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
380 for (
size_t i = 0; i < txns.
size(); ++i)
383 auto const& meta = metas[i];
384 uint32_t txnIdx = meta->getFieldU32(sfTransactionIndex);
385 auto const result = env.rpc(
392 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
393 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
396 const auto deletedLedger = (startLegSeq + endLegSeq) / 2;
400 ->deleteTransactionByLedgerSeq(deletedLedger);
403 for (
int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
405 auto const result = env.rpc(
413 result[jss::result][jss::status] == jss::error &&
414 result[jss::result][jss::error] == NOT_FOUND);
415 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
421 auto const result = env.rpc(
425 result[jss::result][jss::status] == jss::error &&
426 result[jss::result][jss::error] == NOT_FOUND);
428 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
434 auto const result = env.rpc(
441 result[jss::result][jss::status] == jss::error &&
442 result[jss::result][jss::error] == NOT_FOUND);
444 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
450 auto const& meta = metas[0];
451 uint32_t txnIdx = meta->getFieldU32(sfTransactionIndex);
452 auto const result = env.rpc(
458 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
459 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
464 auto const result = env.rpc(
472 result[jss::result][jss::status] == jss::error &&
473 result[jss::result][jss::error] ==
INVALID);
475 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
480 auto const result = env.rpc(
488 result[jss::result][jss::status] == jss::error &&
489 result[jss::result][jss::error] ==
INVALID);
491 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
500 result[jss::result][jss::status] == jss::error &&
501 result[jss::result][jss::error] ==
INVALID);
503 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
508 auto const result = env.rpc(COMMAND, ctid, BINARY,
to_string(20));
511 result[jss::result][jss::status] == jss::error &&
512 result[jss::result][jss::error] ==
INVALID);
514 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
519 auto const result = env.rpc(COMMAND, ctid,
to_string(20));
526 BEAST_EXPECT(result[jss::result][jss::status] == jss::error);
528 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
533 auto const result = env.rpc(
541 result[jss::result][jss::status] == jss::error &&
542 result[jss::result][jss::error] == EXCESSIVE);
544 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
553 using namespace test::jtx;
567 BEAST_EXPECT(
RPC::encodeCTID(13249191UL, 12911U, 65535U) == expected14);
589 auto const expected51 =
593 auto const expected52 =
597 auto const expected53 =
652 using namespace test::jtx;
657 uint32_t netID = env.app().config().NETWORK_ID;
659 auto const alice = Account(
"alice");
660 auto const bob = Account(
"bob");
662 auto const startLegSeq = env.current()->info().seq;
663 env.fund(XRP(10000), alice, bob);
664 env(pay(alice, bob, XRP(10)));
669 jsonTx[jss::binary] =
false;
670 jsonTx[jss::ctid] = ctid;
672 auto jrr = env.rpc(
"json",
"tx",
to_string(jsonTx))[jss::result];
673 BEAST_EXPECT(jrr[jss::ctid] == ctid);
674 BEAST_EXPECT(jrr[jss::hash]);
682 Account
const alice = Account(
"alice");
683 Account
const bob = Account(
"bob");
686 env.fund(XRP(10000), alice, bob);
687 env(pay(alice, bob, XRP(10)));
691 auto isUpper = [](
char c) {
return std::isupper(c) != 0; };
702 mixedCase.
begin(), mixedCase.
end(), isUpper);
703 *iter = std::tolower(*iter);
705 BEAST_EXPECT(ctid != mixedCase);
708 jsonTx[jss::binary] =
false;
709 jsonTx[jss::ctid] = mixedCase;
712 env.rpc(
"json",
"tx",
to_string(jsonTx))[jss::result];
713 BEAST_EXPECT(jrr[jss::ctid] == ctid);
714 BEAST_EXPECT(jrr[jss::hash]);
721 uint32_t netID = env.app().config().NETWORK_ID;
723 auto const alice = Account(
"alice");
724 auto const bob = Account(
"bob");
726 auto const startLegSeq = env.current()->info().seq;
727 env.fund(XRP(10000), alice, bob);
728 env(pay(alice, bob, XRP(10)));
733 jsonTx[jss::binary] =
false;
734 jsonTx[jss::ctid] = ctid;
736 auto jrr = env.rpc(
"json",
"tx",
to_string(jsonTx))[jss::result];
737 BEAST_EXPECT(!jrr[jss::ctid]);
738 BEAST_EXPECT(jrr[jss::hash]);
747 using namespace test::jtx;
751 cfg->FEES.reference_fee = 10;
754 Account
const alice{
"alice"};
755 Account
const alie{
"alie"};
756 Account
const gw{
"gw"};
757 auto const USD{gw[
"USD"]};
759 env.fund(XRP(1000000), alice, gw);
766 env(pay(alice, gw, XRP(100)));
771 env.closed()->txRead(env.tx()->getTransactionID()).second;
774 expected[jss::DeliverMax] = expected[jss::Amount];
781 Json::Value const result = {[&env, txn, apiVersion]() {
783 params[jss::transaction] =
to_string(txn->getTransactionID());
784 params[jss::binary] =
false;
785 params[jss::api_version] = apiVersion;
786 return env.client().invoke(
"tx", params);
789 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
793 result[jss::result][jss::close_time_iso] ==
794 "2000-01-01T00:00:20Z");
796 result[jss::result][jss::hash] ==
798 BEAST_EXPECT(result[jss::result][jss::validated] ==
true);
799 BEAST_EXPECT(result[jss::result][jss::ledger_index] == 4);
801 result[jss::result][jss::ledger_hash] ==
802 "B41882E20F0EC6228417D28B9AE0F33833645D35F6799DFB782AC97FC4BB51"
806 for (
auto memberIt = expected.
begin(); memberIt != expected.
end();
810 auto const& result_transaction =
811 (apiVersion > 1 ? result[jss::result][jss::tx_json]
812 : result[jss::result]);
813 if (BEAST_EXPECT(result_transaction.isMember(name)))
815 auto const received = result_transaction[name];
817 received == *memberIt,
818 "Transaction contains \n\"" + name +
"\": "
832 using namespace test::jtx;
836 cfg->FEES.reference_fee = 10;
839 Account
const alice{
"alice"};
840 Account
const gw{
"gw"};
841 auto const USD{gw[
"USD"]};
843 env.fund(XRP(1000000), alice, gw);
847 "3F8BDE5A5F82C4F4708E5E9255B713E303E6E1A371FD5C7A704AFD1387C23981");
850 env.closed()->txRead(txn->getTransactionID()).second;
855 Json::Value const result = [&env, txn, apiVersion]() {
857 params[jss::transaction] =
to_string(txn->getTransactionID());
858 params[jss::binary] =
true;
859 params[jss::api_version] = apiVersion;
860 return env.client().invoke(
"tx", params);
863 if (BEAST_EXPECT(result[jss::status] ==
"success"))
865 BEAST_EXPECT(result[jss::result][jss::status] ==
"success");
866 BEAST_EXPECT(result[jss::result][jss::validated] ==
true);
868 result[jss::result][jss::hash] ==
870 BEAST_EXPECT(result[jss::result][jss::ledger_index] == 3);
871 BEAST_EXPECT(result[jss::result][jss::ctid] ==
"C000000300030000");
876 result[jss::result][jss::tx_blob] == expected_tx_blob);
878 result[jss::result][jss::meta_blob] == expected_meta_blob);
880 result[jss::result][jss::ledger_hash] ==
881 "2D5150E5A5AA436736A732291E437ABF01BC9E206C2DF3C77C4F856915"
884 result[jss::result][jss::close_time_iso] ==
885 "2000-01-01T00:00:10Z");
889 BEAST_EXPECT(result[jss::result][jss::tx] == expected_tx_blob);
891 result[jss::result][jss::meta] == expected_meta_blob);
892 BEAST_EXPECT(result[jss::result][jss::date] == 10);
901 using namespace test::jtx;
const_iterator begin() const
const_iterator end() const
Value removeMember(const char *key)
Remove and return the named member.
testcase_t testcase
Memberspace for declaring test cases.
void testCTIDValidation(FeatureBitset features)
void run() override
Runs the suite.
void testRangeRequest(FeatureBitset features)
std::unique_ptr< Config > makeNetworkConfig(uint32_t networkID)
void testRequest(FeatureBitset features, unsigned apiVersion)
void testBinaryRequest(unsigned apiVersion)
void testCTIDRPC(FeatureBitset features)
void testRangeCTIDRequest(FeatureBitset features)
void testWithFeats(FeatureBitset features)
T emplace_back(T... args)
@ objectValue
object value (collection of name/value pairs).
std::optional< std::tuple< uint32_t, uint16_t, uint16_t > > decodeCTID(const T ctid) noexcept
ErrorInfo const & get_error_info(error_code_i code)
Returns an ErrorInfo that reflects the error code.
std::optional< std::string > encodeCTID(uint32_t ledger_seq, uint16_t txn_index, uint16_t network_id) noexcept
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::string serializeHex(STObject const &o)
Serialize an object to a hex string.
std::string strHex(FwdIt begin, FwdIt end)
void forAllApiVersions(Fn const &fn, Args &&... args)
std::string to_string(base_uint< Bits, Tag > const &a)