2#include <test/jtx/TestHelpers.h>
3#include <test/jtx/utility.h>
5#include <xrpld/app/misc/HashRouter.h>
6#include <xrpld/app/misc/NetworkOPs.h>
7#include <xrpld/app/misc/Transaction.h>
8#include <xrpld/app/tx/apply.h>
9#include <xrpld/app/tx/detail/Batch.h>
11#include <xrpl/protocol/Batch.h>
12#include <xrpl/protocol/Feature.h>
13#include <xrpl/protocol/STParsedJSON.h>
14#include <xrpl/protocol/Sign.h>
15#include <xrpl/protocol/TxFlags.h>
16#include <xrpl/protocol/jss.h>
41 for (
auto const& txn : jrr[jss::result][jss::ledger][jss::transactions])
43 if (txn[jss::metaData][sfTransactionIndex.jsonName] == index)
53 params[jss::ledger_index] = env.
closed()->seq();
54 params[jss::transactions] =
true;
55 params[jss::expand] =
true;
66 BEAST_EXPECT(jrr[sfTransactionType.jsonName] == ledgerResult.
txType);
68 jrr[jss::meta][sfTransactionResult.jsonName] ==
70 BEAST_EXPECT(jrr[jss::meta][sfParentBatchID.jsonName] == batchID);
79 auto const transactions =
80 jrr[jss::result][jss::ledger][jss::transactions];
81 BEAST_EXPECT(transactions.size() == ledgerResults.
size());
85 BEAST_EXPECT(txn[jss::hash].asString() == ledgerResult.txHash);
86 BEAST_EXPECT(txn.isMember(jss::metaData));
89 txn[sfTransactionType.jsonName] == ledgerResult.txType);
91 meta[sfTransactionResult.jsonName] == ledgerResult.result);
92 if (ledgerResult.batchID)
97 template <
typename... Args>
104 auto const ids = batchTxn.stx->getBatchTransactionIDs();
106 for (
auto const&
id : ids)
108 TxID const batchID = batchTxn.stx->getTransactionID();
124 auto& section = p->section(
"transaction_queue");
125 section.set(
"ledgers_in_queue",
"2");
126 section.set(
"minimum_queue_size",
"2");
127 section.set(
"min_ledgers_to_compute_size_limit",
"3");
128 section.set(
"max_ledger_counts_to_store",
"100");
129 section.set(
"retry_sequence_percent",
"25");
130 section.set(
"normal_consensus_increase_percent",
"0");
132 for (
auto const& [k, v] : extraTxQ)
143 auto const& view = *env.
current();
145 return toDrops(metrics.openLedgerFeeLevel, batchFee) + 1;
153 using namespace test::jtx;
156 for (
bool const withBatch : {
true,
false})
158 auto const amend = withBatch ? features : features - featureBatch;
161 auto const alice =
Account(
"alice");
162 auto const bob =
Account(
"bob");
163 auto const carol =
Account(
"carol");
164 env.fund(
XRP(10000), alice, bob, carol);
169 auto const seq = env.
seq(alice);
171 auto const txResult =
185 auto const txResult =
187 env(
pay(alice, bob,
XRP(1)),
202 using namespace test::jtx;
210 auto const alice =
Account(
"alice");
211 auto const bob =
Account(
"bob");
212 auto const carol =
Account(
"carol");
213 env.fund(
XRP(10000), alice, bob, carol);
226 auto const seq = env.
seq(alice);
235 auto const seq = env.
seq(alice);
244 auto const seq = env.
seq(alice);
254 auto const seq = env.
seq(alice);
263 auto const seq = env.
seq(alice);
274 auto const seq = env.
seq(alice);
293 auto const seq = env.
seq(alice);
294 auto jt = env.jtnofill(
306 auto const seq = env.
seq(alice);
320 auto const seq = env.
seq(alice);
323 auto jt = env.jtnofill(
334 auto const seq = env.
seq(alice);
336 auto jt = env.jt(
pay(alice, bob,
XRP(1)));
346 auto const seq = env.
seq(alice);
348 auto tx1 =
pay(alice, bob,
XRP(1));
351 tx1[sfSigners.jsonName][0U][sfSigner.jsonName][sfAccount.jsonName] =
353 tx1[sfSigners.jsonName][0U][sfSigner.jsonName]
354 [sfSigningPubKey.jsonName] =
strHex(alice.pk());
355 tx1[sfSigners.jsonName][0U][sfSigner.jsonName]
356 [sfTxnSignature.jsonName] =
"DEADBEEF";
367 auto const seq = env.
seq(alice);
370 tx1[jss::SigningPubKey] =
strHex(alice.pk());
371 auto jt = env.jtnofill(
382 auto const seq = env.
seq(alice);
394 auto const seq = env.
seq(alice);
397 tx1[jss::Fee] =
to_string(env.current()->fees().base);
408 auto const seq = env.
seq(alice);
411 tx1[jss::Sequence] =
seq + 1;
422 auto const seq = env.
seq(alice);
433 auto const seq = env.
seq(alice);
444 auto const seq = env.
seq(alice);
455 auto const seq = env.
seq(alice);
468 auto const seq = env.
seq(alice);
490 auto const seq = env.
seq(alice);
502 auto const seq = env.
seq(alice);
515 auto const seq = env.
seq(alice);
527 auto const seq = env.
seq(alice);
539 auto const seq = env.
seq(alice);
540 auto const bobSeq = env.seq(bob);
542 auto jt = env.jtnofill(
551 jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName]
552 [sfAccount.jsonName] = bob.human();
553 jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName]
554 [sfSigningPubKey.jsonName] =
strHex(alice.pk());
555 jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName]
556 [sfTxnSignature.jsonName] =
565 auto const seq = env.
seq(alice);
582 using namespace test::jtx;
590 auto const alice =
Account(
"alice");
591 auto const bob =
Account(
"bob");
592 auto const carol =
Account(
"carol");
593 auto const dave =
Account(
"dave");
594 auto const elsa =
Account(
"elsa");
595 auto const frank =
Account(
"frank");
596 auto const phantom =
Account(
"phantom");
597 env.memoize(phantom);
599 env.fund(
XRP(10000), alice, bob, carol, dave, elsa, frank);
607 auto const seq = env.
seq(alice);
622 auto const seq = env.
seq(alice);
632 env(
signers(alice, 2, {{bob, 1}, {carol, 1}}));
635 env(
signers(bob, 2, {{carol, 1}, {dave, 1}, {elsa, 1}}));
640 auto const seq = env.
seq(alice);
652 auto const seq = env.
seq(alice);
657 batch::msig(bob, {carol, Account(
"dave", KeyType::ed25519)}),
666 auto const seq = env.
seq(alice);
678 auto const seq = env.
seq(alice);
690 auto const seq = env.
seq(alice);
704 auto const seq = env.
seq(alice);
708 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
709 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
710 batch::msig(bob, {carol, Reg{dave, davo}}),
717 auto const seq = env.seq(alice);
720 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
721 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
722 batch::msig(bob, {carol}),
729 auto const seq = env.seq(alice);
732 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
733 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
734 batch::msig(bob, {carol, dave}),
741 auto const seq = env.seq(alice);
744 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
745 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
746 batch::msig(bob, {carol, dave}),
757 auto const ledSeq = env.current()->seq();
758 auto const seq = env.seq(alice);
761 batch::inner(
pay(alice, phantom,
XRP(1000)), seq + 1),
762 batch::inner(
noop(phantom), ledSeq),
763 batch::sig(Reg{phantom, carol}),
770 auto const ledSeq = env.current()->seq();
771 auto const seq = env.seq(alice);
774 batch::inner(
pay(alice, bob,
XRP(1000)), seq + 1),
775 batch::inner(
noop(bob), ledSeq),
776 batch::sig(Reg{bob, carol}),
784 auto const seq = env.seq(alice);
787 batch::inner(
pay(alice, bob,
XRP(1)), seq + 1),
788 batch::inner(
pay(bob, alice,
XRP(2)), env.seq(bob)),
789 batch::sig(Reg{bob, carol}),
796 auto const seq = env.seq(alice);
799 batch::inner(
pay(alice, bob,
XRP(1)), seq + 1),
800 batch::inner(
pay(bob, alice,
XRP(2)), env.seq(bob)),
810 auto const seq = env.seq(alice);
813 batch::inner(
pay(alice, bob,
XRP(1)), seq + 1),
814 batch::inner(
pay(bob, alice,
XRP(2)), env.seq(bob)),
824 testcase(
"bad raw txn");
826 using namespace test::jtx;
831 auto const alice =
Account(
"alice");
832 auto const bob =
Account(
"bob");
834 env.fund(
XRP(10000), alice, bob);
838 auto const batchFee = batch::calcBatchFee(env, 1, 2);
839 auto const seq = env.
seq(alice);
841 tx1.removeMember(jss::TransactionType);
842 auto jt = env.jtnofill(
853 auto const batchFee = batch::calcBatchFee(env, 1, 2);
854 auto const seq = env.
seq(alice);
856 tx1.removeMember(jss::Account);
857 auto jt = env.jtnofill(
868 auto const batchFee = batch::calcBatchFee(env, 1, 2);
869 auto const seq = env.
seq(alice);
871 tx1.removeMember(jss::Sequence);
872 auto jt = env.jtnofill(
883 auto const batchFee = batch::calcBatchFee(env, 1, 2);
884 auto const seq = env.
seq(alice);
886 tx1.removeMember(jss::Fee);
887 auto jt = env.jtnofill(
898 auto const batchFee = batch::calcBatchFee(env, 1, 2);
899 auto const seq = env.
seq(alice);
901 tx1.removeMember(jss::SigningPubKey);
902 auto jt = env.jtnofill(
915 testcase(
"bad sequence");
917 using namespace test::jtx;
922 auto const alice =
Account(
"alice");
923 auto const bob =
Account(
"bob");
925 auto const USD = gw[
"USD"];
927 env.fund(
XRP(10000), alice, bob, gw);
929 env.trust(USD(1000), alice, bob);
930 env(pay(gw, alice, USD(100)));
931 env(pay(gw, bob, USD(100)));
939 auto const preAliceSeq = env.seq(alice);
940 auto const preAlice = env.balance(alice);
941 auto const preAliceUSD = env.balance(alice, USD.issue());
942 auto const preBobSeq = env.seq(bob);
943 auto const preBob = env.balance(bob);
944 auto const preBobUSD = env.balance(bob, USD.issue());
946 auto const batchFee = batch::calcBatchFee(env, 1, 2);
947 auto const [txIDs, batchID] = submitBatch(
960 validateClosedLedger(env, testCases);
967 validateClosedLedger(env, testCases);
971 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
972 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
973 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
974 BEAST_EXPECT(env.seq(bob) == preBobSeq);
975 BEAST_EXPECT(env.balance(bob) == preBob);
976 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
981 auto const preAliceSeq = env.seq(alice);
982 auto const preAlice = env.balance(alice);
983 auto const preAliceUSD = env.balance(alice, USD.issue());
984 auto const preBobSeq = env.seq(bob);
985 auto const preBob = env.balance(bob);
986 auto const preBobUSD = env.balance(bob, USD.issue());
988 auto const batchFee = batch::calcBatchFee(env, 1, 2);
989 auto const [txIDs, batchID] = submitBatch(
1002 validateClosedLedger(env, testCases);
1009 validateClosedLedger(env, testCases);
1013 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1014 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1015 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1016 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1017 BEAST_EXPECT(env.balance(bob) == preBob);
1018 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1023 auto const preAliceSeq = env.seq(alice);
1024 auto const preAlice = env.balance(alice);
1025 auto const preAliceUSD = env.balance(alice, USD.issue());
1026 auto const preBobSeq = env.seq(bob);
1027 auto const preBob = env.balance(bob);
1028 auto const preBobUSD = env.balance(bob, USD.issue());
1030 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1031 auto const [txIDs, batchID] = submitBatch(
1044 validateClosedLedger(env, testCases);
1051 validateClosedLedger(env, testCases);
1055 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1056 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1057 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1058 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1059 BEAST_EXPECT(env.balance(bob) == preBob);
1060 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1065 auto const preAliceSeq = env.seq(alice);
1066 auto const preAlice = env.balance(alice);
1067 auto const preAliceUSD = env.balance(alice, USD.issue());
1068 auto const preBobSeq = env.seq(bob);
1069 auto const preBob = env.balance(bob);
1070 auto const preBobUSD = env.balance(bob, USD.issue());
1072 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1073 auto const [txIDs, batchID] = submitBatch(
1086 validateClosedLedger(env, testCases);
1093 validateClosedLedger(env, testCases);
1097 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1098 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1099 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1100 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1101 BEAST_EXPECT(env.balance(bob) == preBob);
1102 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1107 auto const preAliceSeq = env.seq(alice);
1108 auto const preAlice = env.balance(alice);
1109 auto const preAliceUSD = env.balance(alice, USD.issue());
1110 auto const preBobSeq = env.seq(bob);
1111 auto const preBob = env.balance(bob);
1112 auto const preBobUSD = env.balance(bob, USD.issue());
1114 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1115 auto const [txIDs, batchID] = submitBatch(
1128 validateClosedLedger(env, testCases);
1135 validateClosedLedger(env, testCases);
1139 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1140 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1141 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1142 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1143 BEAST_EXPECT(env.balance(bob) == preBob);
1144 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1151 testcase(
"bad outer fee");
1153 using namespace test::jtx;
1160 auto const alice =
Account(
"alice");
1161 auto const bob =
Account(
"bob");
1162 env.fund(
XRP(10000), alice, bob);
1169 auto const batchFee = batch::calcBatchFee(env, 0, 1);
1170 auto const aliceSeq = env.seq(alice);
1182 auto const alice =
Account(
"alice");
1183 auto const bob =
Account(
"bob");
1184 auto const carol =
Account(
"carol");
1185 env.fund(
XRP(10000), alice, bob, carol);
1191 env(signers(alice, 2, {{bob, 1}, {carol, 1}}));
1195 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1196 auto const aliceSeq = env.seq(alice);
1209 auto const alice =
Account(
"alice");
1210 auto const bob =
Account(
"bob");
1211 auto const carol =
Account(
"carol");
1212 env.fund(
XRP(10000), alice, bob, carol);
1218 env(signers(alice, 2, {{bob, 1}, {carol, 1}}));
1222 auto const batchFee = batch::calcBatchFee(env, 2, 2);
1223 auto const aliceSeq = env.seq(alice);
1224 auto const bobSeq = env.seq(bob);
1238 auto const alice =
Account(
"alice");
1239 auto const bob =
Account(
"bob");
1240 auto const carol =
Account(
"carol");
1241 env.fund(
XRP(10000), alice, bob, carol);
1247 env(signers(alice, 2, {{bob, 1}, {carol, 1}}));
1250 env(signers(bob, 2, {{alice, 1}, {carol, 1}}));
1254 auto const batchFee = batch::calcBatchFee(env, 3, 2);
1255 auto const aliceSeq = env.seq(alice);
1256 auto const bobSeq = env.seq(bob);
1270 auto const alice =
Account(
"alice");
1271 auto const bob =
Account(
"bob");
1272 env.fund(
XRP(10000), alice, bob);
1279 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1280 auto const aliceSeq = env.seq(alice);
1281 auto const bobSeq = env.seq(bob);
1294 auto const alice =
Account(
"alice");
1295 auto const bob =
Account(
"bob");
1296 auto const gw =
Account(
"gw");
1297 auto const USD = gw[
"USD"];
1299 env.fund(
XRP(10000), alice, bob, gw);
1301 auto const ammCreate =
1304 jv[jss::Account] = alice.human();
1307 jv[jss::TradingFee] = 0;
1308 jv[jss::TransactionType] = jss::AMMCreate;
1312 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1313 auto const seq = env.
seq(alice);
1325 testcase(
"calculate base fee");
1327 using namespace test::jtx;
1334 auto const alice =
Account(
"alice");
1335 auto const bob =
Account(
"bob");
1336 env.fund(
XRP(10000), alice, bob);
1339 auto const batchFee = batch::calcBatchFee(env, 0, 9);
1340 auto const aliceSeq = env.seq(alice);
1359 auto const alice =
Account(
"alice");
1360 auto const bob =
Account(
"bob");
1361 env.fund(
XRP(10000), alice, bob);
1364 auto const batchFee = batch::calcBatchFee(env, 0, 9);
1365 auto const aliceSeq = env.seq(alice);
1366 auto jt = env.jtnofill(
1378 env.app().openLedger().modify(
1384 return result.applied;
1392 auto const alice =
Account(
"alice");
1393 auto const bob =
Account(
"bob");
1394 env.fund(
XRP(10000), alice, bob);
1397 auto const aliceSeq = env.seq(alice);
1398 auto const batchFee = batch::calcBatchFee(env, 9, 2);
1402 batch::sig(bob, bob, bob, bob, bob, bob, bob, bob, bob, bob),
1411 auto const alice =
Account(
"alice");
1412 auto const bob =
Account(
"bob");
1413 env.fund(
XRP(10000), alice, bob);
1416 auto const batchFee = batch::calcBatchFee(env, 0, 9);
1417 auto const aliceSeq = env.seq(alice);
1418 auto jt = env.jtnofill(
1422 batch::sig(bob, bob, bob, bob, bob, bob, bob, bob, bob, bob));
1424 env.app().openLedger().modify(
1430 return result.applied;
1438 testcase(
"all or nothing");
1440 using namespace test::jtx;
1445 auto const alice =
Account(
"alice");
1446 auto const bob =
Account(
"bob");
1447 auto const gw =
Account(
"gw");
1448 auto const USD = gw[
"USD"];
1449 env.fund(
XRP(10000), alice, bob, gw);
1454 auto const preAlice = env.balance(alice);
1455 auto const preBob = env.balance(bob);
1457 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1458 auto const seq = env.
seq(alice);
1459 auto const [txIDs, batchID] = submitBatch(
1469 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1470 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1472 validateClosedLedger(env, testCases);
1475 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1478 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1479 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1484 auto const preAlice = env.balance(alice);
1485 auto const preBob = env.balance(bob);
1487 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1488 auto const seq = env.
seq(alice);
1490 auto const [txIDs, batchID] = submitBatch(
1502 validateClosedLedger(env, testCases);
1505 BEAST_EXPECT(env.seq(alice) ==
seq + 1);
1508 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1509 BEAST_EXPECT(env.balance(bob) == preBob);
1514 auto const preAlice = env.balance(alice);
1515 auto const preBob = env.balance(bob);
1517 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1518 auto const seq = env.
seq(alice);
1519 auto const [txIDs, batchID] = submitBatch(
1531 validateClosedLedger(env, testCases);
1534 BEAST_EXPECT(env.seq(alice) ==
seq + 1);
1537 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1538 BEAST_EXPECT(env.balance(bob) == preBob);
1543 auto const preAlice = env.balance(alice);
1544 auto const preBob = env.balance(bob);
1546 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1547 auto const seq = env.
seq(alice);
1548 auto const [txIDs, batchID] = submitBatch(
1560 validateClosedLedger(env, testCases);
1563 BEAST_EXPECT(env.seq(alice) ==
seq + 1);
1566 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1567 BEAST_EXPECT(env.balance(bob) == preBob);
1574 testcase(
"only one");
1576 using namespace test::jtx;
1581 auto const alice =
Account(
"alice");
1582 auto const bob =
Account(
"bob");
1583 auto const carol =
Account(
"carol");
1584 auto const dave =
Account(
"dave");
1585 auto const gw =
Account(
"gw");
1586 auto const USD = gw[
"USD"];
1587 env.fund(
XRP(10000), alice, bob, carol, dave, gw);
1592 auto const preAlice = env.balance(alice);
1593 auto const preBob = env.balance(bob);
1595 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1596 auto const seq = env.
seq(alice);
1597 auto const [txIDs, batchID] = submitBatch(
1611 {1,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[0], batchID},
1612 {2,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[1], batchID},
1613 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
1615 validateClosedLedger(env, testCases);
1618 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
1621 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1622 BEAST_EXPECT(env.balance(bob) == preBob);
1627 auto const preAlice = env.balance(alice);
1628 auto const preBob = env.balance(bob);
1630 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1631 auto const seq = env.
seq(alice);
1632 auto const [txIDs, batchID] = submitBatch(
1644 {1,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[0], batchID},
1645 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1647 validateClosedLedger(env, testCases);
1650 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1653 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
1654 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1659 auto const preAlice = env.balance(alice);
1660 auto const preBob = env.balance(bob);
1662 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1663 auto const seq = env.
seq(alice);
1664 auto const [txIDs, batchID] = submitBatch(
1676 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1678 validateClosedLedger(env, testCases);
1681 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1684 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
1685 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1690 auto const preAlice = env.balance(alice);
1691 auto const preBob = env.balance(bob);
1693 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1694 auto const seq = env.
seq(alice);
1695 auto const [txIDs, batchID] = submitBatch(
1707 {1,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1709 validateClosedLedger(env, testCases);
1712 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1715 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(1));
1716 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1721 auto const preAlice = env.balance(alice);
1722 auto const preBob = env.balance(bob);
1724 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1725 auto const seq = env.
seq(alice);
1726 auto const [txIDs, batchID] = submitBatch(
1738 {1,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1740 validateClosedLedger(env, testCases);
1743 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1746 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(1));
1747 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1752 auto const preAlice = env.balance(alice);
1753 auto const preBob = env.balance(bob);
1754 auto const preCarol = env.balance(carol);
1755 auto const seq = env.
seq(alice);
1756 auto const batchFee = batch::calcBatchFee(env, 0, 6);
1758 auto const [txIDs, batchID] = submitBatch(
1790 {1,
"OfferCreate",
"tecKILLED", txIDs[0], batchID},
1791 {2,
"OfferCreate",
"tecKILLED", txIDs[1], batchID},
1792 {3,
"OfferCreate",
"tecKILLED", txIDs[2], batchID},
1793 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
1795 validateClosedLedger(env, testCases);
1797 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(100) - batchFee);
1798 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(100));
1799 BEAST_EXPECT(env.balance(carol) == preCarol);
1806 testcase(
"until failure");
1808 using namespace test::jtx;
1813 auto const alice =
Account(
"alice");
1814 auto const bob =
Account(
"bob");
1815 auto const carol =
Account(
"carol");
1816 auto const dave =
Account(
"dave");
1817 auto const gw =
Account(
"gw");
1818 auto const USD = gw[
"USD"];
1819 env.fund(
XRP(10000), alice, bob, carol, dave, gw);
1824 auto const preAlice = env.balance(alice);
1825 auto const preBob = env.balance(bob);
1827 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1828 auto const seq = env.
seq(alice);
1829 auto const [txIDs, batchID] = submitBatch(
1842 {1,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[0], batchID},
1844 validateClosedLedger(env, testCases);
1847 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1850 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1851 BEAST_EXPECT(env.balance(bob) == preBob);
1856 auto const preAlice = env.balance(alice);
1857 auto const preBob = env.balance(bob);
1859 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1860 auto const seq = env.
seq(alice);
1861 auto const [txIDs, batchID] = submitBatch(
1873 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1874 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1875 {3,
"Payment",
"tesSUCCESS", txIDs[2], batchID},
1876 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
1878 validateClosedLedger(env, testCases);
1881 BEAST_EXPECT(env.seq(alice) ==
seq + 5);
1884 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(10) - batchFee);
1885 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(10));
1890 auto const preAlice = env.balance(alice);
1891 auto const preBob = env.balance(bob);
1893 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1894 auto const seq = env.
seq(alice);
1895 auto const [txIDs, batchID] = submitBatch(
1908 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1909 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1910 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
1912 validateClosedLedger(env, testCases);
1915 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
1918 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1919 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1924 auto const preAlice = env.balance(alice);
1925 auto const preBob = env.balance(bob);
1927 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1928 auto const seq = env.
seq(alice);
1929 auto const [txIDs, batchID] = submitBatch(
1942 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1943 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1945 validateClosedLedger(env, testCases);
1948 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1951 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1952 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1957 auto const preAlice = env.balance(alice);
1958 auto const preBob = env.balance(bob);
1960 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1961 auto const seq = env.
seq(alice);
1962 auto const [txIDs, batchID] = submitBatch(
1975 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1976 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1978 validateClosedLedger(env, testCases);
1981 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1984 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1985 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1990 auto const preAlice = env.balance(alice);
1991 auto const preBob = env.balance(bob);
1992 auto const preCarol = env.balance(carol);
1993 auto const seq = env.
seq(alice);
1994 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1995 auto const [txIDs, batchID] = submitBatch(
2013 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2014 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2015 {3,
"OfferCreate",
"tecKILLED", txIDs[2], batchID},
2017 validateClosedLedger(env, testCases);
2019 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(200) - batchFee);
2020 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(100));
2021 BEAST_EXPECT(env.balance(carol) == preCarol +
XRP(100));
2028 testcase(
"independent");
2030 using namespace test::jtx;
2035 auto const alice =
Account(
"alice");
2036 auto const bob =
Account(
"bob");
2037 auto const carol =
Account(
"carol");
2038 auto const gw =
Account(
"gw");
2039 auto const USD = gw[
"USD"];
2040 env.fund(
XRP(10000), alice, bob, carol, gw);
2045 auto const preAlice = env.balance(alice);
2046 auto const preBob = env.balance(bob);
2048 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2049 auto const seq = env.
seq(alice);
2050 auto const [txIDs, batchID] = submitBatch(
2064 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2065 {2,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[1], batchID},
2066 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
2067 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2069 validateClosedLedger(env, testCases);
2072 BEAST_EXPECT(env.seq(alice) ==
seq + 5);
2075 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(4) - batchFee);
2076 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(4));
2081 auto const preAlice = env.balance(alice);
2082 auto const preBob = env.balance(bob);
2084 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2085 auto const seq = env.
seq(alice);
2086 auto const [txIDs, batchID] = submitBatch(
2099 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2100 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2101 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
2102 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2104 validateClosedLedger(env, testCases);
2107 BEAST_EXPECT(env.seq(alice) ==
seq + 5);
2110 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(6) - batchFee);
2111 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(6));
2116 auto const preAlice = env.balance(alice);
2117 auto const preBob = env.balance(bob);
2119 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2120 auto const seq = env.
seq(alice);
2121 auto const [txIDs, batchID] = submitBatch(
2134 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2135 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2136 {3,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2138 validateClosedLedger(env, testCases);
2141 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
2144 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(6));
2145 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(6));
2150 auto const preAlice = env.balance(alice);
2151 auto const preBob = env.balance(bob);
2153 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2154 auto const seq = env.
seq(alice);
2155 auto const [txIDs, batchID] = submitBatch(
2168 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2169 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2170 {3,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2172 validateClosedLedger(env, testCases);
2175 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
2178 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(6));
2179 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(6));
2184 auto const preAlice = env.balance(alice);
2185 auto const preBob = env.balance(bob);
2186 auto const preCarol = env.balance(carol);
2187 auto const seq = env.
seq(alice);
2188 auto const batchFee = batch::calcBatchFee(env, 0, 3);
2189 auto const [txIDs, batchID] = submitBatch(
2206 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2207 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2208 {3,
"OfferCreate",
"tecKILLED", txIDs[2], batchID},
2210 validateClosedLedger(env, testCases);
2212 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(200) - batchFee);
2213 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(100));
2214 BEAST_EXPECT(env.balance(carol) == preCarol +
XRP(100));
2221 testcase(
"inner submit rpc");
2223 using namespace test::jtx;
2228 auto const alice =
Account(
"alice");
2229 auto const bob =
Account(
"bob");
2231 env.fund(
XRP(10000), alice, bob);
2234 auto submitAndValidate = [&](
Slice const&
slice) {
2235 auto const jrr = env.rpc(
"submit",
strHex(
slice))[jss::result];
2237 jrr[jss::status] ==
"error" &&
2238 jrr[jss::error] ==
"invalidTransaction" &&
2239 jrr[jss::error_exception] ==
2240 "fails local checks: Malformed: Invalid inner batch "
2252 txn[sfTxnSignature] =
"DEADBEEF";
2256 submitAndValidate(s.
slice());
2266 txn[sfSigningPubKey] =
strHex(alice.pk());
2270 submitAndValidate(s.
slice());
2284 submitAndValidate(s.
slice());
2297 auto const jrr = env.rpc(
"submit",
strHex(s.
slice()))[jss::result];
2299 jrr[jss::status] ==
"success" &&
2300 jrr[jss::engine_result] ==
"temINVALID_FLAG");
2309 testcase(
"account activation");
2311 using namespace test::jtx;
2316 auto const alice =
Account(
"alice");
2317 auto const bob =
Account(
"bob");
2318 env.fund(
XRP(10000), alice);
2322 auto const preAlice = env.balance(alice);
2323 auto const ledSeq = env.current()->seq();
2324 auto const seq = env.
seq(alice);
2325 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2326 auto const [txIDs, batchID] = submitBatch(
2337 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2338 {2,
"AccountSet",
"tesSUCCESS", txIDs[1], batchID},
2340 validateClosedLedger(env, testCases);
2343 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
2346 BEAST_EXPECT(env.seq(bob) == ledSeq + 1);
2349 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1000) - batchFee);
2350 BEAST_EXPECT(env.balance(bob) ==
XRP(1000));
2356 testcase(
"account set");
2358 using namespace test::jtx;
2363 auto const alice =
Account(
"alice");
2364 auto const bob =
Account(
"bob");
2365 env.fund(
XRP(10000), alice, bob);
2368 auto const preAlice = env.balance(alice);
2369 auto const preBob = env.balance(bob);
2371 auto const seq = env.
seq(alice);
2372 auto const batchFee = batch::calcBatchFee(env, 0, 2);
2376 auto const [txIDs, batchID] = submitBatch(
2386 {1,
"AccountSet",
"tesSUCCESS", txIDs[0], batchID},
2387 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2389 validateClosedLedger(env, testCases);
2397 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
2400 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
2401 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
2407 testcase(
"account delete");
2409 using namespace test::jtx;
2416 auto const alice =
Account(
"alice");
2417 auto const bob =
Account(
"bob");
2418 env.fund(
XRP(10000), alice, bob);
2422 for (
int i = 0; i < 5; ++i)
2425 auto const preAlice = env.balance(alice);
2426 auto const preBob = env.balance(bob);
2428 auto const seq = env.
seq(alice);
2429 auto const batchFee = batch::calcBatchFee(env, 0, 2) +
2430 env.current()->fees().increment;
2431 auto const [txIDs, batchID] = submitBatch(
2443 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2444 {2,
"AccountDelete",
"tesSUCCESS", txIDs[1], batchID},
2446 validateClosedLedger(env, testCases);
2450 BEAST_EXPECT(env.balance(bob) == preBob + (preAlice - batchFee));
2457 auto const alice =
Account(
"alice");
2458 auto const bob =
Account(
"bob");
2459 env.fund(
XRP(10000), alice, bob);
2463 for (
int i = 0; i < 5; ++i)
2466 auto const preAlice = env.balance(alice);
2467 auto const preBob = env.balance(bob);
2469 env.trust(bob[
"USD"](1000), alice);
2472 auto const seq = env.
seq(alice);
2473 auto const batchFee = batch::calcBatchFee(env, 0, 2) +
2474 env.current()->fees().increment;
2475 auto const [txIDs, batchID] = submitBatch(
2487 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2488 {2,
"AccountDelete",
"tecHAS_OBLIGATIONS", txIDs[1], batchID},
2489 {3,
"Payment",
"tesSUCCESS", txIDs[2], batchID},
2491 validateClosedLedger(env, testCases);
2495 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
2502 auto const alice =
Account(
"alice");
2503 auto const bob =
Account(
"bob");
2504 env.fund(
XRP(10000), alice, bob);
2508 for (
int i = 0; i < 5; ++i)
2511 auto const preAlice = env.balance(alice);
2512 auto const preBob = env.balance(bob);
2514 auto const seq = env.
seq(alice);
2515 auto const batchFee = batch::calcBatchFee(env, 0, 2) +
2516 env.current()->fees().increment;
2517 auto const [txIDs, batchID] = submitBatch(
2530 validateClosedLedger(env, testCases);
2534 BEAST_EXPECT(env.balance(bob) == preBob);
2546 [](
auto const& disabled) {
return disabled == ttLOAN_BROKER_SET; });
2548 using namespace test::jtx;
2553 features | featureSingleAssetVault | featureLendingProtocol |
2556 Account const issuer{
"issuer"};
2559 Account const lender{
"lender"};
2561 Account const borrower{
"borrower"};
2565 env.fund(
XRP(100'000), issuer,
noripple(lender, borrower));
2573 auto const deposit = asset(50'000);
2574 auto const debtMaximumValue = asset(25'000).value();
2575 auto const coverDepositValue = asset(1000).value();
2577 auto [tx, vaultKeylet] =
2578 vault.create({.owner = lender, .asset = asset});
2581 BEAST_EXPECT(env.le(vaultKeylet));
2584 {.depositor = lender, .id = vaultKeylet.key, .amount = deposit}));
2587 auto const brokerKeylet =
2591 using namespace loanBroker;
2592 env(
set(lender, vaultKeylet.key),
2594 debtMaximum(debtMaximumValue),
2598 env(coverDeposit(lender, brokerKeylet.key, coverDepositValue));
2604 using namespace loan;
2605 using namespace std::chrono_literals;
2607 auto const lenderSeq = env.seq(lender);
2608 auto const batchFee = batch::calcBatchFee(env, 0, 2);
2610 auto const loanKeylet =
keylet::loan(brokerKeylet.key, 1);
2612 auto const [txIDs, batchID] = submitBatch(
2619 set(lender, brokerKeylet.key, asset(1000).value()),
2621 sig(sfCounterpartySignature, borrower),
2629 STAmount{asset, asset(500).value()}),
2633 auto const [txIDs, batchID] = submitBatch(
2639 set(lender, brokerKeylet.key, asset(1000).value()),
2648 STAmount{asset, asset(500).value()}),
2652 auto const [txIDs, batchID] = submitBatch(
2659 set(lender, brokerKeylet.key, asset(1000).value()),
2661 counterparty(borrower.id()),
2669 STAmount{asset, asset(500).value()}),
2676 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2677 auto const [txIDs, batchID] = submitBatch(
2684 set(lender, brokerKeylet.key, asset(1000).value()),
2685 counterparty(borrower.id()),
2697 STAmount{asset, asset(500).value()}),
2702 BEAST_EXPECT(env.le(brokerKeylet));
2703 BEAST_EXPECT(!env.le(loanKeylet));
2708 auto const lenderSeq = env.seq(lender);
2709 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2710 auto const [txIDs, batchID] = submitBatch(
2717 set(lender, brokerKeylet.key, asset(1000).value()),
2718 counterparty(borrower.id()),
2729 BEAST_EXPECT(env.le(brokerKeylet));
2730 if (
auto const sleLoan = env.le(loanKeylet); lendingBatchEnabled
2731 ? BEAST_EXPECT(sleLoan)
2732 : !BEAST_EXPECT(!sleLoan))
2742 testcase(
"object create w/ sequence");
2744 using namespace test::jtx;
2749 auto const alice =
Account(
"alice");
2750 auto const bob =
Account(
"bob");
2751 auto const gw =
Account(
"gw");
2752 auto const USD = gw[
"USD"];
2754 env.fund(
XRP(10000), alice, bob, gw);
2757 env.trust(USD(1000), alice, bob);
2758 env(pay(gw, alice, USD(100)));
2759 env(pay(gw, bob, USD(100)));
2764 auto const aliceSeq = env.seq(alice);
2765 auto const bobSeq = env.seq(bob);
2766 auto const preAlice = env.balance(alice);
2767 auto const preBob = env.balance(bob);
2768 auto const preAliceUSD = env.balance(alice, USD.issue());
2769 auto const preBobUSD = env.balance(bob, USD.issue());
2771 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2772 uint256 const chkID{getCheckIndex(bob, env.seq(bob))};
2773 auto const [txIDs, batchID] = submitBatch(
2777 batch::inner(check::create(bob, alice, USD(10)), bobSeq),
2778 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq + 1),
2784 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
2785 {2,
"CheckCash",
"tesSUCCESS", txIDs[1], batchID},
2787 validateClosedLedger(env, testCases);
2790 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
2793 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
2796 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
2797 BEAST_EXPECT(env.balance(bob) == preBob);
2801 env.balance(alice, USD.issue()) == preAliceUSD + USD(10));
2802 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10));
2810 auto const aliceSeq = env.seq(alice);
2811 auto const bobSeq = env.seq(bob);
2812 auto const preAlice = env.balance(alice);
2813 auto const preBob = env.balance(bob);
2814 auto const preAliceUSD = env.balance(alice, USD.issue());
2815 auto const preBobUSD = env.balance(bob, USD.issue());
2817 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2818 uint256 const chkID{getCheckIndex(bob, env.seq(bob))};
2819 auto const [txIDs, batchID] = submitBatch(
2824 batch::inner(check::create(bob, alice, USD(10)), bobSeq),
2825 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq + 1),
2831 {1,
"CheckCreate",
"tecDST_TAG_NEEDED", txIDs[0], batchID},
2832 {2,
"CheckCash",
"tecNO_ENTRY", txIDs[1], batchID},
2834 validateClosedLedger(env, testCases);
2837 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
2840 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
2843 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
2844 BEAST_EXPECT(env.balance(bob) == preBob);
2847 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
2848 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
2855 testcase(
"object create w/ ticket");
2857 using namespace test::jtx;
2862 auto const alice =
Account(
"alice");
2863 auto const bob =
Account(
"bob");
2864 auto const gw =
Account(
"gw");
2865 auto const USD = gw[
"USD"];
2867 env.fund(
XRP(10000), alice, bob, gw);
2870 env.trust(USD(1000), alice, bob);
2871 env(pay(gw, alice, USD(100)));
2872 env(pay(gw, bob, USD(100)));
2875 auto const aliceSeq = env.seq(alice);
2876 auto const bobSeq = env.seq(bob);
2877 auto const preAlice = env.balance(alice);
2878 auto const preBob = env.balance(bob);
2879 auto const preAliceUSD = env.balance(alice, USD.issue());
2880 auto const preBobUSD = env.balance(bob, USD.issue());
2882 auto const batchFee = batch::calcBatchFee(env, 1, 3);
2883 uint256 const chkID{getCheckIndex(bob, bobSeq + 1)};
2884 auto const [txIDs, batchID] = submitBatch(
2889 batch::inner(check::create(bob, alice, USD(10)), 0, bobSeq + 1),
2890 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq + 1),
2896 {1,
"TicketCreate",
"tesSUCCESS", txIDs[0], batchID},
2897 {2,
"CheckCreate",
"tesSUCCESS", txIDs[1], batchID},
2898 {3,
"CheckCash",
"tesSUCCESS", txIDs[2], batchID},
2900 validateClosedLedger(env, testCases);
2902 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
2903 BEAST_EXPECT(env.seq(bob) == bobSeq + 10 + 1);
2904 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
2905 BEAST_EXPECT(env.balance(bob) == preBob);
2906 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD + USD(10));
2907 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10));
2913 testcase(
"object create w/ 3rd party");
2915 using namespace test::jtx;
2920 auto const alice =
Account(
"alice");
2921 auto const bob =
Account(
"bob");
2922 auto const carol =
Account(
"carol");
2923 auto const gw =
Account(
"gw");
2924 auto const USD = gw[
"USD"];
2926 env.fund(
XRP(10000), alice, bob, carol, gw);
2929 env.trust(USD(1000), alice, bob);
2930 env(pay(gw, alice, USD(100)));
2931 env(pay(gw, bob, USD(100)));
2934 auto const aliceSeq = env.seq(alice);
2935 auto const bobSeq = env.seq(bob);
2936 auto const carolSeq = env.seq(carol);
2937 auto const preAlice = env.balance(alice);
2938 auto const preBob = env.balance(bob);
2939 auto const preCarol = env.balance(carol);
2940 auto const preAliceUSD = env.balance(alice, USD.issue());
2941 auto const preBobUSD = env.balance(bob, USD.issue());
2943 auto const batchFee = batch::calcBatchFee(env, 2, 2);
2944 uint256 const chkID{getCheckIndex(bob, env.seq(bob))};
2945 auto const [txIDs, batchID] = submitBatch(
2949 batch::inner(check::create(bob, alice, USD(10)), bobSeq),
2950 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq),
2956 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
2957 {2,
"CheckCash",
"tesSUCCESS", txIDs[1], batchID},
2959 validateClosedLedger(env, testCases);
2961 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
2962 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
2963 BEAST_EXPECT(env.seq(carol) == carolSeq + 1);
2964 BEAST_EXPECT(env.balance(alice) == preAlice);
2965 BEAST_EXPECT(env.balance(bob) == preBob);
2966 BEAST_EXPECT(env.balance(carol) == preCarol - batchFee);
2967 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD + USD(10));
2968 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10));
2975 testcase(
"tickets outer");
2977 using namespace test::jtx;
2982 auto const alice =
Account(
"alice");
2983 auto const bob =
Account(
"bob");
2985 env.fund(
XRP(10000), alice, bob);
2989 env(ticket::create(alice, 10));
2992 auto const aliceSeq = env.seq(alice);
2993 auto const preAlice = env.balance(alice);
2994 auto const preBob = env.balance(bob);
2996 auto const batchFee = batch::calcBatchFee(env, 0, 2);
2997 auto const [txIDs, batchID] = submitBatch(
3008 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3009 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3011 validateClosedLedger(env, testCases);
3015 BEAST_EXPECT(sle->getFieldU32(sfOwnerCount) == 9);
3016 BEAST_EXPECT(sle->getFieldU32(sfTicketCount) == 9);
3018 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
3019 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3020 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3024 testcase(
"tickets inner");
3026 using namespace test::jtx;
3031 auto const alice =
Account(
"alice");
3032 auto const bob =
Account(
"bob");
3034 env.fund(
XRP(10000), alice, bob);
3038 env(ticket::create(alice, 10));
3041 auto const aliceSeq = env.seq(alice);
3042 auto const preAlice = env.balance(alice);
3043 auto const preBob = env.balance(bob);
3045 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3046 auto const [txIDs, batchID] = submitBatch(
3056 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3057 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3059 validateClosedLedger(env, testCases);
3063 BEAST_EXPECT(sle->getFieldU32(sfOwnerCount) == 8);
3064 BEAST_EXPECT(sle->getFieldU32(sfTicketCount) == 8);
3066 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
3067 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3068 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3072 testcase(
"tickets outer inner");
3074 using namespace test::jtx;
3079 auto const alice =
Account(
"alice");
3080 auto const bob =
Account(
"bob");
3082 env.fund(
XRP(10000), alice, bob);
3086 env(ticket::create(alice, 10));
3089 auto const aliceSeq = env.seq(alice);
3090 auto const preAlice = env.balance(alice);
3091 auto const preBob = env.balance(bob);
3093 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3094 auto const [txIDs, batchID] = submitBatch(
3105 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3106 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3108 validateClosedLedger(env, testCases);
3112 BEAST_EXPECT(sle->getFieldU32(sfOwnerCount) == 8);
3113 BEAST_EXPECT(sle->getFieldU32(sfTicketCount) == 8);
3115 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
3116 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3117 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3124 testcase(
"sequence open ledger");
3126 using namespace test::jtx;
3129 auto const alice =
Account(
"alice");
3130 auto const bob =
Account(
"bob");
3131 auto const carol =
Account(
"carol");
3141 env.fund(
XRP(10000), alice, bob, carol);
3144 auto const aliceSeq = env.seq(alice);
3145 auto const carolSeq = env.seq(carol);
3148 auto const noopTxn = env.jt(
noop(alice),
seq(aliceSeq + 2));
3149 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3153 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3154 auto const [txIDs, batchID] = submitBatch(
3166 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3167 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3169 validateClosedLedger(env, testCases);
3176 {0,
"AccountSet",
"tesSUCCESS", noopTxnID,
std::nullopt},
3178 validateClosedLedger(env, testCases);
3188 env.fund(
XRP(10000), alice, bob);
3191 auto const aliceSeq = env.seq(alice);
3194 auto const noopTxn = env.jt(
noop(alice),
seq(aliceSeq + 1));
3198 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3199 auto const [txIDs, batchID] = submitBatch(
3210 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3211 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3213 validateClosedLedger(env, testCases);
3220 validateClosedLedger(env, testCases);
3230 env.fund(
XRP(10000), alice, bob);
3233 auto const aliceSeq = env.seq(alice);
3234 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3235 auto const [txIDs, batchID] = submitBatch(
3242 auto const noopTxn = env.jt(
noop(alice),
seq(aliceSeq + 1));
3243 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3250 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3251 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3253 validateClosedLedger(env, testCases);
3260 validateClosedLedger(env, testCases);
3267 env.fund(
XRP(10000), alice, bob, carol);
3270 auto const aliceSeq = env.seq(alice);
3271 auto const carolSeq = env.seq(carol);
3274 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3275 auto const [txIDs, batchID] = submitBatch(
3284 auto const noopTxn = env.jt(
noop(carol),
seq(carolSeq));
3285 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3291 {0,
"AccountSet",
"tesSUCCESS", noopTxnID,
std::nullopt},
3293 {2,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3294 {3,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3296 validateClosedLedger(env, testCases);
3303 validateClosedLedger(env, testCases);
3311 testcase(
"tickets open ledger");
3313 using namespace test::jtx;
3316 auto const alice =
Account(
"alice");
3317 auto const bob =
Account(
"bob");
3325 env.fund(
XRP(10000), alice, bob);
3329 env(ticket::create(alice, 10));
3332 auto const aliceSeq = env.seq(alice);
3335 auto const noopTxn =
3337 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3341 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3342 auto const [txIDs, batchID] = submitBatch(
3354 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3355 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3357 validateClosedLedger(env, testCases);
3364 validateClosedLedger(env, testCases);
3374 env.fund(
XRP(10000), alice, bob);
3378 env(ticket::create(alice, 10));
3381 auto const aliceSeq = env.seq(alice);
3384 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3385 auto const [txIDs, batchID] = submitBatch(
3394 auto const noopTxn =
3402 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3403 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3405 validateClosedLedger(env, testCases);
3412 validateClosedLedger(env, testCases);
3420 testcase(
"objects open ledger");
3422 using namespace test::jtx;
3425 auto const alice =
Account(
"alice");
3426 auto const bob =
Account(
"bob");
3436 env.fund(
XRP(10000), alice, bob);
3440 env(ticket::create(alice, 10));
3443 auto const aliceSeq = env.seq(alice);
3446 uint256 const chkID{getCheckIndex(alice, aliceSeq)};
3447 auto const objTxn = env.jt(check::cash(bob, chkID,
XRP(10)));
3448 auto const objTxnID =
to_string(objTxn.stx->getTransactionID());
3452 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3453 auto const [txIDs, batchID] = submitBatch(
3465 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
3466 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3467 {3,
"CheckCash",
"tesSUCCESS", objTxnID,
std::nullopt},
3469 validateClosedLedger(env, testCases);
3476 validateClosedLedger(env, testCases);
3483 env.fund(
XRP(10000), alice, bob);
3487 env(ticket::create(alice, 10));
3490 auto const aliceSeq = env.seq(alice);
3491 auto const bobSeq = env.seq(bob);
3494 uint256 const chkID{getCheckIndex(alice, aliceSeq)};
3495 auto const objTxn = env.jt(check::create(alice, bob,
XRP(10)));
3496 auto const objTxnID =
to_string(objTxn.stx->getTransactionID());
3500 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3501 auto const [txIDs, batchID] = submitBatch(
3513 {0,
"CheckCreate",
"tesSUCCESS", objTxnID,
std::nullopt},
3515 {2,
"CheckCash",
"tesSUCCESS", txIDs[0], batchID},
3516 {3,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3518 validateClosedLedger(env, testCases);
3530 env.fund(
XRP(10000), alice, bob);
3534 env(ticket::create(alice, 10));
3537 auto const aliceSeq = env.seq(alice);
3540 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3541 uint256 const chkID{getCheckIndex(alice, aliceSeq)};
3542 auto const [txIDs, batchID] = submitBatch(
3551 auto const objTxn = env.jt(check::cash(bob, chkID,
XRP(10)));
3552 auto const objTxnID =
to_string(objTxn.stx->getTransactionID());
3559 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
3560 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3561 {3,
"CheckCash",
"tesSUCCESS", objTxnID,
std::nullopt},
3563 validateClosedLedger(env, testCases);
3571 testcase(
"pseudo txn with tfInnerBatchTxn");
3573 using namespace test::jtx;
3578 auto const alice =
Account(
"alice");
3579 auto const bob =
Account(
"bob");
3580 env.fund(
XRP(10000), alice, bob);
3583 STTx const stx =
STTx(ttAMENDMENT, [&](
auto& obj) {
3584 obj.setAccountID(sfAccount,
AccountID());
3585 obj.setFieldH256(sfAmendment,
uint256(2));
3586 obj.setFieldU32(sfLedgerSequence, env.seq(alice));
3593 BEAST_EXPECT(reason ==
"Cannot submit pseudo transactions.");
3597 return result.applied;
3604 testcase(
"batch open ledger");
3612 using namespace test::jtx;
3616 XRPAmount const baseFee = env.current()->fees().base;
3618 auto const alice =
Account(
"alice");
3619 auto const bob =
Account(
"bob");
3621 env.fund(
XRP(10000), alice, bob);
3627 auto const aliceSeq = env.seq(alice);
3628 auto const preAlice = env.balance(alice);
3629 auto const preBob = env.balance(bob);
3630 auto const bobSeq = env.seq(bob);
3633 auto const payTxn1 = env.jt(pay(alice, bob,
XRP(10)),
seq(aliceSeq));
3634 auto const payTxn1ID =
to_string(payTxn1.stx->getTransactionID());
3638 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3639 auto const [txIDs, batchID] = submitBatch(
3648 auto const payTxn2 = env.jt(pay(bob, alice,
XRP(5)),
seq(bobSeq + 1));
3649 auto const payTxn2ID =
to_string(payTxn2.stx->getTransactionID());
3656 {2,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3657 {3,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3659 validateClosedLedger(env, testCases);
3667 validateClosedLedger(env, testCases);
3671 BEAST_EXPECT(env.seq(alice) == aliceSeq + 3);
3674 BEAST_EXPECT(env.seq(bob) == bobSeq + 2);
3678 env.balance(alice) == preAlice -
XRP(10) - batchFee - baseFee);
3679 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(10) - baseFee);
3685 testcase(
"batch tx queue");
3687 using namespace test::jtx;
3694 makeSmallQueueConfig(
3695 {{
"minimum_txn_in_ledger_standalone",
"2"}}),
3699 auto alice =
Account(
"alice");
3701 auto carol =
Account(
"carol");
3705 env.close(env.now() + 5s, 10000ms);
3707 env.close(env.now() + 5s, 10000ms);
3718 auto const aliceSeq = env.seq(alice);
3719 auto const bobSeq = env.seq(bob);
3720 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3738 openLedgerFee(env, batchFee),
3754 makeSmallQueueConfig(
3755 {{
"minimum_txn_in_ledger_standalone",
"2"}}),
3759 auto alice =
Account(
"alice");
3761 auto carol =
Account(
"carol");
3765 env.close(env.now() + 5s, 10000ms);
3767 env.close(env.now() + 5s, 10000ms);
3774 auto const aliceSeq = env.seq(alice);
3775 auto const bobSeq = env.seq(bob);
3776 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3797 testcase(
"batch network ops");
3799 using namespace test::jtx;
3809 auto alice =
Account(
"alice");
3811 env.
fund(
XRP(10000), alice, bob);
3819 return jt.stx->getTransactionID();
3831 return transaction->getID();
3856 testcase(
"batch delegate");
3858 using namespace test::jtx;
3865 auto const alice =
Account(
"alice");
3866 auto const bob =
Account(
"bob");
3867 auto const gw =
Account(
"gw");
3868 auto const USD = gw[
"USD"];
3869 env.fund(
XRP(10000), alice, bob, gw);
3872 env(delegate::set(alice, bob, {
"Payment"}));
3875 auto const preAlice = env.balance(alice);
3876 auto const preBob = env.balance(bob);
3878 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3879 auto const seq = env.
seq(alice);
3882 tx[jss::Delegate] = bob.human();
3883 auto const [txIDs, batchID] = submitBatch(
3893 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3894 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3896 validateClosedLedger(env, testCases);
3899 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
3902 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3903 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3910 auto const alice =
Account(
"alice");
3911 auto const bob =
Account(
"bob");
3912 auto const carol =
Account(
"carol");
3913 auto const gw =
Account(
"gw");
3914 auto const USD = gw[
"USD"];
3915 env.fund(
XRP(10000), alice, bob, carol, gw);
3918 env(delegate::set(bob, carol, {
"Payment"}));
3921 auto const preAlice = env.balance(alice);
3922 auto const preBob = env.balance(bob);
3923 auto const preCarol = env.balance(carol);
3925 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3926 auto const aliceSeq = env.seq(alice);
3927 auto const bobSeq = env.seq(bob);
3930 tx[jss::Delegate] = carol.human();
3931 auto const [txIDs, batchID] = submitBatch(
3942 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3943 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3945 validateClosedLedger(env, testCases);
3947 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
3948 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
3949 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
3950 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
3953 BEAST_EXPECT(env.balance(carol) == preCarol);
3962 auto const alice =
Account(
"alice");
3963 auto const bob =
Account(
"bob");
3964 auto const gw =
Account(
"gw");
3965 auto const USD = gw[
"USD"];
3966 env.fund(
XRP(10000), alice, bob, gw);
3969 env(delegate::set(alice, bob, {
"AccountDomainSet"}));
3972 auto const preAlice = env.balance(alice);
3973 auto const preBob = env.balance(bob);
3975 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3976 auto const seq = env.
seq(alice);
3981 tx[jss::Delegate] = bob.human();
3982 auto const [txIDs, batchID] = submitBatch(
3992 {1,
"AccountSet",
"tesSUCCESS", txIDs[0], batchID},
3993 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3995 validateClosedLedger(env, testCases);
3998 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
4001 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(2) - batchFee);
4002 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(2));
4012 env.fund(
XRP(100000), alice, bob);
4015 auto const mptID =
makeMptID(env.seq(alice), alice);
4016 MPTTester mpt(env, alice, {.fund =
false});
4023 alice, bob, {
"MPTokenIssuanceLock",
"MPTokenIssuanceUnlock"}));
4026 auto const seq = env.
seq(alice);
4027 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4030 jv1[sfTransactionType] = jss::MPTokenIssuanceSet;
4031 jv1[sfAccount] = alice.human();
4032 jv1[sfDelegate] = bob.human();
4033 jv1[sfSequence] =
seq + 1;
4034 jv1[sfMPTokenIssuanceID] =
to_string(mptID);
4038 jv2[sfTransactionType] = jss::MPTokenIssuanceSet;
4039 jv2[sfAccount] = alice.human();
4040 jv2[sfDelegate] = bob.human();
4041 jv2[sfSequence] =
seq + 2;
4042 jv2[sfMPTokenIssuanceID] =
to_string(mptID);
4045 auto const [txIDs, batchID] = submitBatch(
4055 {1,
"MPTokenIssuanceSet",
"tesSUCCESS", txIDs[0], batchID},
4056 {2,
"MPTokenIssuanceSet",
"tesSUCCESS", txIDs[1], batchID},
4058 validateClosedLedger(env, testCases);
4069 env.fund(
XRP(10000), gw, alice, bob);
4072 env(trust(alice, gw[
"USD"](50)));
4076 gw, bob, {
"TrustlineAuthorize",
"TrustlineFreeze"}));
4079 auto const seq = env.
seq(gw);
4080 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4082 auto jv1 = trust(gw, gw[
"USD"](0), alice,
tfSetfAuth);
4083 jv1[sfDelegate] = bob.human();
4084 auto jv2 = trust(gw, gw[
"USD"](0), alice,
tfSetFreeze);
4085 jv2[sfDelegate] = bob.human();
4087 auto const [txIDs, batchID] = submitBatch(
4097 {1,
"TrustSet",
"tesSUCCESS", txIDs[0], batchID},
4098 {2,
"TrustSet",
"tesSUCCESS", txIDs[1], batchID},
4100 validateClosedLedger(env, testCases);
4109 env.fund(
XRP(10000), gw, alice, bob);
4112 env(trust(alice, gw[
"USD"](50)));
4116 gw, bob, {
"TrustlineAuthorize",
"TrustlineFreeze"}));
4119 auto const seq = env.
seq(gw);
4120 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4122 auto jv1 = trust(gw, gw[
"USD"](0), alice,
tfSetFreeze);
4123 jv1[sfDelegate] = bob.human();
4125 jv2[sfDelegate] = bob.human();
4127 auto const [txIDs, batchID] = submitBatch(
4138 {1,
"TrustSet",
"tesSUCCESS", txIDs[0], batchID},
4140 validateClosedLedger(env, testCases);
4150 testcase(
"Validate RPC response");
4152 using namespace jtx;
4156 env.
fund(
XRP(10000), alice, bob);
4161 auto const baseFee = env.
current()->fees().base;
4162 auto const aliceSeq = env.
seq(alice);
4163 auto jtx = env.
jt(pay(alice, bob,
XRP(1)));
4167 auto const jr = env.
rpc(
"submit",
strHex(s.
slice()))[jss::result];
4170 BEAST_EXPECT(jr.isMember(jss::account_sequence_available));
4172 jr[jss::account_sequence_available].asUInt() == aliceSeq + 1);
4173 BEAST_EXPECT(jr.isMember(jss::account_sequence_next));
4175 jr[jss::account_sequence_next].asUInt() == aliceSeq + 1);
4176 BEAST_EXPECT(jr.isMember(jss::open_ledger_cost));
4177 BEAST_EXPECT(jr[jss::open_ledger_cost] ==
to_string(baseFee));
4178 BEAST_EXPECT(jr.isMember(jss::validated_ledger_index));
4183 auto const baseFee = env.
current()->fees().base;
4184 auto const aliceSeq = env.
seq(alice);
4186 auto jtx = env.
jt(pay(alice, bob,
XRP(1)),
seq(aliceSeq));
4190 auto const jr = env.
rpc(
"submit",
strHex(s.
slice()))[jss::result];
4193 BEAST_EXPECT(jr.isMember(jss::account_sequence_available));
4195 jr[jss::account_sequence_available].asUInt() == aliceSeq + 1);
4196 BEAST_EXPECT(jr.isMember(jss::account_sequence_next));
4198 jr[jss::account_sequence_next].asUInt() == aliceSeq + 1);
4199 BEAST_EXPECT(jr.isMember(jss::open_ledger_cost));
4200 BEAST_EXPECT(jr[jss::open_ledger_cost] ==
to_string(baseFee));
4201 BEAST_EXPECT(jr.isMember(jss::validated_ledger_index));
4206 auto const baseFee = env.
current()->fees().base;
4207 auto const aliceSeq = env.
seq(alice);
4208 auto jtx = env.
jt(pay(alice, bob,
XRP(1)),
seq(aliceSeq + 1));
4212 auto const jr = env.
rpc(
"submit",
strHex(s.
slice()))[jss::result];
4215 BEAST_EXPECT(jr.isMember(jss::account_sequence_available));
4217 jr[jss::account_sequence_available].asUInt() == aliceSeq);
4218 BEAST_EXPECT(jr.isMember(jss::account_sequence_next));
4219 BEAST_EXPECT(jr[jss::account_sequence_next].asUInt() == aliceSeq);
4220 BEAST_EXPECT(jr.isMember(jss::open_ledger_cost));
4221 BEAST_EXPECT(jr[jss::open_ledger_cost] ==
to_string(baseFee));
4222 BEAST_EXPECT(jr.isMember(jss::validated_ledger_index));
4229 using namespace jtx;
4234 env.
fund(
XRP(10000), alice, bob, carol);
4245 auto const seq = env.
seq(alice);
4246 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4252 XRPAmount const txBaseFee = getBaseFee(jtx);
4258 auto const seq = env.
seq(alice);
4259 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4273 XRPAmount const txBaseFee = getBaseFee(jtx);
4279 auto const seq = env.
seq(alice);
4280 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4297 XRPAmount const txBaseFee = getBaseFee(jtx);
4303 auto const seq = env.
seq(alice);
4304 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4309 XRPAmount const txBaseFee = getBaseFee(jtx);
4310 BEAST_EXPECT(txBaseFee == batchFee);
4317 testEnable(features);
4318 testPreflight(features);
4319 testPreclaim(features);
4320 testBadRawTxn(features);
4321 testBadSequence(features);
4322 testBadOuterFee(features);
4323 testCalculateBaseFee(features);
4324 testAllOrNothing(features);
4325 testOnlyOne(features);
4326 testUntilFailure(features);
4327 testIndependent(features);
4328 testInnerSubmitRPC(features);
4329 testAccountActivation(features);
4330 testAccountSet(features);
4331 testAccountDelete(features);
4333 testObjectCreateSequence(features);
4334 testObjectCreateTicket(features);
4335 testObjectCreate3rdParty(features);
4336 testTickets(features);
4337 testSequenceOpenLedger(features);
4338 testTicketsOpenLedger(features);
4339 testObjectsOpenLedger(features);
4340 testPseudoTxn(features);
4341 testOpenLedger(features);
4342 testBatchTxQueue(features);
4343 testBatchNetworkOps(features);
4344 testBatchDelegate(features);
4345 testValidateRPCResponse(features);
4346 testBatchCalculateBaseFee(features);
4353 using namespace test::jtx;
A generic endpoint for log messages.
testcase_t testcase
Memberspace for declaring test cases.
virtual NetworkOPs & getOPs()=0
virtual HashRouter & getHashRouter()=0
static constexpr auto disabledTxTypes
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
Calculates the total base fee for a batch transaction.
HashRouterFlags getFlags(uint256 const &key)
virtual void submitTransaction(std::shared_ptr< STTx const > const &)=0
virtual void processTransaction(std::shared_ptr< Transaction > &transaction, bool bUnlimited, bool bLocal, FailHard failType)=0
Process transactions as they arrive from the network or which are submitted by clients.
Writable ledger view that accumulates state and tx changes.
Holds the serialized result of parsing an input JSON object.
std::optional< STObject > object
The STObject if the parse was successful.
Slice slice() const noexcept
An immutable linear range of bytes.
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
void testBatchNetworkOps(FeatureBitset features)
void validateInnerTxn(jtx::Env &env, std::string const &batchID, TestLedgerData const &ledgerResult)
void testAccountSet(FeatureBitset features)
void testTickets(FeatureBitset features)
void run() override
Runs the suite.
void testAllOrNothing(FeatureBitset features)
void testBatchCalculateBaseFee(FeatureBitset features)
void testObjectCreate3rdParty(FeatureBitset features)
void testAccountActivation(FeatureBitset features)
Json::Value getLastLedger(jtx::Env &env)
void testValidateRPCResponse(FeatureBitset features)
void testObjectCreateTicket(FeatureBitset features)
void testBadRawTxn(FeatureBitset features)
void testPreclaim(FeatureBitset features)
std::pair< std::vector< std::string >, std::string > submitBatch(jtx::Env &env, TER const &result, Args &&... args)
void testBatchTxQueue(FeatureBitset features)
void testBadSequence(FeatureBitset features)
static uint256 getCheckIndex(AccountID const &account, std::uint32_t uSequence)
Json::Value getTxByIndex(Json::Value const &jrr, int const index)
void validateClosedLedger(jtx::Env &env, std::vector< TestLedgerData > const &ledgerResults)
void testObjectCreateSequence(FeatureBitset features)
void testBatchDelegate(FeatureBitset features)
void testOpenLedger(FeatureBitset features)
auto openLedgerFee(jtx::Env &env, XRPAmount const &batchFee)
void testPreflight(FeatureBitset features)
void testUntilFailure(FeatureBitset features)
void testWithFeats(FeatureBitset features)
void testSequenceOpenLedger(FeatureBitset features)
void testTicketsOpenLedger(FeatureBitset features)
void testIndependent(FeatureBitset features)
static std::unique_ptr< Config > makeSmallQueueConfig(std::map< std::string, std::string > extraTxQ={}, std::map< std::string, std::string > extraVoting={})
void testOnlyOne(FeatureBitset features)
void testPseudoTxn(FeatureBitset features)
void testInnerSubmitRPC(FeatureBitset features)
void testEnable(FeatureBitset features)
void testBadOuterFee(FeatureBitset features)
void testObjectsOpenLedger(FeatureBitset features)
void testLoan(FeatureBitset features)
void testCalculateBaseFee(FeatureBitset features)
void testAccountDelete(FeatureBitset features)
Immutable cryptographic account descriptor.
A transaction testing environment.
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
void create(MPTCreate const &arg=MPTCreate{})
Adds a new Batch Txn on a JTx and autofills.
Set a batch nested multi-signature on a JTx.
Set a batch signature on a JTx.
Set a multisignature on a JTx.
Set the regular signature on a JTx.
Set the expected result code for a JTx The test will fail if the code doesn't match.
Set a ticket sequence on a JTx.
@ arrayValue
array value (ordered list)
@ objectValue
object value (collection of name/value pairs).
Keylet loan(uint256 const &loanBrokerID, std::uint32_t loanSeq) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Keylet loanbroker(AccountID const &owner, std::uint32_t seq) noexcept
Json::Value outer(jtx::Account const &account, uint32_t seq, STAmount const &fee, std::uint32_t flags)
Batch.
XRPAmount calcBatchFee(jtx::Env const &env, uint32_t const &numSigners, uint32_t const &txns=0)
Calculate Batch Fee.
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
Json::Value signers(Account const &account, std::uint32_t quorum, std::vector< signer > const &v)
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
FeatureBitset testable_amendments()
std::array< Account, 1+sizeof...(Args)> noripple(Account const &account, Args const &... args)
Designate accounts as no-ripple in Env::fund.
void checkMetrics(Suite &test, jtx::Env &env, std::size_t expectedCount, std::optional< std::size_t > expectedMaxCount, std::size_t expectedInLedger, std::size_t expectedPerLedger, std::uint64_t expectedMinFeeLevel=baseFeeLevel.fee(), std::uint64_t expectedMedFeeLevel=minEscalationFeeLevel.fee(), source_location const location=source_location::current())
void incLgrSeqForAccDel(jtx::Env &env, jtx::Account const &acc, std::uint32_t margin=0)
Json::Value acctdelete(Account const &account, Account const &dest)
Delete account.
XRP_t const XRP
Converts to XRP Issue or STAmount.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
constexpr std::uint32_t tfAllOrNothing
TenthBips< std::uint32_t > TenthBips32
constexpr std::uint32_t tfOnlyOne
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
constexpr std::uint32_t asfRequireDest
constexpr std::uint32_t tfIndependent
void serializeBatch(Serializer &msg, std::uint32_t const &flags, std::vector< uint256 > const &txids)
constexpr std::uint32_t const tfMPTUnlock
bool set(T &target, std::string const &name, Section const §ion)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
constexpr XRPAmount INITIAL_XRP
Configure the native currency.
constexpr std::uint32_t tfImmediateOrCancel
constexpr std::uint32_t asfDisableMaster
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &message)
Generate a signature for a message.
constexpr std::uint32_t tfUntilFailure
std::string strHex(FwdIt begin, FwdIt end)
constexpr std::uint32_t tfSetfAuth
constexpr std::uint32_t tfClearFreeze
constexpr std::uint32_t const tfMPTLock
constexpr std::uint32_t tfDisallowXRP
ApplyResult apply(Application &app, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
constexpr TenthBips32 percentageToTenthBips(std::uint32_t percentage)
TenthBips< std::uint16_t > TenthBips16
bool passesLocalChecks(STObject const &st, std::string &)
std::string to_string(base_uint< Bits, Tag > const &a)
constexpr std::uint32_t asfAllowTrustLineClawback
XRPAmount toDrops(FeeLevel< T > const &level, XRPAmount baseFee)
constexpr std::uint32_t asfRequireAuth
MPTID makeMptID(std::uint32_t sequence, AccountID const &account)
TERSubset< CanCvtToTER > TER
constexpr std::uint32_t const tfLoanImpair
constexpr std::uint32_t tfSetFreeze
constexpr std::uint32_t const tfMPTCanLock
constexpr std::uint32_t tfInnerBatchTxn
std::optional< std::string > batchID
Execution context for applying a JSON transaction.
Set the sequence number on a JTx.