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 char const* COMMAND = jss::tx.c_str();
59 char const* BINARY = jss::binary.c_str();
62 char const* 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 auto const 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 char const* COMMAND = jss::tx.c_str();
309 char const* BINARY = jss::binary.c_str();
312 char const* 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;
358 auto const ctid = *
RPC::encodeCTID(endLegSeq, tx->getSeqValue(), netID);
359 for (
int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
361 auto const result = env.rpc(
369 result[jss::result][jss::status] == jss::error &&
370 result[jss::result][jss::error] == NOT_FOUND);
373 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
375 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
379 for (
size_t i = 0; i < txns.
size(); ++i)
382 auto const& meta = metas[i];
383 uint32_t txnIdx = meta->getFieldU32(sfTransactionIndex);
384 auto const result = env.rpc(
391 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
392 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
395 auto const deletedLedger = (startLegSeq + endLegSeq) / 2;
399 ->deleteTransactionByLedgerSeq(deletedLedger);
402 for (
int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
404 auto const result = env.rpc(
412 result[jss::result][jss::status] == jss::error &&
413 result[jss::result][jss::error] == NOT_FOUND);
414 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
420 auto const result = env.rpc(
424 result[jss::result][jss::status] == jss::error &&
425 result[jss::result][jss::error] == NOT_FOUND);
427 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
433 auto const result = env.rpc(
440 result[jss::result][jss::status] == jss::error &&
441 result[jss::result][jss::error] == NOT_FOUND);
443 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
449 auto const& meta = metas[0];
450 uint32_t txnIdx = meta->getFieldU32(sfTransactionIndex);
451 auto const result = env.rpc(
457 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
458 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
463 auto const result = env.rpc(
471 result[jss::result][jss::status] == jss::error &&
472 result[jss::result][jss::error] ==
INVALID);
474 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
479 auto const result = env.rpc(
487 result[jss::result][jss::status] == jss::error &&
488 result[jss::result][jss::error] ==
INVALID);
490 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
499 result[jss::result][jss::status] == jss::error &&
500 result[jss::result][jss::error] ==
INVALID);
502 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
507 auto const result = env.rpc(COMMAND, ctid, BINARY,
to_string(20));
510 result[jss::result][jss::status] == jss::error &&
511 result[jss::result][jss::error] ==
INVALID);
513 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
518 auto const result = env.rpc(COMMAND, ctid,
to_string(20));
525 BEAST_EXPECT(result[jss::result][jss::status] == jss::error);
527 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
532 auto const result = env.rpc(
540 result[jss::result][jss::status] == jss::error &&
541 result[jss::result][jss::error] == EXCESSIVE);
543 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
552 using namespace test::jtx;
566 BEAST_EXPECT(
RPC::encodeCTID(13249191UL, 12911U, 65535U) == expected14);
578 auto const expected51 =
582 auto const expected52 =
586 auto const expected53 =
641 using namespace test::jtx;
644 for (uint32_t netID : {11111, 65535, 65536})
647 BEAST_EXPECT(netID == env.app().config().NETWORK_ID);
649 auto const alice = Account(
"alice");
650 auto const bob = Account(
"bob");
652 auto const startLegSeq = env.current()->info().seq;
653 env.fund(XRP(10000), alice, bob);
654 env(pay(alice, bob, XRP(10)));
661 BEAST_EXPECT(ctid == std::nullopt);
666 jsonTx[jss::binary] =
false;
667 jsonTx[jss::ctid] = *ctid;
670 env.rpc(
"json",
"tx",
to_string(jsonTx))[jss::result];
671 BEAST_EXPECT(jrr[jss::ctid] == ctid);
672 BEAST_EXPECT(jrr.isMember(jss::hash));
680 Account
const alice = Account(
"alice");
681 Account
const bob = Account(
"bob");
684 env.fund(XRP(10000), alice, bob);
685 env(pay(alice, bob, XRP(10)));
689 auto isUpper = [](
char c) {
return std::isupper(c) != 0; };
700 mixedCase.
begin(), mixedCase.
end(), isUpper);
701 *iter = std::tolower(*iter);
703 BEAST_EXPECT(ctid != mixedCase);
706 jsonTx[jss::binary] =
false;
707 jsonTx[jss::ctid] = mixedCase;
710 env.rpc(
"json",
"tx",
to_string(jsonTx))[jss::result];
711 BEAST_EXPECT(jrr[jss::ctid] == ctid);
712 BEAST_EXPECT(jrr[jss::hash]);
719 for (uint32_t netID : {2, 1024, 65535, 65536})
722 BEAST_EXPECT(netID == env.app().config().NETWORK_ID);
724 auto const alice = Account(
"alice");
725 auto const bob = Account(
"bob");
727 env.fund(XRP(10000), alice, bob);
728 env(pay(alice, bob, XRP(10)));
731 auto const ledgerSeq = env.current()->info().seq;
739 params[jss::transaction] = hash;
741 env.rpc(
"json",
"tx",
to_string(params))[jss::result];
742 BEAST_EXPECT(jrr[jss::hash] == hash);
744 BEAST_EXPECT(jrr.isMember(jss::ctid) == (netID <= 0xFFFF));
745 if (jrr.isMember(jss::ctid))
748 BEAST_EXPECT(jrr[jss::ctid] == *ctid);
755 uint32_t netID = env.app().config().NETWORK_ID;
757 auto const alice = Account(
"alice");
758 auto const bob = Account(
"bob");
760 auto const startLegSeq = env.current()->info().seq;
761 env.fund(XRP(10000), alice, bob);
762 env(pay(alice, bob, XRP(10)));
767 jsonTx[jss::binary] =
false;
768 jsonTx[jss::ctid] = ctid;
771 env.rpc(
"json",
"tx",
to_string(jsonTx))[jss::result];
772 BEAST_EXPECT(jrr[jss::error] ==
"wrongNetwork");
775 jrr[jss::error_message] ==
776 "Wrong network. You should submit this request to a node "
777 "running on NetworkID: 21338");
786 using namespace test::jtx;
790 cfg->FEES.reference_fee = 10;
793 Account
const alice{
"alice"};
794 Account
const alie{
"alie"};
795 Account
const gw{
"gw"};
796 auto const USD{gw[
"USD"]};
798 env.fund(XRP(1000000), alice, gw);
805 env(pay(alice, gw, XRP(100)));
810 env.closed()->txRead(env.tx()->getTransactionID()).second;
813 expected[jss::DeliverMax] = expected[jss::Amount];
820 Json::Value const result = {[&env, txn, apiVersion]() {
822 params[jss::transaction] =
to_string(txn->getTransactionID());
823 params[jss::binary] =
false;
824 params[jss::api_version] = apiVersion;
825 return env.client().invoke(
"tx", params);
828 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
832 result[jss::result][jss::close_time_iso] ==
833 "2000-01-01T00:00:20Z");
835 result[jss::result][jss::hash] ==
837 BEAST_EXPECT(result[jss::result][jss::validated] ==
true);
838 BEAST_EXPECT(result[jss::result][jss::ledger_index] == 4);
840 result[jss::result][jss::ledger_hash] ==
841 "B41882E20F0EC6228417D28B9AE0F33833645D35F6799DFB782AC97FC4BB51"
845 for (
auto memberIt = expected.
begin(); memberIt != expected.
end();
849 auto const& result_transaction =
850 (apiVersion > 1 ? result[jss::result][jss::tx_json]
851 : result[jss::result]);
852 if (BEAST_EXPECT(result_transaction.isMember(name)))
854 auto const received = result_transaction[name];
856 received == *memberIt,
857 "Transaction contains \n\"" + name +
"\": "
871 using namespace test::jtx;
875 cfg->FEES.reference_fee = 10;
878 Account
const alice{
"alice"};
879 Account
const gw{
"gw"};
880 auto const USD{gw[
"USD"]};
882 env.fund(XRP(1000000), alice, gw);
886 "3F8BDE5A5F82C4F4708E5E9255B713E303E6E1A371FD5C7A704AFD1387C23981");
889 env.closed()->txRead(txn->getTransactionID()).second;
894 Json::Value const result = [&env, txn, apiVersion]() {
896 params[jss::transaction] =
to_string(txn->getTransactionID());
897 params[jss::binary] =
true;
898 params[jss::api_version] = apiVersion;
899 return env.client().invoke(
"tx", params);
902 if (BEAST_EXPECT(result[jss::status] ==
"success"))
904 BEAST_EXPECT(result[jss::result][jss::status] ==
"success");
905 BEAST_EXPECT(result[jss::result][jss::validated] ==
true);
907 result[jss::result][jss::hash] ==
909 BEAST_EXPECT(result[jss::result][jss::ledger_index] == 3);
910 BEAST_EXPECT(result[jss::result][jss::ctid] ==
"C000000300030000");
915 result[jss::result][jss::tx_blob] == expected_tx_blob);
917 result[jss::result][jss::meta_blob] == expected_meta_blob);
919 result[jss::result][jss::ledger_hash] ==
920 "2D5150E5A5AA436736A732291E437ABF01BC9E206C2DF3C77C4F856915"
923 result[jss::result][jss::close_time_iso] ==
924 "2000-01-01T00:00:10Z");
928 BEAST_EXPECT(result[jss::result][jss::tx] == expected_tx_blob);
930 result[jss::result][jss::meta] == expected_meta_blob);
931 BEAST_EXPECT(result[jss::result][jss::date] == 10);
940 using namespace test::jtx;
const_iterator begin() const
const_iterator end() const
Value removeMember(char const *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::string > encodeCTID(uint32_t ledgerSeq, uint32_t txnIndex, uint32_t networkID) noexcept
ErrorInfo const & get_error_info(error_code_i code)
Returns an ErrorInfo that reflects the error code.
std::optional< std::tuple< uint32_t, uint16_t, uint16_t > > decodeCTID(T const ctid) 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)