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);
407 auto const seq = env.
seq(alice);
410 tx1[jss::Fee] =
"-1";
420 auto const seq = env.
seq(alice);
423 tx1[jss::Fee] =
"1.5";
429 fail(
"Expected parse_error for fractional fee");
440 auto const seq = env.
seq(alice);
443 tx1[jss::Sequence] =
seq + 1;
454 auto const seq = env.
seq(alice);
465 auto const seq = env.
seq(alice);
476 auto const seq = env.
seq(alice);
487 auto const seq = env.
seq(alice);
500 auto const seq = env.
seq(alice);
522 auto const seq = env.
seq(alice);
534 auto const seq = env.
seq(alice);
547 auto const seq = env.
seq(alice);
559 auto const seq = env.
seq(alice);
571 auto const seq = env.
seq(alice);
572 auto const bobSeq = env.seq(bob);
574 auto jt = env.jtnofill(
583 jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName]
584 [sfAccount.jsonName] = bob.human();
585 jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName]
586 [sfSigningPubKey.jsonName] =
strHex(alice.pk());
587 jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName]
588 [sfTxnSignature.jsonName] =
597 auto const seq = env.
seq(alice);
614 using namespace test::jtx;
622 auto const alice =
Account(
"alice");
623 auto const bob =
Account(
"bob");
624 auto const carol =
Account(
"carol");
625 auto const dave =
Account(
"dave");
626 auto const elsa =
Account(
"elsa");
627 auto const frank =
Account(
"frank");
628 auto const phantom =
Account(
"phantom");
629 env.memoize(phantom);
631 env.fund(
XRP(10000), alice, bob, carol, dave, elsa, frank);
639 auto const seq = env.
seq(alice);
654 auto const seq = env.
seq(alice);
664 env(
signers(alice, 2, {{bob, 1}, {carol, 1}}));
667 env(
signers(bob, 2, {{carol, 1}, {dave, 1}, {elsa, 1}}));
672 auto const seq = env.
seq(alice);
684 auto const seq = env.
seq(alice);
689 batch::msig(bob, {carol, Account(
"dave", KeyType::ed25519)}),
698 auto const seq = env.
seq(alice);
710 auto const seq = env.
seq(alice);
722 auto const seq = env.
seq(alice);
736 auto const seq = env.
seq(alice);
740 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
741 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
742 batch::msig(bob, {carol, Reg{dave, davo}}),
749 auto const seq = env.seq(alice);
752 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
753 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
754 batch::msig(bob, {carol}),
761 auto const seq = env.seq(alice);
764 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
765 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
766 batch::msig(bob, {carol, dave}),
773 auto const seq = env.seq(alice);
776 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
777 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
778 batch::msig(bob, {carol, dave}),
789 auto const ledSeq = env.current()->seq();
790 auto const seq = env.seq(alice);
793 batch::inner(
pay(alice, phantom,
XRP(1000)), seq + 1),
794 batch::inner(
noop(phantom), ledSeq),
795 batch::sig(Reg{phantom, carol}),
802 auto const ledSeq = env.current()->seq();
803 auto const seq = env.seq(alice);
806 batch::inner(
pay(alice, bob,
XRP(1000)), seq + 1),
807 batch::inner(
noop(bob), ledSeq),
808 batch::sig(Reg{bob, carol}),
816 auto const seq = env.seq(alice);
819 batch::inner(
pay(alice, bob,
XRP(1)), seq + 1),
820 batch::inner(
pay(bob, alice,
XRP(2)), env.seq(bob)),
821 batch::sig(Reg{bob, carol}),
828 auto const seq = env.seq(alice);
831 batch::inner(
pay(alice, bob,
XRP(1)), seq + 1),
832 batch::inner(
pay(bob, alice,
XRP(2)), env.seq(bob)),
842 auto const seq = env.seq(alice);
845 batch::inner(
pay(alice, bob,
XRP(1)), seq + 1),
846 batch::inner(
pay(bob, alice,
XRP(2)), env.seq(bob)),
856 testcase(
"bad raw txn");
858 using namespace test::jtx;
863 auto const alice =
Account(
"alice");
864 auto const bob =
Account(
"bob");
866 env.fund(
XRP(10000), alice, bob);
870 auto const batchFee = batch::calcBatchFee(env, 1, 2);
871 auto const seq = env.
seq(alice);
873 tx1.removeMember(jss::TransactionType);
874 auto jt = env.jtnofill(
885 auto const batchFee = batch::calcBatchFee(env, 1, 2);
886 auto const seq = env.
seq(alice);
888 tx1.removeMember(jss::Account);
889 auto jt = env.jtnofill(
900 auto const batchFee = batch::calcBatchFee(env, 1, 2);
901 auto const seq = env.
seq(alice);
903 tx1.removeMember(jss::Sequence);
904 auto jt = env.jtnofill(
915 auto const batchFee = batch::calcBatchFee(env, 1, 2);
916 auto const seq = env.
seq(alice);
918 tx1.removeMember(jss::Fee);
919 auto jt = env.jtnofill(
930 auto const batchFee = batch::calcBatchFee(env, 1, 2);
931 auto const seq = env.
seq(alice);
933 tx1.removeMember(jss::SigningPubKey);
934 auto jt = env.jtnofill(
947 testcase(
"bad sequence");
949 using namespace test::jtx;
954 auto const alice =
Account(
"alice");
955 auto const bob =
Account(
"bob");
957 auto const USD = gw[
"USD"];
959 env.fund(
XRP(10000), alice, bob, gw);
961 env.trust(USD(1000), alice, bob);
962 env(pay(gw, alice, USD(100)));
963 env(pay(gw, bob, USD(100)));
971 auto const preAliceSeq = env.seq(alice);
972 auto const preAlice = env.balance(alice);
973 auto const preAliceUSD = env.balance(alice, USD.issue());
974 auto const preBobSeq = env.seq(bob);
975 auto const preBob = env.balance(bob);
976 auto const preBobUSD = env.balance(bob, USD.issue());
978 auto const batchFee = batch::calcBatchFee(env, 1, 2);
979 auto const [txIDs, batchID] = submitBatch(
992 validateClosedLedger(env, testCases);
999 validateClosedLedger(env, testCases);
1003 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1004 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1005 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1006 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1007 BEAST_EXPECT(env.balance(bob) == preBob);
1008 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1013 auto const preAliceSeq = env.seq(alice);
1014 auto const preAlice = env.balance(alice);
1015 auto const preAliceUSD = env.balance(alice, USD.issue());
1016 auto const preBobSeq = env.seq(bob);
1017 auto const preBob = env.balance(bob);
1018 auto const preBobUSD = env.balance(bob, USD.issue());
1020 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1021 auto const [txIDs, batchID] = submitBatch(
1034 validateClosedLedger(env, testCases);
1041 validateClosedLedger(env, testCases);
1045 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1046 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1047 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1048 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1049 BEAST_EXPECT(env.balance(bob) == preBob);
1050 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1055 auto const preAliceSeq = env.seq(alice);
1056 auto const preAlice = env.balance(alice);
1057 auto const preAliceUSD = env.balance(alice, USD.issue());
1058 auto const preBobSeq = env.seq(bob);
1059 auto const preBob = env.balance(bob);
1060 auto const preBobUSD = env.balance(bob, USD.issue());
1062 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1063 auto const [txIDs, batchID] = submitBatch(
1076 validateClosedLedger(env, testCases);
1083 validateClosedLedger(env, testCases);
1087 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1088 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1089 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1090 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1091 BEAST_EXPECT(env.balance(bob) == preBob);
1092 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1097 auto const preAliceSeq = env.seq(alice);
1098 auto const preAlice = env.balance(alice);
1099 auto const preAliceUSD = env.balance(alice, USD.issue());
1100 auto const preBobSeq = env.seq(bob);
1101 auto const preBob = env.balance(bob);
1102 auto const preBobUSD = env.balance(bob, USD.issue());
1104 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1105 auto const [txIDs, batchID] = submitBatch(
1118 validateClosedLedger(env, testCases);
1125 validateClosedLedger(env, testCases);
1129 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1130 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1131 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1132 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1133 BEAST_EXPECT(env.balance(bob) == preBob);
1134 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1139 auto const preAliceSeq = env.seq(alice);
1140 auto const preAlice = env.balance(alice);
1141 auto const preAliceUSD = env.balance(alice, USD.issue());
1142 auto const preBobSeq = env.seq(bob);
1143 auto const preBob = env.balance(bob);
1144 auto const preBobUSD = env.balance(bob, USD.issue());
1146 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1147 auto const [txIDs, batchID] = submitBatch(
1160 validateClosedLedger(env, testCases);
1167 validateClosedLedger(env, testCases);
1171 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1172 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1173 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1174 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1175 BEAST_EXPECT(env.balance(bob) == preBob);
1176 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1183 testcase(
"bad outer fee");
1185 using namespace test::jtx;
1192 auto const alice =
Account(
"alice");
1193 auto const bob =
Account(
"bob");
1194 env.fund(
XRP(10000), alice, bob);
1201 auto const batchFee = batch::calcBatchFee(env, 0, 1);
1202 auto const aliceSeq = env.seq(alice);
1214 auto const alice =
Account(
"alice");
1215 auto const bob =
Account(
"bob");
1216 auto const carol =
Account(
"carol");
1217 env.fund(
XRP(10000), alice, bob, carol);
1223 env(signers(alice, 2, {{bob, 1}, {carol, 1}}));
1227 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1228 auto const aliceSeq = env.seq(alice);
1241 auto const alice =
Account(
"alice");
1242 auto const bob =
Account(
"bob");
1243 auto const carol =
Account(
"carol");
1244 env.fund(
XRP(10000), alice, bob, carol);
1250 env(signers(alice, 2, {{bob, 1}, {carol, 1}}));
1254 auto const batchFee = batch::calcBatchFee(env, 2, 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 auto const carol =
Account(
"carol");
1273 env.fund(
XRP(10000), alice, bob, carol);
1279 env(signers(alice, 2, {{bob, 1}, {carol, 1}}));
1282 env(signers(bob, 2, {{alice, 1}, {carol, 1}}));
1286 auto const batchFee = batch::calcBatchFee(env, 3, 2);
1287 auto const aliceSeq = env.seq(alice);
1288 auto const bobSeq = env.seq(bob);
1302 auto const alice =
Account(
"alice");
1303 auto const bob =
Account(
"bob");
1304 env.fund(
XRP(10000), alice, bob);
1311 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1312 auto const aliceSeq = env.seq(alice);
1313 auto const bobSeq = env.seq(bob);
1326 auto const alice =
Account(
"alice");
1327 auto const bob =
Account(
"bob");
1328 auto const gw =
Account(
"gw");
1329 auto const USD = gw[
"USD"];
1331 env.fund(
XRP(10000), alice, bob, gw);
1333 auto const ammCreate =
1336 jv[jss::Account] = alice.human();
1339 jv[jss::TradingFee] = 0;
1340 jv[jss::TransactionType] = jss::AMMCreate;
1344 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1345 auto const seq = env.
seq(alice);
1357 testcase(
"calculate base fee");
1359 using namespace test::jtx;
1366 auto const alice =
Account(
"alice");
1367 auto const bob =
Account(
"bob");
1368 env.fund(
XRP(10000), alice, bob);
1371 auto const batchFee = batch::calcBatchFee(env, 0, 9);
1372 auto const aliceSeq = env.seq(alice);
1391 auto const alice =
Account(
"alice");
1392 auto const bob =
Account(
"bob");
1393 env.fund(
XRP(10000), alice, bob);
1396 auto const batchFee = batch::calcBatchFee(env, 0, 9);
1397 auto const aliceSeq = env.seq(alice);
1398 auto jt = env.jtnofill(
1410 env.app().openLedger().modify(
1416 return result.applied;
1424 auto const alice =
Account(
"alice");
1425 auto const bob =
Account(
"bob");
1426 env.fund(
XRP(10000), alice, bob);
1429 auto const aliceSeq = env.seq(alice);
1430 auto const batchFee = batch::calcBatchFee(env, 9, 2);
1434 batch::sig(bob, bob, bob, bob, bob, bob, bob, bob, bob, bob),
1443 auto const alice =
Account(
"alice");
1444 auto const bob =
Account(
"bob");
1445 env.fund(
XRP(10000), alice, bob);
1448 auto const batchFee = batch::calcBatchFee(env, 0, 9);
1449 auto const aliceSeq = env.seq(alice);
1450 auto jt = env.jtnofill(
1454 batch::sig(bob, bob, bob, bob, bob, bob, bob, bob, bob, bob));
1456 env.app().openLedger().modify(
1462 return result.applied;
1470 testcase(
"all or nothing");
1472 using namespace test::jtx;
1477 auto const alice =
Account(
"alice");
1478 auto const bob =
Account(
"bob");
1479 auto const gw =
Account(
"gw");
1480 auto const USD = gw[
"USD"];
1481 env.fund(
XRP(10000), alice, bob, gw);
1486 auto const preAlice = env.balance(alice);
1487 auto const preBob = env.balance(bob);
1489 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1490 auto const seq = env.
seq(alice);
1491 auto const [txIDs, batchID] = submitBatch(
1501 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1502 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1504 validateClosedLedger(env, testCases);
1507 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1510 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1511 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1516 auto const preAlice = env.balance(alice);
1517 auto const preBob = env.balance(bob);
1519 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1520 auto const seq = env.
seq(alice);
1522 auto const [txIDs, batchID] = submitBatch(
1534 validateClosedLedger(env, testCases);
1537 BEAST_EXPECT(env.seq(alice) ==
seq + 1);
1540 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1541 BEAST_EXPECT(env.balance(bob) == preBob);
1546 auto const preAlice = env.balance(alice);
1547 auto const preBob = env.balance(bob);
1549 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1550 auto const seq = env.
seq(alice);
1551 auto const [txIDs, batchID] = submitBatch(
1563 validateClosedLedger(env, testCases);
1566 BEAST_EXPECT(env.seq(alice) ==
seq + 1);
1569 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1570 BEAST_EXPECT(env.balance(bob) == preBob);
1575 auto const preAlice = env.balance(alice);
1576 auto const preBob = env.balance(bob);
1578 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1579 auto const seq = env.
seq(alice);
1580 auto const [txIDs, batchID] = submitBatch(
1592 validateClosedLedger(env, testCases);
1595 BEAST_EXPECT(env.seq(alice) ==
seq + 1);
1598 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1599 BEAST_EXPECT(env.balance(bob) == preBob);
1606 testcase(
"only one");
1608 using namespace test::jtx;
1613 auto const alice =
Account(
"alice");
1614 auto const bob =
Account(
"bob");
1615 auto const carol =
Account(
"carol");
1616 auto const dave =
Account(
"dave");
1617 auto const gw =
Account(
"gw");
1618 auto const USD = gw[
"USD"];
1619 env.fund(
XRP(10000), alice, bob, carol, dave, gw);
1624 auto const preAlice = env.balance(alice);
1625 auto const preBob = env.balance(bob);
1627 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1628 auto const seq = env.
seq(alice);
1629 auto const [txIDs, batchID] = submitBatch(
1643 {1,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[0], batchID},
1644 {2,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[1], batchID},
1645 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
1647 validateClosedLedger(env, testCases);
1650 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
1653 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1654 BEAST_EXPECT(env.balance(bob) == preBob);
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",
"tecUNFUNDED_PAYMENT", txIDs[0], batchID},
1677 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1679 validateClosedLedger(env, testCases);
1682 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1685 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
1686 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1691 auto const preAlice = env.balance(alice);
1692 auto const preBob = env.balance(bob);
1694 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1695 auto const seq = env.
seq(alice);
1696 auto const [txIDs, batchID] = submitBatch(
1708 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1710 validateClosedLedger(env, testCases);
1713 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1716 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
1717 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1722 auto const preAlice = env.balance(alice);
1723 auto const preBob = env.balance(bob);
1725 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1726 auto const seq = env.
seq(alice);
1727 auto const [txIDs, batchID] = submitBatch(
1739 {1,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1741 validateClosedLedger(env, testCases);
1744 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1747 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(1));
1748 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1753 auto const preAlice = env.balance(alice);
1754 auto const preBob = env.balance(bob);
1756 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1757 auto const seq = env.
seq(alice);
1758 auto const [txIDs, batchID] = submitBatch(
1770 {1,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1772 validateClosedLedger(env, testCases);
1775 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1778 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(1));
1779 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1784 auto const preAlice = env.balance(alice);
1785 auto const preBob = env.balance(bob);
1786 auto const preCarol = env.balance(carol);
1787 auto const seq = env.
seq(alice);
1788 auto const batchFee = batch::calcBatchFee(env, 0, 6);
1790 auto const [txIDs, batchID] = submitBatch(
1822 {1,
"OfferCreate",
"tecKILLED", txIDs[0], batchID},
1823 {2,
"OfferCreate",
"tecKILLED", txIDs[1], batchID},
1824 {3,
"OfferCreate",
"tecKILLED", txIDs[2], batchID},
1825 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
1827 validateClosedLedger(env, testCases);
1829 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(100) - batchFee);
1830 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(100));
1831 BEAST_EXPECT(env.balance(carol) == preCarol);
1838 testcase(
"until failure");
1840 using namespace test::jtx;
1845 auto const alice =
Account(
"alice");
1846 auto const bob =
Account(
"bob");
1847 auto const carol =
Account(
"carol");
1848 auto const dave =
Account(
"dave");
1849 auto const gw =
Account(
"gw");
1850 auto const USD = gw[
"USD"];
1851 env.fund(
XRP(10000), alice, bob, carol, dave, gw);
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(
1874 {1,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[0], batchID},
1876 validateClosedLedger(env, testCases);
1879 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1882 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1883 BEAST_EXPECT(env.balance(bob) == preBob);
1888 auto const preAlice = env.balance(alice);
1889 auto const preBob = env.balance(bob);
1891 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1892 auto const seq = env.
seq(alice);
1893 auto const [txIDs, batchID] = submitBatch(
1905 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1906 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1907 {3,
"Payment",
"tesSUCCESS", txIDs[2], batchID},
1908 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
1910 validateClosedLedger(env, testCases);
1913 BEAST_EXPECT(env.seq(alice) ==
seq + 5);
1916 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(10) - batchFee);
1917 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(10));
1922 auto const preAlice = env.balance(alice);
1923 auto const preBob = env.balance(bob);
1925 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1926 auto const seq = env.
seq(alice);
1927 auto const [txIDs, batchID] = submitBatch(
1940 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1941 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1942 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
1944 validateClosedLedger(env, testCases);
1947 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
1950 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1951 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1956 auto const preAlice = env.balance(alice);
1957 auto const preBob = env.balance(bob);
1959 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1960 auto const seq = env.
seq(alice);
1961 auto const [txIDs, batchID] = submitBatch(
1974 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1975 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1977 validateClosedLedger(env, testCases);
1980 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1983 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1984 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1989 auto const preAlice = env.balance(alice);
1990 auto const preBob = env.balance(bob);
1992 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1993 auto const seq = env.
seq(alice);
1994 auto const [txIDs, batchID] = submitBatch(
2007 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2008 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2010 validateClosedLedger(env, testCases);
2013 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
2016 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
2017 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
2022 auto const preAlice = env.balance(alice);
2023 auto const preBob = env.balance(bob);
2024 auto const preCarol = env.balance(carol);
2025 auto const seq = env.
seq(alice);
2026 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2027 auto const [txIDs, batchID] = submitBatch(
2045 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2046 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2047 {3,
"OfferCreate",
"tecKILLED", txIDs[2], batchID},
2049 validateClosedLedger(env, testCases);
2051 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(200) - batchFee);
2052 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(100));
2053 BEAST_EXPECT(env.balance(carol) == preCarol +
XRP(100));
2060 testcase(
"independent");
2062 using namespace test::jtx;
2067 auto const alice =
Account(
"alice");
2068 auto const bob =
Account(
"bob");
2069 auto const carol =
Account(
"carol");
2070 auto const gw =
Account(
"gw");
2071 auto const USD = gw[
"USD"];
2072 env.fund(
XRP(10000), alice, bob, carol, gw);
2077 auto const preAlice = env.balance(alice);
2078 auto const preBob = env.balance(bob);
2080 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2081 auto const seq = env.
seq(alice);
2082 auto const [txIDs, batchID] = submitBatch(
2096 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2097 {2,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[1], batchID},
2098 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
2099 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2101 validateClosedLedger(env, testCases);
2104 BEAST_EXPECT(env.seq(alice) ==
seq + 5);
2107 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(4) - batchFee);
2108 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(4));
2113 auto const preAlice = env.balance(alice);
2114 auto const preBob = env.balance(bob);
2116 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2117 auto const seq = env.
seq(alice);
2118 auto const [txIDs, batchID] = submitBatch(
2131 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2132 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2133 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
2134 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2136 validateClosedLedger(env, testCases);
2139 BEAST_EXPECT(env.seq(alice) ==
seq + 5);
2142 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(6) - batchFee);
2143 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(6));
2148 auto const preAlice = env.balance(alice);
2149 auto const preBob = env.balance(bob);
2151 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2152 auto const seq = env.
seq(alice);
2153 auto const [txIDs, batchID] = submitBatch(
2166 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2167 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2168 {3,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2170 validateClosedLedger(env, testCases);
2173 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
2176 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(6));
2177 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(6));
2182 auto const preAlice = env.balance(alice);
2183 auto const preBob = env.balance(bob);
2185 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2186 auto const seq = env.
seq(alice);
2187 auto const [txIDs, batchID] = submitBatch(
2200 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2201 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2202 {3,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2204 validateClosedLedger(env, testCases);
2207 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
2210 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(6));
2211 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(6));
2216 auto const preAlice = env.balance(alice);
2217 auto const preBob = env.balance(bob);
2218 auto const preCarol = env.balance(carol);
2219 auto const seq = env.
seq(alice);
2220 auto const batchFee = batch::calcBatchFee(env, 0, 3);
2221 auto const [txIDs, batchID] = submitBatch(
2238 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2239 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2240 {3,
"OfferCreate",
"tecKILLED", txIDs[2], batchID},
2242 validateClosedLedger(env, testCases);
2244 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(200) - batchFee);
2245 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(100));
2246 BEAST_EXPECT(env.balance(carol) == preCarol +
XRP(100));
2253 testcase(
"inner submit rpc");
2255 using namespace test::jtx;
2260 auto const alice =
Account(
"alice");
2261 auto const bob =
Account(
"bob");
2263 env.fund(
XRP(10000), alice, bob);
2266 auto submitAndValidate = [&](
Slice const&
slice) {
2267 auto const jrr = env.rpc(
"submit",
strHex(
slice))[jss::result];
2269 jrr[jss::status] ==
"error" &&
2270 jrr[jss::error] ==
"invalidTransaction" &&
2271 jrr[jss::error_exception] ==
2272 "fails local checks: Malformed: Invalid inner batch "
2284 txn[sfTxnSignature] =
"DEADBEEF";
2288 submitAndValidate(s.
slice());
2298 txn[sfSigningPubKey] =
strHex(alice.pk());
2302 submitAndValidate(s.
slice());
2316 submitAndValidate(s.
slice());
2329 auto const jrr = env.rpc(
"submit",
strHex(s.
slice()))[jss::result];
2331 jrr[jss::status] ==
"success" &&
2332 jrr[jss::engine_result] ==
"temINVALID_FLAG");
2341 testcase(
"account activation");
2343 using namespace test::jtx;
2348 auto const alice =
Account(
"alice");
2349 auto const bob =
Account(
"bob");
2350 env.fund(
XRP(10000), alice);
2354 auto const preAlice = env.balance(alice);
2355 auto const ledSeq = env.current()->seq();
2356 auto const seq = env.
seq(alice);
2357 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2358 auto const [txIDs, batchID] = submitBatch(
2369 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2370 {2,
"AccountSet",
"tesSUCCESS", txIDs[1], batchID},
2372 validateClosedLedger(env, testCases);
2375 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
2378 BEAST_EXPECT(env.seq(bob) == ledSeq + 1);
2381 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1000) - batchFee);
2382 BEAST_EXPECT(env.balance(bob) ==
XRP(1000));
2388 testcase(
"account set");
2390 using namespace test::jtx;
2395 auto const alice =
Account(
"alice");
2396 auto const bob =
Account(
"bob");
2397 env.fund(
XRP(10000), alice, bob);
2400 auto const preAlice = env.balance(alice);
2401 auto const preBob = env.balance(bob);
2403 auto const seq = env.
seq(alice);
2404 auto const batchFee = batch::calcBatchFee(env, 0, 2);
2408 auto const [txIDs, batchID] = submitBatch(
2418 {1,
"AccountSet",
"tesSUCCESS", txIDs[0], batchID},
2419 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2421 validateClosedLedger(env, testCases);
2429 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
2432 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
2433 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
2439 testcase(
"account delete");
2441 using namespace test::jtx;
2448 auto const alice =
Account(
"alice");
2449 auto const bob =
Account(
"bob");
2450 env.fund(
XRP(10000), alice, bob);
2454 for (
int i = 0; i < 5; ++i)
2457 auto const preAlice = env.balance(alice);
2458 auto const preBob = env.balance(bob);
2460 auto const seq = env.
seq(alice);
2461 auto const batchFee = batch::calcBatchFee(env, 0, 2) +
2462 env.current()->fees().increment;
2463 auto const [txIDs, batchID] = submitBatch(
2475 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2476 {2,
"AccountDelete",
"tesSUCCESS", txIDs[1], batchID},
2478 validateClosedLedger(env, testCases);
2482 BEAST_EXPECT(env.balance(bob) == preBob + (preAlice - batchFee));
2489 auto const alice =
Account(
"alice");
2490 auto const bob =
Account(
"bob");
2491 env.fund(
XRP(10000), alice, bob);
2495 for (
int i = 0; i < 5; ++i)
2498 auto const preAlice = env.balance(alice);
2499 auto const preBob = env.balance(bob);
2501 env.trust(bob[
"USD"](1000), alice);
2504 auto const seq = env.
seq(alice);
2505 auto const batchFee = batch::calcBatchFee(env, 0, 2) +
2506 env.current()->fees().increment;
2507 auto const [txIDs, batchID] = submitBatch(
2519 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2520 {2,
"AccountDelete",
"tecHAS_OBLIGATIONS", txIDs[1], batchID},
2521 {3,
"Payment",
"tesSUCCESS", txIDs[2], batchID},
2523 validateClosedLedger(env, testCases);
2527 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
2534 auto const alice =
Account(
"alice");
2535 auto const bob =
Account(
"bob");
2536 env.fund(
XRP(10000), alice, bob);
2540 for (
int i = 0; i < 5; ++i)
2543 auto const preAlice = env.balance(alice);
2544 auto const preBob = env.balance(bob);
2546 auto const seq = env.
seq(alice);
2547 auto const batchFee = batch::calcBatchFee(env, 0, 2) +
2548 env.current()->fees().increment;
2549 auto const [txIDs, batchID] = submitBatch(
2562 validateClosedLedger(env, testCases);
2566 BEAST_EXPECT(env.balance(bob) == preBob);
2578 [](
auto const& disabled) {
return disabled == ttLOAN_BROKER_SET; });
2580 using namespace test::jtx;
2585 features | featureSingleAssetVault | featureLendingProtocol |
2588 Account const issuer{
"issuer"};
2591 Account const lender{
"lender"};
2593 Account const borrower{
"borrower"};
2597 env.fund(
XRP(100'000), issuer,
noripple(lender, borrower));
2605 auto const deposit = asset(50'000);
2606 auto const debtMaximumValue = asset(25'000).value();
2607 auto const coverDepositValue = asset(1000).value();
2609 auto [tx, vaultKeylet] =
2610 vault.create({.owner = lender, .asset = asset});
2613 BEAST_EXPECT(env.le(vaultKeylet));
2616 {.depositor = lender, .id = vaultKeylet.key, .amount = deposit}));
2619 auto const brokerKeylet =
2623 using namespace loanBroker;
2624 env(
set(lender, vaultKeylet.key),
2626 debtMaximum(debtMaximumValue),
2630 env(coverDeposit(lender, brokerKeylet.key, coverDepositValue));
2636 using namespace loan;
2637 using namespace std::chrono_literals;
2639 auto const lenderSeq = env.seq(lender);
2640 auto const batchFee = batch::calcBatchFee(env, 0, 2);
2642 auto const loanKeylet =
keylet::loan(brokerKeylet.key, 1);
2644 auto const [txIDs, batchID] = submitBatch(
2651 set(lender, brokerKeylet.key, asset(1000).value()),
2653 sig(sfCounterpartySignature, borrower),
2661 STAmount{asset, asset(500).value()}),
2665 auto const [txIDs, batchID] = submitBatch(
2671 set(lender, brokerKeylet.key, asset(1000).value()),
2680 STAmount{asset, asset(500).value()}),
2684 auto const [txIDs, batchID] = submitBatch(
2691 set(lender, brokerKeylet.key, asset(1000).value()),
2693 counterparty(borrower.id()),
2701 STAmount{asset, asset(500).value()}),
2708 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2709 auto const [txIDs, batchID] = submitBatch(
2716 set(lender, brokerKeylet.key, asset(1000).value()),
2717 counterparty(borrower.id()),
2729 STAmount{asset, asset(500).value()}),
2734 BEAST_EXPECT(env.le(brokerKeylet));
2735 BEAST_EXPECT(!env.le(loanKeylet));
2740 auto const lenderSeq = env.seq(lender);
2741 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2742 auto const [txIDs, batchID] = submitBatch(
2749 set(lender, brokerKeylet.key, asset(1000).value()),
2750 counterparty(borrower.id()),
2761 BEAST_EXPECT(env.le(brokerKeylet));
2762 if (
auto const sleLoan = env.le(loanKeylet); lendingBatchEnabled
2763 ? BEAST_EXPECT(sleLoan)
2764 : !BEAST_EXPECT(!sleLoan))
2774 testcase(
"object create w/ sequence");
2776 using namespace test::jtx;
2781 auto const alice =
Account(
"alice");
2782 auto const bob =
Account(
"bob");
2783 auto const gw =
Account(
"gw");
2784 auto const USD = gw[
"USD"];
2786 env.fund(
XRP(10000), alice, bob, gw);
2789 env.trust(USD(1000), alice, bob);
2790 env(pay(gw, alice, USD(100)));
2791 env(pay(gw, bob, USD(100)));
2796 auto const aliceSeq = env.seq(alice);
2797 auto const bobSeq = env.seq(bob);
2798 auto const preAlice = env.balance(alice);
2799 auto const preBob = env.balance(bob);
2800 auto const preAliceUSD = env.balance(alice, USD.issue());
2801 auto const preBobUSD = env.balance(bob, USD.issue());
2803 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2804 uint256 const chkID{getCheckIndex(bob, env.seq(bob))};
2805 auto const [txIDs, batchID] = submitBatch(
2809 batch::inner(check::create(bob, alice, USD(10)), bobSeq),
2810 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq + 1),
2816 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
2817 {2,
"CheckCash",
"tesSUCCESS", txIDs[1], batchID},
2819 validateClosedLedger(env, testCases);
2822 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
2825 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
2828 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
2829 BEAST_EXPECT(env.balance(bob) == preBob);
2833 env.balance(alice, USD.issue()) == preAliceUSD + USD(10));
2834 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10));
2842 auto const aliceSeq = env.seq(alice);
2843 auto const bobSeq = env.seq(bob);
2844 auto const preAlice = env.balance(alice);
2845 auto const preBob = env.balance(bob);
2846 auto const preAliceUSD = env.balance(alice, USD.issue());
2847 auto const preBobUSD = env.balance(bob, USD.issue());
2849 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2850 uint256 const chkID{getCheckIndex(bob, env.seq(bob))};
2851 auto const [txIDs, batchID] = submitBatch(
2856 batch::inner(check::create(bob, alice, USD(10)), bobSeq),
2857 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq + 1),
2863 {1,
"CheckCreate",
"tecDST_TAG_NEEDED", txIDs[0], batchID},
2864 {2,
"CheckCash",
"tecNO_ENTRY", txIDs[1], batchID},
2866 validateClosedLedger(env, testCases);
2869 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
2872 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
2875 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
2876 BEAST_EXPECT(env.balance(bob) == preBob);
2879 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
2880 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
2887 testcase(
"object create w/ ticket");
2889 using namespace test::jtx;
2894 auto const alice =
Account(
"alice");
2895 auto const bob =
Account(
"bob");
2896 auto const gw =
Account(
"gw");
2897 auto const USD = gw[
"USD"];
2899 env.fund(
XRP(10000), alice, bob, gw);
2902 env.trust(USD(1000), alice, bob);
2903 env(pay(gw, alice, USD(100)));
2904 env(pay(gw, bob, USD(100)));
2907 auto const aliceSeq = env.seq(alice);
2908 auto const bobSeq = env.seq(bob);
2909 auto const preAlice = env.balance(alice);
2910 auto const preBob = env.balance(bob);
2911 auto const preAliceUSD = env.balance(alice, USD.issue());
2912 auto const preBobUSD = env.balance(bob, USD.issue());
2914 auto const batchFee = batch::calcBatchFee(env, 1, 3);
2915 uint256 const chkID{getCheckIndex(bob, bobSeq + 1)};
2916 auto const [txIDs, batchID] = submitBatch(
2921 batch::inner(check::create(bob, alice, USD(10)), 0, bobSeq + 1),
2922 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq + 1),
2928 {1,
"TicketCreate",
"tesSUCCESS", txIDs[0], batchID},
2929 {2,
"CheckCreate",
"tesSUCCESS", txIDs[1], batchID},
2930 {3,
"CheckCash",
"tesSUCCESS", txIDs[2], batchID},
2932 validateClosedLedger(env, testCases);
2934 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
2935 BEAST_EXPECT(env.seq(bob) == bobSeq + 10 + 1);
2936 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
2937 BEAST_EXPECT(env.balance(bob) == preBob);
2938 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD + USD(10));
2939 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10));
2945 testcase(
"object create w/ 3rd party");
2947 using namespace test::jtx;
2952 auto const alice =
Account(
"alice");
2953 auto const bob =
Account(
"bob");
2954 auto const carol =
Account(
"carol");
2955 auto const gw =
Account(
"gw");
2956 auto const USD = gw[
"USD"];
2958 env.fund(
XRP(10000), alice, bob, carol, gw);
2961 env.trust(USD(1000), alice, bob);
2962 env(pay(gw, alice, USD(100)));
2963 env(pay(gw, bob, USD(100)));
2966 auto const aliceSeq = env.seq(alice);
2967 auto const bobSeq = env.seq(bob);
2968 auto const carolSeq = env.seq(carol);
2969 auto const preAlice = env.balance(alice);
2970 auto const preBob = env.balance(bob);
2971 auto const preCarol = env.balance(carol);
2972 auto const preAliceUSD = env.balance(alice, USD.issue());
2973 auto const preBobUSD = env.balance(bob, USD.issue());
2975 auto const batchFee = batch::calcBatchFee(env, 2, 2);
2976 uint256 const chkID{getCheckIndex(bob, env.seq(bob))};
2977 auto const [txIDs, batchID] = submitBatch(
2981 batch::inner(check::create(bob, alice, USD(10)), bobSeq),
2982 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq),
2988 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
2989 {2,
"CheckCash",
"tesSUCCESS", txIDs[1], batchID},
2991 validateClosedLedger(env, testCases);
2993 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
2994 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
2995 BEAST_EXPECT(env.seq(carol) == carolSeq + 1);
2996 BEAST_EXPECT(env.balance(alice) == preAlice);
2997 BEAST_EXPECT(env.balance(bob) == preBob);
2998 BEAST_EXPECT(env.balance(carol) == preCarol - batchFee);
2999 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD + USD(10));
3000 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10));
3007 testcase(
"tickets outer");
3009 using namespace test::jtx;
3014 auto const alice =
Account(
"alice");
3015 auto const bob =
Account(
"bob");
3017 env.fund(
XRP(10000), alice, bob);
3021 env(ticket::create(alice, 10));
3024 auto const aliceSeq = env.seq(alice);
3025 auto const preAlice = env.balance(alice);
3026 auto const preBob = env.balance(bob);
3028 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3029 auto const [txIDs, batchID] = submitBatch(
3040 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3041 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3043 validateClosedLedger(env, testCases);
3047 BEAST_EXPECT(sle->getFieldU32(sfOwnerCount) == 9);
3048 BEAST_EXPECT(sle->getFieldU32(sfTicketCount) == 9);
3050 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
3051 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3052 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3056 testcase(
"tickets inner");
3058 using namespace test::jtx;
3063 auto const alice =
Account(
"alice");
3064 auto const bob =
Account(
"bob");
3066 env.fund(
XRP(10000), alice, bob);
3070 env(ticket::create(alice, 10));
3073 auto const aliceSeq = env.seq(alice);
3074 auto const preAlice = env.balance(alice);
3075 auto const preBob = env.balance(bob);
3077 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3078 auto const [txIDs, batchID] = submitBatch(
3088 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3089 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3091 validateClosedLedger(env, testCases);
3095 BEAST_EXPECT(sle->getFieldU32(sfOwnerCount) == 8);
3096 BEAST_EXPECT(sle->getFieldU32(sfTicketCount) == 8);
3098 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
3099 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3100 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3104 testcase(
"tickets outer inner");
3106 using namespace test::jtx;
3111 auto const alice =
Account(
"alice");
3112 auto const bob =
Account(
"bob");
3114 env.fund(
XRP(10000), alice, bob);
3118 env(ticket::create(alice, 10));
3121 auto const aliceSeq = env.seq(alice);
3122 auto const preAlice = env.balance(alice);
3123 auto const preBob = env.balance(bob);
3125 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3126 auto const [txIDs, batchID] = submitBatch(
3137 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3138 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3140 validateClosedLedger(env, testCases);
3144 BEAST_EXPECT(sle->getFieldU32(sfOwnerCount) == 8);
3145 BEAST_EXPECT(sle->getFieldU32(sfTicketCount) == 8);
3147 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
3148 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3149 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3156 testcase(
"sequence open ledger");
3158 using namespace test::jtx;
3161 auto const alice =
Account(
"alice");
3162 auto const bob =
Account(
"bob");
3163 auto const carol =
Account(
"carol");
3173 env.fund(
XRP(10000), alice, bob, carol);
3176 auto const aliceSeq = env.seq(alice);
3177 auto const carolSeq = env.seq(carol);
3180 auto const noopTxn = env.jt(
noop(alice),
seq(aliceSeq + 2));
3181 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3185 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3186 auto const [txIDs, batchID] = submitBatch(
3198 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3199 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3201 validateClosedLedger(env, testCases);
3208 {0,
"AccountSet",
"tesSUCCESS", noopTxnID,
std::nullopt},
3210 validateClosedLedger(env, testCases);
3220 env.fund(
XRP(10000), alice, bob);
3223 auto const aliceSeq = env.seq(alice);
3226 auto const noopTxn = env.jt(
noop(alice),
seq(aliceSeq + 1));
3230 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3231 auto const [txIDs, batchID] = submitBatch(
3242 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3243 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3245 validateClosedLedger(env, testCases);
3252 validateClosedLedger(env, testCases);
3262 env.fund(
XRP(10000), alice, bob);
3265 auto const aliceSeq = env.seq(alice);
3266 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3267 auto const [txIDs, batchID] = submitBatch(
3274 auto const noopTxn = env.jt(
noop(alice),
seq(aliceSeq + 1));
3275 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3282 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3283 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3285 validateClosedLedger(env, testCases);
3292 validateClosedLedger(env, testCases);
3299 env.fund(
XRP(10000), alice, bob, carol);
3302 auto const aliceSeq = env.seq(alice);
3303 auto const carolSeq = env.seq(carol);
3306 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3307 auto const [txIDs, batchID] = submitBatch(
3316 auto const noopTxn = env.jt(
noop(carol),
seq(carolSeq));
3317 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3323 {0,
"AccountSet",
"tesSUCCESS", noopTxnID,
std::nullopt},
3325 {2,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3326 {3,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3328 validateClosedLedger(env, testCases);
3335 validateClosedLedger(env, testCases);
3343 testcase(
"tickets open ledger");
3345 using namespace test::jtx;
3348 auto const alice =
Account(
"alice");
3349 auto const bob =
Account(
"bob");
3357 env.fund(
XRP(10000), alice, bob);
3361 env(ticket::create(alice, 10));
3364 auto const aliceSeq = env.seq(alice);
3367 auto const noopTxn =
3369 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3373 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3374 auto const [txIDs, batchID] = submitBatch(
3386 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3387 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3389 validateClosedLedger(env, testCases);
3396 validateClosedLedger(env, testCases);
3406 env.fund(
XRP(10000), alice, bob);
3410 env(ticket::create(alice, 10));
3413 auto const aliceSeq = env.seq(alice);
3416 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3417 auto const [txIDs, batchID] = submitBatch(
3426 auto const noopTxn =
3434 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3435 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3437 validateClosedLedger(env, testCases);
3444 validateClosedLedger(env, testCases);
3452 testcase(
"objects open ledger");
3454 using namespace test::jtx;
3457 auto const alice =
Account(
"alice");
3458 auto const bob =
Account(
"bob");
3468 env.fund(
XRP(10000), alice, bob);
3472 env(ticket::create(alice, 10));
3475 auto const aliceSeq = env.seq(alice);
3478 uint256 const chkID{getCheckIndex(alice, aliceSeq)};
3479 auto const objTxn = env.jt(check::cash(bob, chkID,
XRP(10)));
3480 auto const objTxnID =
to_string(objTxn.stx->getTransactionID());
3484 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3485 auto const [txIDs, batchID] = submitBatch(
3497 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
3498 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3499 {3,
"CheckCash",
"tesSUCCESS", objTxnID,
std::nullopt},
3501 validateClosedLedger(env, testCases);
3508 validateClosedLedger(env, testCases);
3515 env.fund(
XRP(10000), alice, bob);
3519 env(ticket::create(alice, 10));
3522 auto const aliceSeq = env.seq(alice);
3523 auto const bobSeq = env.seq(bob);
3526 uint256 const chkID{getCheckIndex(alice, aliceSeq)};
3527 auto const objTxn = env.jt(check::create(alice, bob,
XRP(10)));
3528 auto const objTxnID =
to_string(objTxn.stx->getTransactionID());
3532 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3533 auto const [txIDs, batchID] = submitBatch(
3545 {0,
"CheckCreate",
"tesSUCCESS", objTxnID,
std::nullopt},
3547 {2,
"CheckCash",
"tesSUCCESS", txIDs[0], batchID},
3548 {3,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3550 validateClosedLedger(env, testCases);
3562 env.fund(
XRP(10000), alice, bob);
3566 env(ticket::create(alice, 10));
3569 auto const aliceSeq = env.seq(alice);
3572 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3573 uint256 const chkID{getCheckIndex(alice, aliceSeq)};
3574 auto const [txIDs, batchID] = submitBatch(
3583 auto const objTxn = env.jt(check::cash(bob, chkID,
XRP(10)));
3584 auto const objTxnID =
to_string(objTxn.stx->getTransactionID());
3591 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
3592 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3593 {3,
"CheckCash",
"tesSUCCESS", objTxnID,
std::nullopt},
3595 validateClosedLedger(env, testCases);
3603 testcase(
"pseudo txn with tfInnerBatchTxn");
3605 using namespace test::jtx;
3610 auto const alice =
Account(
"alice");
3611 auto const bob =
Account(
"bob");
3612 env.fund(
XRP(10000), alice, bob);
3615 STTx const stx =
STTx(ttAMENDMENT, [&](
auto& obj) {
3616 obj.setAccountID(sfAccount,
AccountID());
3617 obj.setFieldH256(sfAmendment,
uint256(2));
3618 obj.setFieldU32(sfLedgerSequence, env.seq(alice));
3625 BEAST_EXPECT(reason ==
"Cannot submit pseudo transactions.");
3629 return result.applied;
3636 testcase(
"batch open ledger");
3644 using namespace test::jtx;
3648 XRPAmount const baseFee = env.current()->fees().base;
3650 auto const alice =
Account(
"alice");
3651 auto const bob =
Account(
"bob");
3653 env.fund(
XRP(10000), alice, bob);
3659 auto const aliceSeq = env.seq(alice);
3660 auto const preAlice = env.balance(alice);
3661 auto const preBob = env.balance(bob);
3662 auto const bobSeq = env.seq(bob);
3665 auto const payTxn1 = env.jt(pay(alice, bob,
XRP(10)),
seq(aliceSeq));
3666 auto const payTxn1ID =
to_string(payTxn1.stx->getTransactionID());
3670 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3671 auto const [txIDs, batchID] = submitBatch(
3680 auto const payTxn2 = env.jt(pay(bob, alice,
XRP(5)),
seq(bobSeq + 1));
3681 auto const payTxn2ID =
to_string(payTxn2.stx->getTransactionID());
3688 {2,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3689 {3,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3691 validateClosedLedger(env, testCases);
3699 validateClosedLedger(env, testCases);
3703 BEAST_EXPECT(env.seq(alice) == aliceSeq + 3);
3706 BEAST_EXPECT(env.seq(bob) == bobSeq + 2);
3710 env.balance(alice) == preAlice -
XRP(10) - batchFee - baseFee);
3711 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(10) - baseFee);
3717 testcase(
"batch tx queue");
3719 using namespace test::jtx;
3726 makeSmallQueueConfig(
3727 {{
"minimum_txn_in_ledger_standalone",
"2"}}),
3731 auto alice =
Account(
"alice");
3733 auto carol =
Account(
"carol");
3737 env.close(env.now() + 5s, 10000ms);
3739 env.close(env.now() + 5s, 10000ms);
3750 auto const aliceSeq = env.seq(alice);
3751 auto const bobSeq = env.seq(bob);
3752 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3770 openLedgerFee(env, batchFee),
3786 makeSmallQueueConfig(
3787 {{
"minimum_txn_in_ledger_standalone",
"2"}}),
3791 auto alice =
Account(
"alice");
3793 auto carol =
Account(
"carol");
3797 env.close(env.now() + 5s, 10000ms);
3799 env.close(env.now() + 5s, 10000ms);
3806 auto const aliceSeq = env.seq(alice);
3807 auto const bobSeq = env.seq(bob);
3808 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3829 testcase(
"batch network ops");
3831 using namespace test::jtx;
3841 auto alice =
Account(
"alice");
3843 env.
fund(
XRP(10000), alice, bob);
3851 return jt.stx->getTransactionID();
3863 return transaction->getID();
3888 testcase(
"batch delegate");
3890 using namespace test::jtx;
3897 auto const alice =
Account(
"alice");
3898 auto const bob =
Account(
"bob");
3899 auto const gw =
Account(
"gw");
3900 auto const USD = gw[
"USD"];
3901 env.fund(
XRP(10000), alice, bob, gw);
3904 env(delegate::set(alice, bob, {
"Payment"}));
3907 auto const preAlice = env.balance(alice);
3908 auto const preBob = env.balance(bob);
3910 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3911 auto const seq = env.
seq(alice);
3914 tx[jss::Delegate] = bob.human();
3915 auto const [txIDs, batchID] = submitBatch(
3925 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3926 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3928 validateClosedLedger(env, testCases);
3931 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
3934 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3935 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3942 auto const alice =
Account(
"alice");
3943 auto const bob =
Account(
"bob");
3944 auto const carol =
Account(
"carol");
3945 auto const gw =
Account(
"gw");
3946 auto const USD = gw[
"USD"];
3947 env.fund(
XRP(10000), alice, bob, carol, gw);
3950 env(delegate::set(bob, carol, {
"Payment"}));
3953 auto const preAlice = env.balance(alice);
3954 auto const preBob = env.balance(bob);
3955 auto const preCarol = env.balance(carol);
3957 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3958 auto const aliceSeq = env.seq(alice);
3959 auto const bobSeq = env.seq(bob);
3962 tx[jss::Delegate] = carol.human();
3963 auto const [txIDs, batchID] = submitBatch(
3974 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3975 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3977 validateClosedLedger(env, testCases);
3979 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
3980 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
3981 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
3982 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
3985 BEAST_EXPECT(env.balance(carol) == preCarol);
3994 auto const alice =
Account(
"alice");
3995 auto const bob =
Account(
"bob");
3996 auto const gw =
Account(
"gw");
3997 auto const USD = gw[
"USD"];
3998 env.fund(
XRP(10000), alice, bob, gw);
4001 env(delegate::set(alice, bob, {
"AccountDomainSet"}));
4004 auto const preAlice = env.balance(alice);
4005 auto const preBob = env.balance(bob);
4007 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4008 auto const seq = env.
seq(alice);
4013 tx[jss::Delegate] = bob.human();
4014 auto const [txIDs, batchID] = submitBatch(
4024 {1,
"AccountSet",
"tesSUCCESS", txIDs[0], batchID},
4025 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
4027 validateClosedLedger(env, testCases);
4030 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
4033 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(2) - batchFee);
4034 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(2));
4044 env.fund(
XRP(100000), alice, bob);
4047 auto const mptID =
makeMptID(env.seq(alice), alice);
4048 MPTTester mpt(env, alice, {.fund =
false});
4055 alice, bob, {
"MPTokenIssuanceLock",
"MPTokenIssuanceUnlock"}));
4058 auto const seq = env.
seq(alice);
4059 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4062 jv1[sfTransactionType] = jss::MPTokenIssuanceSet;
4063 jv1[sfAccount] = alice.human();
4064 jv1[sfDelegate] = bob.human();
4065 jv1[sfSequence] =
seq + 1;
4066 jv1[sfMPTokenIssuanceID] =
to_string(mptID);
4070 jv2[sfTransactionType] = jss::MPTokenIssuanceSet;
4071 jv2[sfAccount] = alice.human();
4072 jv2[sfDelegate] = bob.human();
4073 jv2[sfSequence] =
seq + 2;
4074 jv2[sfMPTokenIssuanceID] =
to_string(mptID);
4077 auto const [txIDs, batchID] = submitBatch(
4087 {1,
"MPTokenIssuanceSet",
"tesSUCCESS", txIDs[0], batchID},
4088 {2,
"MPTokenIssuanceSet",
"tesSUCCESS", txIDs[1], batchID},
4090 validateClosedLedger(env, testCases);
4101 env.fund(
XRP(10000), gw, alice, bob);
4104 env(trust(alice, gw[
"USD"](50)));
4108 gw, bob, {
"TrustlineAuthorize",
"TrustlineFreeze"}));
4111 auto const seq = env.
seq(gw);
4112 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4114 auto jv1 = trust(gw, gw[
"USD"](0), alice,
tfSetfAuth);
4115 jv1[sfDelegate] = bob.human();
4116 auto jv2 = trust(gw, gw[
"USD"](0), alice,
tfSetFreeze);
4117 jv2[sfDelegate] = bob.human();
4119 auto const [txIDs, batchID] = submitBatch(
4129 {1,
"TrustSet",
"tesSUCCESS", txIDs[0], batchID},
4130 {2,
"TrustSet",
"tesSUCCESS", txIDs[1], batchID},
4132 validateClosedLedger(env, testCases);
4141 env.fund(
XRP(10000), gw, alice, bob);
4144 env(trust(alice, gw[
"USD"](50)));
4148 gw, bob, {
"TrustlineAuthorize",
"TrustlineFreeze"}));
4151 auto const seq = env.
seq(gw);
4152 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4154 auto jv1 = trust(gw, gw[
"USD"](0), alice,
tfSetFreeze);
4155 jv1[sfDelegate] = bob.human();
4157 jv2[sfDelegate] = bob.human();
4159 auto const [txIDs, batchID] = submitBatch(
4170 {1,
"TrustSet",
"tesSUCCESS", txIDs[0], batchID},
4172 validateClosedLedger(env, testCases);
4182 testcase(
"Validate RPC response");
4184 using namespace jtx;
4188 env.
fund(
XRP(10000), alice, bob);
4193 auto const baseFee = env.
current()->fees().base;
4194 auto const aliceSeq = env.
seq(alice);
4195 auto jtx = env.
jt(pay(alice, bob,
XRP(1)));
4199 auto const jr = env.
rpc(
"submit",
strHex(s.
slice()))[jss::result];
4202 BEAST_EXPECT(jr.isMember(jss::account_sequence_available));
4204 jr[jss::account_sequence_available].asUInt() == aliceSeq + 1);
4205 BEAST_EXPECT(jr.isMember(jss::account_sequence_next));
4207 jr[jss::account_sequence_next].asUInt() == aliceSeq + 1);
4208 BEAST_EXPECT(jr.isMember(jss::open_ledger_cost));
4209 BEAST_EXPECT(jr[jss::open_ledger_cost] ==
to_string(baseFee));
4210 BEAST_EXPECT(jr.isMember(jss::validated_ledger_index));
4215 auto const baseFee = env.
current()->fees().base;
4216 auto const aliceSeq = env.
seq(alice);
4218 auto jtx = env.
jt(pay(alice, bob,
XRP(1)),
seq(aliceSeq));
4222 auto const jr = env.
rpc(
"submit",
strHex(s.
slice()))[jss::result];
4225 BEAST_EXPECT(jr.isMember(jss::account_sequence_available));
4227 jr[jss::account_sequence_available].asUInt() == aliceSeq + 1);
4228 BEAST_EXPECT(jr.isMember(jss::account_sequence_next));
4230 jr[jss::account_sequence_next].asUInt() == aliceSeq + 1);
4231 BEAST_EXPECT(jr.isMember(jss::open_ledger_cost));
4232 BEAST_EXPECT(jr[jss::open_ledger_cost] ==
to_string(baseFee));
4233 BEAST_EXPECT(jr.isMember(jss::validated_ledger_index));
4238 auto const baseFee = env.
current()->fees().base;
4239 auto const aliceSeq = env.
seq(alice);
4240 auto jtx = env.
jt(pay(alice, bob,
XRP(1)),
seq(aliceSeq + 1));
4244 auto const jr = env.
rpc(
"submit",
strHex(s.
slice()))[jss::result];
4247 BEAST_EXPECT(jr.isMember(jss::account_sequence_available));
4249 jr[jss::account_sequence_available].asUInt() == aliceSeq);
4250 BEAST_EXPECT(jr.isMember(jss::account_sequence_next));
4251 BEAST_EXPECT(jr[jss::account_sequence_next].asUInt() == aliceSeq);
4252 BEAST_EXPECT(jr.isMember(jss::open_ledger_cost));
4253 BEAST_EXPECT(jr[jss::open_ledger_cost] ==
to_string(baseFee));
4254 BEAST_EXPECT(jr.isMember(jss::validated_ledger_index));
4261 using namespace jtx;
4266 env.
fund(
XRP(10000), alice, bob, carol);
4277 auto const seq = env.
seq(alice);
4278 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4284 XRPAmount const txBaseFee = getBaseFee(jtx);
4290 auto const seq = env.
seq(alice);
4291 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4305 XRPAmount const txBaseFee = getBaseFee(jtx);
4311 auto const seq = env.
seq(alice);
4312 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4329 XRPAmount const txBaseFee = getBaseFee(jtx);
4335 auto const seq = env.
seq(alice);
4336 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4341 XRPAmount const txBaseFee = getBaseFee(jtx);
4342 BEAST_EXPECT(txBaseFee == batchFee);
4349 testEnable(features);
4350 testPreflight(features);
4351 testPreclaim(features);
4352 testBadRawTxn(features);
4353 testBadSequence(features);
4354 testBadOuterFee(features);
4355 testCalculateBaseFee(features);
4356 testAllOrNothing(features);
4357 testOnlyOne(features);
4358 testUntilFailure(features);
4359 testIndependent(features);
4360 testInnerSubmitRPC(features);
4361 testAccountActivation(features);
4362 testAccountSet(features);
4363 testAccountDelete(features);
4365 testObjectCreateSequence(features);
4366 testObjectCreateTicket(features);
4367 testObjectCreate3rdParty(features);
4368 testTickets(features);
4369 testSequenceOpenLedger(features);
4370 testTicketsOpenLedger(features);
4371 testObjectsOpenLedger(features);
4372 testPseudoTxn(features);
4373 testOpenLedger(features);
4374 testBatchTxQueue(features);
4375 testBatchNetworkOps(features);
4376 testBatchDelegate(features);
4377 testValidateRPCResponse(features);
4378 testBatchCalculateBaseFee(features);
4385 using namespace test::jtx;
A generic endpoint for log messages.
testcase_t testcase
Memberspace for declaring test cases.
void fail(String const &reason, char const *file, int line)
Record a failure.
virtual HashRouter & getHashRouter()=0
virtual NetworkOPs & getOPs()=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 testOpenLedger(FeatureBitset features)
void testTicketsOpenLedger(FeatureBitset features)
void run() override
Runs the suite.
void testBadRawTxn(FeatureBitset features)
void testObjectsOpenLedger(FeatureBitset features)
void testSequenceOpenLedger(FeatureBitset features)
void testEnable(FeatureBitset features)
void testPreflight(FeatureBitset features)
void testObjectCreate3rdParty(FeatureBitset features)
auto openLedgerFee(jtx::Env &env, XRPAmount const &batchFee)
void testIndependent(FeatureBitset features)
void testBatchDelegate(FeatureBitset features)
void testBadSequence(FeatureBitset features)
void testTickets(FeatureBitset features)
void testAccountSet(FeatureBitset features)
std::pair< std::vector< std::string >, std::string > submitBatch(jtx::Env &env, TER const &result, Args &&... args)
void testPreclaim(FeatureBitset features)
void testBatchTxQueue(FeatureBitset features)
void testAllOrNothing(FeatureBitset features)
void testValidateRPCResponse(FeatureBitset features)
void testWithFeats(FeatureBitset features)
void testBatchCalculateBaseFee(FeatureBitset features)
void testLoan(FeatureBitset features)
void testBatchNetworkOps(FeatureBitset features)
void testObjectCreateTicket(FeatureBitset features)
void testInnerSubmitRPC(FeatureBitset features)
void validateClosedLedger(jtx::Env &env, std::vector< TestLedgerData > const &ledgerResults)
void testCalculateBaseFee(FeatureBitset features)
void testAccountActivation(FeatureBitset features)
void testUntilFailure(FeatureBitset features)
static uint256 getCheckIndex(AccountID const &account, std::uint32_t uSequence)
void validateInnerTxn(jtx::Env &env, std::string const &batchID, TestLedgerData const &ledgerResult)
Json::Value getTxByIndex(Json::Value const &jrr, int const index)
Json::Value getLastLedger(jtx::Env &env)
void testObjectCreateSequence(FeatureBitset features)
void testOnlyOne(FeatureBitset features)
static std::unique_ptr< Config > makeSmallQueueConfig(std::map< std::string, std::string > extraTxQ={}, std::map< std::string, std::string > extraVoting={})
void testAccountDelete(FeatureBitset features)
void testPseudoTxn(FeatureBitset features)
void testBadOuterFee(FeatureBitset features)
Immutable cryptographic account descriptor.
A transaction testing environment.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
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.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
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 loanbroker(AccountID const &owner, std::uint32_t seq) noexcept
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Keylet loan(uint256 const &loanBrokerID, std::uint32_t loanSeq) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
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 signers(Account const &account, std::uint32_t quorum, std::vector< signer > const &v)
XRP_t const XRP
Converts to XRP Issue or STAmount.
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
void incLgrSeqForAccDel(jtx::Env &env, jtx::Account const &acc, std::uint32_t margin=0)
std::array< Account, 1+sizeof...(Args)> noripple(Account const &account, Args const &... args)
Designate accounts as no-ripple in Env::fund.
FeatureBitset testable_amendments()
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Json::Value acctdelete(Account const &account, Account const &dest)
Delete account.
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())
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
constexpr std::uint32_t asfAllowTrustLineClawback
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 std::uint32_t asfRequireDest
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
constexpr std::uint32_t tfImmediateOrCancel
constexpr std::uint32_t asfDisableMaster
ApplyResult apply(Application &app, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
constexpr std::uint32_t tfInnerBatchTxn
std::string to_string(base_uint< Bits, Tag > const &a)
std::string strHex(FwdIt begin, FwdIt end)
constexpr TenthBips32 percentageToTenthBips(std::uint32_t percentage)
constexpr std::uint32_t const tfLoanImpair
XRPAmount toDrops(FeeLevel< T > const &level, XRPAmount baseFee)
TenthBips< std::uint32_t > TenthBips32
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
constexpr std::uint32_t const tfMPTUnlock
constexpr std::uint32_t tfAllOrNothing
constexpr std::uint32_t const tfMPTCanLock
constexpr std::uint32_t tfClearFreeze
TERSubset< CanCvtToTER > TER
constexpr std::uint32_t const tfMPTLock
bool passesLocalChecks(STObject const &st, std::string &)
constexpr std::uint32_t tfOnlyOne
constexpr std::uint32_t tfSetfAuth
TenthBips< std::uint16_t > TenthBips16
constexpr std::uint32_t asfRequireAuth
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &message)
Generate a signature for a message.
constexpr XRPAmount INITIAL_XRP
Configure the native currency.
constexpr std::uint32_t tfUntilFailure
void serializeBatch(Serializer &msg, std::uint32_t const &flags, std::vector< uint256 > const &txids)
constexpr std::uint32_t tfIndependent
constexpr std::uint32_t tfSetFreeze
constexpr std::uint32_t tfDisallowXRP
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
MPTID makeMptID(std::uint32_t sequence, AccountID const &account)
std::optional< std::string > batchID
Execution context for applying a JSON transaction.
Set the sequence number on a JTx.