21#include <test/jtx/Env.h>
22#include <test/jtx/envconfig.h>
23#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
24#include <xrpld/rpc/CTID.h>
25#include <xrpl/protocol/ErrorCodes.h>
26#include <xrpl/protocol/STBase.h>
27#include <xrpl/protocol/jss.h>
28#include <xrpl/protocol/serialize.h>
41 using namespace test::jtx;
43 cfg->NETWORK_ID = networkID;
53 using namespace test::jtx;
56 const char* COMMAND = jss::tx.c_str();
57 const char* BINARY = jss::binary.c_str();
60 const char* EXCESSIVE =
63 Env env{*
this, features};
64 auto const alice = Account(
"alice");
65 env.fund(XRP(1000), alice);
70 auto const startLegSeq = env.current()->info().seq;
71 for (
int i = 0; i < 750; ++i)
77 env.closed()->txRead(env.tx()->getTransactionID()).second);
79 auto const endLegSeq = env.closed()->info().seq;
82 for (
size_t i = 0; i < txns.
size(); ++i)
84 auto const& tx = txns[i];
85 auto const& meta = metas[i];
86 auto const result = env.rpc(
93 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
95 result[jss::result][jss::tx] ==
96 strHex(tx->getSerializer().getData()));
98 result[jss::result][jss::meta] ==
99 strHex(meta->getSerializer().getData()));
102 auto const tx = env.jt(noop(alice), seq(env.seq(alice))).stx;
103 for (
int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
105 auto const result = env.rpc(
113 result[jss::result][jss::status] == jss::error &&
114 result[jss::result][jss::error] == NOT_FOUND);
117 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
119 BEAST_EXPECT(result[jss::result][jss::searched_all].asBool());
123 for (
auto&& tx : txns)
125 auto const result = env.rpc(
132 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
133 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
136 const auto deletedLedger = (startLegSeq + endLegSeq) / 2;
140 ->deleteTransactionByLedgerSeq(deletedLedger);
143 for (
int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
145 auto const result = env.rpc(
153 result[jss::result][jss::status] == jss::error &&
154 result[jss::result][jss::error] == NOT_FOUND);
155 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
161 auto const result = env.rpc(
168 result[jss::result][jss::status] == jss::error &&
169 result[jss::result][jss::error] == NOT_FOUND);
171 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
177 auto const result = env.rpc(
184 result[jss::result][jss::status] == jss::error &&
185 result[jss::result][jss::error] == NOT_FOUND);
187 BEAST_EXPECT(result[jss::result][jss::searched_all].asBool());
193 auto const result = env.rpc(
199 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
200 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
205 auto const result = env.rpc(
213 result[jss::result][jss::status] == jss::error &&
214 result[jss::result][jss::error] ==
INVALID);
216 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
221 auto const result = env.rpc(
229 result[jss::result][jss::status] == jss::error &&
230 result[jss::result][jss::error] ==
INVALID);
232 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
237 auto const result = env.rpc(
245 result[jss::result][jss::status] == jss::error &&
246 result[jss::result][jss::error] ==
INVALID);
248 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
253 auto const result = env.rpc(
260 result[jss::result][jss::status] == jss::error &&
261 result[jss::result][jss::error] ==
INVALID);
263 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
268 auto const result = env.rpc(
276 BEAST_EXPECT(result[jss::result][jss::status] == jss::error);
278 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
283 auto const result = env.rpc(
291 result[jss::result][jss::status] == jss::error &&
292 result[jss::result][jss::error] == EXCESSIVE);
294 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
303 using namespace test::jtx;
306 const char* COMMAND = jss::tx.c_str();
307 const char* BINARY = jss::binary.c_str();
310 const char* EXCESSIVE =
314 uint32_t netID = env.app().config().NETWORK_ID;
316 auto const alice = Account(
"alice");
317 env.fund(XRP(1000), alice);
322 auto const startLegSeq = env.current()->info().seq;
323 for (
int i = 0; i < 750; ++i)
329 env.closed()->txRead(env.tx()->getTransactionID()).second);
331 auto const endLegSeq = env.closed()->info().seq;
334 for (
size_t i = 0; i < txns.
size(); ++i)
336 auto const& tx = txns[i];
337 auto const& meta = metas[i];
338 uint32_t txnIdx = meta->getFieldU32(sfTransactionIndex);
339 auto const result = env.rpc(
346 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
348 result[jss::result][jss::tx] ==
349 strHex(tx->getSerializer().getData()));
351 result[jss::result][jss::meta] ==
352 strHex(meta->getSerializer().getData()));
355 auto const tx = env.jt(noop(alice), seq(env.seq(alice))).stx;
358 for (
int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
360 auto const result = env.rpc(
368 result[jss::result][jss::status] == jss::error &&
369 result[jss::result][jss::error] == NOT_FOUND);
372 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
374 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
378 for (
size_t i = 0; i < txns.
size(); ++i)
381 auto const& meta = metas[i];
382 uint32_t txnIdx = meta->getFieldU32(sfTransactionIndex);
383 auto const result = env.rpc(
390 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
391 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
394 const auto deletedLedger = (startLegSeq + endLegSeq) / 2;
398 ->deleteTransactionByLedgerSeq(deletedLedger);
401 for (
int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
403 auto const result = env.rpc(
411 result[jss::result][jss::status] == jss::error &&
412 result[jss::result][jss::error] == NOT_FOUND);
413 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
419 auto const result = env.rpc(
423 result[jss::result][jss::status] == jss::error &&
424 result[jss::result][jss::error] == NOT_FOUND);
426 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
432 auto const result = env.rpc(
439 result[jss::result][jss::status] == jss::error &&
440 result[jss::result][jss::error] == NOT_FOUND);
442 BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
448 auto const& meta = metas[0];
449 uint32_t txnIdx = meta->getFieldU32(sfTransactionIndex);
450 auto const result = env.rpc(
456 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
457 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
462 auto const result = env.rpc(
470 result[jss::result][jss::status] == jss::error &&
471 result[jss::result][jss::error] ==
INVALID);
473 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
478 auto const result = env.rpc(
486 result[jss::result][jss::status] == jss::error &&
487 result[jss::result][jss::error] ==
INVALID);
489 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
498 result[jss::result][jss::status] == jss::error &&
499 result[jss::result][jss::error] ==
INVALID);
501 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
506 auto const result = env.rpc(COMMAND, ctid, BINARY,
to_string(20));
509 result[jss::result][jss::status] == jss::error &&
510 result[jss::result][jss::error] ==
INVALID);
512 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
517 auto const result = env.rpc(COMMAND, ctid,
to_string(20));
524 BEAST_EXPECT(result[jss::result][jss::status] == jss::error);
526 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
531 auto const result = env.rpc(
539 result[jss::result][jss::status] == jss::error &&
540 result[jss::result][jss::error] == EXCESSIVE);
542 BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
551 using namespace test::jtx;
565 BEAST_EXPECT(
RPC::encodeCTID(13249191UL, 12911U, 65535U) == expected14);
587 auto const expected51 =
591 auto const expected52 =
595 auto const expected53 =
650 using namespace test::jtx;
655 uint32_t netID = env.app().config().NETWORK_ID;
657 auto const alice = Account(
"alice");
658 auto const bob = Account(
"bob");
660 auto const startLegSeq = env.current()->info().seq;
661 env.fund(XRP(10000), alice, bob);
662 env(pay(alice, bob, XRP(10)));
667 jsonTx[jss::binary] =
false;
668 jsonTx[jss::ctid] = ctid;
670 auto jrr = env.rpc(
"json",
"tx",
to_string(jsonTx))[jss::result];
671 BEAST_EXPECT(jrr[jss::ctid] == ctid);
672 BEAST_EXPECT(jrr[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 uint32_t netID = env.app().config().NETWORK_ID;
721 auto const alice = Account(
"alice");
722 auto const bob = Account(
"bob");
724 auto const startLegSeq = env.current()->info().seq;
725 env.fund(XRP(10000), alice, bob);
726 env(pay(alice, bob, XRP(10)));
731 jsonTx[jss::binary] =
false;
732 jsonTx[jss::ctid] = ctid;
734 auto jrr = env.rpc(
"json",
"tx",
to_string(jsonTx))[jss::result];
735 BEAST_EXPECT(!jrr[jss::ctid]);
736 BEAST_EXPECT(jrr[jss::hash]);
745 using namespace test::jtx;
749 Account
const alice{
"alice"};
750 Account
const alie{
"alie"};
751 Account
const gw{
"gw"};
752 auto const USD{gw[
"USD"]};
754 env.fund(XRP(1000000), alice, gw);
761 env(pay(alice, gw, XRP(100)));
766 env.closed()->txRead(env.tx()->getTransactionID()).second;
769 expected[jss::DeliverMax] = expected[jss::Amount];
776 Json::Value const result = {[&env, txn, apiVersion]() {
778 params[jss::transaction] =
to_string(txn->getTransactionID());
779 params[jss::binary] =
false;
780 params[jss::api_version] = apiVersion;
781 return env.client().invoke(
"tx", params);
784 BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
788 result[jss::result][jss::close_time_iso] ==
789 "2000-01-01T00:00:20Z");
791 result[jss::result][jss::hash] ==
793 BEAST_EXPECT(result[jss::result][jss::validated] ==
true);
794 BEAST_EXPECT(result[jss::result][jss::ledger_index] == 4);
796 result[jss::result][jss::ledger_hash] ==
797 "B41882E20F0EC6228417D28B9AE0F33833645D35F6799DFB782AC97FC4BB51"
801 for (
auto memberIt = expected.
begin(); memberIt != expected.
end();
805 auto const& result_transaction =
806 (apiVersion > 1 ? result[jss::result][jss::tx_json]
807 : result[jss::result]);
808 if (BEAST_EXPECT(result_transaction.isMember(name)))
810 auto const received = result_transaction[name];
812 received == *memberIt,
813 "Transaction contains \n\"" + name +
"\": "
827 using namespace test::jtx;
831 Account
const alice{
"alice"};
832 Account
const gw{
"gw"};
833 auto const USD{gw[
"USD"]};
835 env.fund(XRP(1000000), alice, gw);
839 "3F8BDE5A5F82C4F4708E5E9255B713E303E6E1A371FD5C7A704AFD1387C23981");
842 env.closed()->txRead(txn->getTransactionID()).second;
847 Json::Value const result = [&env, txn, apiVersion]() {
849 params[jss::transaction] =
to_string(txn->getTransactionID());
850 params[jss::binary] =
true;
851 params[jss::api_version] = apiVersion;
852 return env.client().invoke(
"tx", params);
855 if (BEAST_EXPECT(result[jss::status] ==
"success"))
857 BEAST_EXPECT(result[jss::result][jss::status] ==
"success");
858 BEAST_EXPECT(result[jss::result][jss::validated] ==
true);
860 result[jss::result][jss::hash] ==
862 BEAST_EXPECT(result[jss::result][jss::ledger_index] == 3);
863 BEAST_EXPECT(result[jss::result][jss::ctid] ==
"C000000300030000");
868 result[jss::result][jss::tx_blob] == expected_tx_blob);
870 result[jss::result][jss::meta_blob] == expected_meta_blob);
872 result[jss::result][jss::ledger_hash] ==
873 "2D5150E5A5AA436736A732291E437ABF01BC9E206C2DF3C77C4F856915"
876 result[jss::result][jss::close_time_iso] ==
877 "2000-01-01T00:00:10Z");
881 BEAST_EXPECT(result[jss::result][jss::tx] == expected_tx_blob);
883 result[jss::result][jss::meta] == expected_meta_blob);
884 BEAST_EXPECT(result[jss::result][jss::date] == 10);
893 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)