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;
151 using namespace test::jtx;
154 bool const withInnerSigFix = features[fixBatchInnerSigs];
156 for (
bool const withBatch : {
true,
false})
159 << (withBatch ?
"enabled" :
"disabled")
160 <<
", Inner Sig Fix: "
161 << (withInnerSigFix ?
"enabled" :
"disabled");
163 auto const amend = withBatch ? features : features - featureBatch;
167 auto const alice =
Account(
"alice");
168 auto const bob =
Account(
"bob");
169 auto const carol =
Account(
"carol");
170 env.fund(
XRP(10000), alice, bob, carol);
175 auto const seq = env.
seq(alice);
177 auto const txResult =
191 auto const txResult =
193 env(
pay(alice, bob,
XRP(1)),
208 using namespace test::jtx;
216 auto const alice =
Account(
"alice");
217 auto const bob =
Account(
"bob");
218 auto const carol =
Account(
"carol");
219 env.fund(
XRP(10000), alice, bob, carol);
232 auto const seq = env.
seq(alice);
241 auto const seq = env.
seq(alice);
250 auto const seq = env.
seq(alice);
260 auto const seq = env.
seq(alice);
269 auto const seq = env.
seq(alice);
280 auto const seq = env.
seq(alice);
299 auto const seq = env.
seq(alice);
300 auto jt = env.jtnofill(
312 auto const seq = env.
seq(alice);
326 auto const seq = env.
seq(alice);
329 auto jt = env.jtnofill(
340 auto const seq = env.
seq(alice);
342 auto jt = env.jt(
pay(alice, bob,
XRP(1)));
352 auto const seq = env.
seq(alice);
354 auto tx1 =
pay(alice, bob,
XRP(1));
357 tx1[sfSigners.jsonName][0U][sfSigner.jsonName][sfAccount.jsonName] =
359 tx1[sfSigners.jsonName][0U][sfSigner.jsonName]
360 [sfSigningPubKey.jsonName] =
strHex(alice.pk());
361 tx1[sfSigners.jsonName][0U][sfSigner.jsonName]
362 [sfTxnSignature.jsonName] =
"DEADBEEF";
373 auto const seq = env.
seq(alice);
376 tx1[jss::SigningPubKey] =
strHex(alice.pk());
377 auto jt = env.jtnofill(
388 auto const seq = env.
seq(alice);
400 auto const seq = env.
seq(alice);
403 tx1[jss::Fee] =
to_string(env.current()->fees().base);
413 auto const seq = env.
seq(alice);
416 tx1[jss::Fee] =
"-1";
426 auto const seq = env.
seq(alice);
429 tx1[jss::Fee] =
"1.5";
435 fail(
"Expected parse_error for fractional fee");
446 auto const seq = env.
seq(alice);
449 tx1[jss::Sequence] =
seq + 1;
460 auto const seq = env.
seq(alice);
471 auto const seq = env.
seq(alice);
482 auto const seq = env.
seq(alice);
493 auto const seq = env.
seq(alice);
506 auto const seq = env.
seq(alice);
528 auto const seq = env.
seq(alice);
540 auto const seq = env.
seq(alice);
553 auto const seq = env.
seq(alice);
565 auto const seq = env.
seq(alice);
577 auto const seq = env.
seq(alice);
578 auto const bobSeq = env.seq(bob);
580 auto jt = env.jtnofill(
589 jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName]
590 [sfAccount.jsonName] = bob.human();
591 jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName]
592 [sfSigningPubKey.jsonName] =
strHex(alice.pk());
593 jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName]
594 [sfTxnSignature.jsonName] =
603 auto const seq = env.
seq(alice);
620 using namespace test::jtx;
628 auto const alice =
Account(
"alice");
629 auto const bob =
Account(
"bob");
630 auto const carol =
Account(
"carol");
631 auto const dave =
Account(
"dave");
632 auto const elsa =
Account(
"elsa");
633 auto const frank =
Account(
"frank");
634 auto const phantom =
Account(
"phantom");
635 env.memoize(phantom);
637 env.fund(
XRP(10000), alice, bob, carol, dave, elsa, frank);
645 auto const seq = env.
seq(alice);
660 auto const seq = env.
seq(alice);
670 env(
signers(alice, 2, {{bob, 1}, {carol, 1}}));
673 env(
signers(bob, 2, {{carol, 1}, {dave, 1}, {elsa, 1}}));
678 auto const seq = env.
seq(alice);
690 auto const seq = env.
seq(alice);
695 batch::msig(bob, {carol, Account(
"dave", KeyType::ed25519)}),
704 auto const seq = env.
seq(alice);
716 auto const seq = env.
seq(alice);
728 auto const seq = env.
seq(alice);
742 auto const seq = env.
seq(alice);
746 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
747 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
748 batch::msig(bob, {carol, Reg{dave, davo}}),
755 auto const seq = env.seq(alice);
758 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
759 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
760 batch::msig(bob, {carol}),
767 auto const seq = env.seq(alice);
770 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
771 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
772 batch::msig(bob, {carol, dave}),
779 auto const seq = env.seq(alice);
782 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
783 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
784 batch::msig(bob, {carol, dave}),
795 auto const ledSeq = env.current()->seq();
796 auto const seq = env.seq(alice);
799 batch::inner(
pay(alice, phantom,
XRP(1000)), seq + 1),
800 batch::inner(
noop(phantom), ledSeq),
801 batch::sig(Reg{phantom, carol}),
808 auto const ledSeq = env.current()->seq();
809 auto const seq = env.seq(alice);
812 batch::inner(
pay(alice, bob,
XRP(1000)), seq + 1),
813 batch::inner(
noop(bob), ledSeq),
814 batch::sig(Reg{bob, carol}),
822 auto const seq = env.seq(alice);
825 batch::inner(
pay(alice, bob,
XRP(1)), seq + 1),
826 batch::inner(
pay(bob, alice,
XRP(2)), env.seq(bob)),
827 batch::sig(Reg{bob, carol}),
834 auto const seq = env.seq(alice);
837 batch::inner(
pay(alice, bob,
XRP(1)), seq + 1),
838 batch::inner(
pay(bob, alice,
XRP(2)), env.seq(bob)),
848 auto const seq = env.seq(alice);
851 batch::inner(
pay(alice, bob,
XRP(1)), seq + 1),
852 batch::inner(
pay(bob, alice,
XRP(2)), env.seq(bob)),
862 testcase(
"bad raw txn");
864 using namespace test::jtx;
869 auto const alice =
Account(
"alice");
870 auto const bob =
Account(
"bob");
872 env.fund(
XRP(10000), alice, bob);
876 auto const batchFee = batch::calcBatchFee(env, 1, 2);
877 auto const seq = env.
seq(alice);
879 tx1.removeMember(jss::TransactionType);
880 auto jt = env.jtnofill(
891 auto const batchFee = batch::calcBatchFee(env, 1, 2);
892 auto const seq = env.
seq(alice);
894 tx1.removeMember(jss::Account);
895 auto jt = env.jtnofill(
906 auto const batchFee = batch::calcBatchFee(env, 1, 2);
907 auto const seq = env.
seq(alice);
909 tx1.removeMember(jss::Sequence);
910 auto jt = env.jtnofill(
921 auto const batchFee = batch::calcBatchFee(env, 1, 2);
922 auto const seq = env.
seq(alice);
924 tx1.removeMember(jss::Fee);
925 auto jt = env.jtnofill(
936 auto const batchFee = batch::calcBatchFee(env, 1, 2);
937 auto const seq = env.
seq(alice);
939 tx1.removeMember(jss::SigningPubKey);
940 auto jt = env.jtnofill(
953 testcase(
"bad sequence");
955 using namespace test::jtx;
960 auto const alice =
Account(
"alice");
961 auto const bob =
Account(
"bob");
963 auto const USD = gw[
"USD"];
965 env.fund(
XRP(10000), alice, bob, gw);
967 env.trust(USD(1000), alice, bob);
968 env(pay(gw, alice, USD(100)));
969 env(pay(gw, bob, USD(100)));
977 auto const preAliceSeq = env.seq(alice);
978 auto const preAlice = env.balance(alice);
979 auto const preAliceUSD = env.balance(alice, USD.issue());
980 auto const preBobSeq = env.seq(bob);
981 auto const preBob = env.balance(bob);
982 auto const preBobUSD = env.balance(bob, USD.issue());
984 auto const batchFee = batch::calcBatchFee(env, 1, 2);
985 auto const [txIDs, batchID] = submitBatch(
998 validateClosedLedger(env, testCases);
1005 validateClosedLedger(env, testCases);
1009 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1010 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1011 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1012 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1013 BEAST_EXPECT(env.balance(bob) == preBob);
1014 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1019 auto const preAliceSeq = env.seq(alice);
1020 auto const preAlice = env.balance(alice);
1021 auto const preAliceUSD = env.balance(alice, USD.issue());
1022 auto const preBobSeq = env.seq(bob);
1023 auto const preBob = env.balance(bob);
1024 auto const preBobUSD = env.balance(bob, USD.issue());
1026 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1027 auto const [txIDs, batchID] = submitBatch(
1040 validateClosedLedger(env, testCases);
1047 validateClosedLedger(env, testCases);
1051 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1052 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1053 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1054 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1055 BEAST_EXPECT(env.balance(bob) == preBob);
1056 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1061 auto const preAliceSeq = env.seq(alice);
1062 auto const preAlice = env.balance(alice);
1063 auto const preAliceUSD = env.balance(alice, USD.issue());
1064 auto const preBobSeq = env.seq(bob);
1065 auto const preBob = env.balance(bob);
1066 auto const preBobUSD = env.balance(bob, USD.issue());
1068 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1069 auto const [txIDs, batchID] = submitBatch(
1082 validateClosedLedger(env, testCases);
1089 validateClosedLedger(env, testCases);
1093 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1094 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1095 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1096 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1097 BEAST_EXPECT(env.balance(bob) == preBob);
1098 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1103 auto const preAliceSeq = env.seq(alice);
1104 auto const preAlice = env.balance(alice);
1105 auto const preAliceUSD = env.balance(alice, USD.issue());
1106 auto const preBobSeq = env.seq(bob);
1107 auto const preBob = env.balance(bob);
1108 auto const preBobUSD = env.balance(bob, USD.issue());
1110 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1111 auto const [txIDs, batchID] = submitBatch(
1124 validateClosedLedger(env, testCases);
1131 validateClosedLedger(env, testCases);
1135 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1136 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1137 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1138 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1139 BEAST_EXPECT(env.balance(bob) == preBob);
1140 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1145 auto const preAliceSeq = env.seq(alice);
1146 auto const preAlice = env.balance(alice);
1147 auto const preAliceUSD = env.balance(alice, USD.issue());
1148 auto const preBobSeq = env.seq(bob);
1149 auto const preBob = env.balance(bob);
1150 auto const preBobUSD = env.balance(bob, USD.issue());
1152 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1153 auto const [txIDs, batchID] = submitBatch(
1166 validateClosedLedger(env, testCases);
1173 validateClosedLedger(env, testCases);
1177 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1178 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1179 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1180 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1181 BEAST_EXPECT(env.balance(bob) == preBob);
1182 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1189 testcase(
"bad outer fee");
1191 using namespace test::jtx;
1198 auto const alice =
Account(
"alice");
1199 auto const bob =
Account(
"bob");
1200 env.fund(
XRP(10000), alice, bob);
1207 auto const batchFee = batch::calcBatchFee(env, 0, 1);
1208 auto const aliceSeq = env.seq(alice);
1220 auto const alice =
Account(
"alice");
1221 auto const bob =
Account(
"bob");
1222 auto const carol =
Account(
"carol");
1223 env.fund(
XRP(10000), alice, bob, carol);
1229 env(signers(alice, 2, {{bob, 1}, {carol, 1}}));
1233 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1234 auto const aliceSeq = env.seq(alice);
1247 auto const alice =
Account(
"alice");
1248 auto const bob =
Account(
"bob");
1249 auto const carol =
Account(
"carol");
1250 env.fund(
XRP(10000), alice, bob, carol);
1256 env(signers(alice, 2, {{bob, 1}, {carol, 1}}));
1260 auto const batchFee = batch::calcBatchFee(env, 2, 2);
1261 auto const aliceSeq = env.seq(alice);
1262 auto const bobSeq = env.seq(bob);
1276 auto const alice =
Account(
"alice");
1277 auto const bob =
Account(
"bob");
1278 auto const carol =
Account(
"carol");
1279 env.fund(
XRP(10000), alice, bob, carol);
1285 env(signers(alice, 2, {{bob, 1}, {carol, 1}}));
1288 env(signers(bob, 2, {{alice, 1}, {carol, 1}}));
1292 auto const batchFee = batch::calcBatchFee(env, 3, 2);
1293 auto const aliceSeq = env.seq(alice);
1294 auto const bobSeq = env.seq(bob);
1308 auto const alice =
Account(
"alice");
1309 auto const bob =
Account(
"bob");
1310 env.fund(
XRP(10000), alice, bob);
1317 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1318 auto const aliceSeq = env.seq(alice);
1319 auto const bobSeq = env.seq(bob);
1332 auto const alice =
Account(
"alice");
1333 auto const bob =
Account(
"bob");
1334 auto const gw =
Account(
"gw");
1335 auto const USD = gw[
"USD"];
1337 env.fund(
XRP(10000), alice, bob, gw);
1339 auto const ammCreate =
1342 jv[jss::Account] = alice.human();
1345 jv[jss::TradingFee] = 0;
1346 jv[jss::TransactionType] = jss::AMMCreate;
1350 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1351 auto const seq = env.
seq(alice);
1363 testcase(
"calculate base fee");
1365 using namespace test::jtx;
1372 auto const alice =
Account(
"alice");
1373 auto const bob =
Account(
"bob");
1374 env.fund(
XRP(10000), alice, bob);
1377 auto const batchFee = batch::calcBatchFee(env, 0, 9);
1378 auto const aliceSeq = env.seq(alice);
1397 auto const alice =
Account(
"alice");
1398 auto const bob =
Account(
"bob");
1399 env.fund(
XRP(10000), alice, bob);
1402 auto const batchFee = batch::calcBatchFee(env, 0, 9);
1403 auto const aliceSeq = env.seq(alice);
1404 auto jt = env.jtnofill(
1416 env.app().openLedger().modify(
1422 return result.applied;
1430 auto const alice =
Account(
"alice");
1431 auto const bob =
Account(
"bob");
1432 env.fund(
XRP(10000), alice, bob);
1435 auto const aliceSeq = env.seq(alice);
1436 auto const batchFee = batch::calcBatchFee(env, 9, 2);
1440 batch::sig(bob, bob, bob, bob, bob, bob, bob, bob, bob, bob),
1449 auto const alice =
Account(
"alice");
1450 auto const bob =
Account(
"bob");
1451 env.fund(
XRP(10000), alice, bob);
1454 auto const batchFee = batch::calcBatchFee(env, 0, 9);
1455 auto const aliceSeq = env.seq(alice);
1456 auto jt = env.jtnofill(
1460 batch::sig(bob, bob, bob, bob, bob, bob, bob, bob, bob, bob));
1462 env.app().openLedger().modify(
1468 return result.applied;
1476 testcase(
"all or nothing");
1478 using namespace test::jtx;
1483 auto const alice =
Account(
"alice");
1484 auto const bob =
Account(
"bob");
1485 auto const gw =
Account(
"gw");
1486 auto const USD = gw[
"USD"];
1487 env.fund(
XRP(10000), alice, bob, gw);
1492 auto const preAlice = env.balance(alice);
1493 auto const preBob = env.balance(bob);
1495 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1496 auto const seq = env.
seq(alice);
1497 auto const [txIDs, batchID] = submitBatch(
1507 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1508 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1510 validateClosedLedger(env, testCases);
1513 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1516 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1517 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1522 auto const preAlice = env.balance(alice);
1523 auto const preBob = env.balance(bob);
1525 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1526 auto const seq = env.
seq(alice);
1528 auto const [txIDs, batchID] = submitBatch(
1540 validateClosedLedger(env, testCases);
1543 BEAST_EXPECT(env.seq(alice) ==
seq + 1);
1546 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1547 BEAST_EXPECT(env.balance(bob) == preBob);
1552 auto const preAlice = env.balance(alice);
1553 auto const preBob = env.balance(bob);
1555 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1556 auto const seq = env.
seq(alice);
1557 auto const [txIDs, batchID] = submitBatch(
1569 validateClosedLedger(env, testCases);
1572 BEAST_EXPECT(env.seq(alice) ==
seq + 1);
1575 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1576 BEAST_EXPECT(env.balance(bob) == preBob);
1581 auto const preAlice = env.balance(alice);
1582 auto const preBob = env.balance(bob);
1584 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1585 auto const seq = env.
seq(alice);
1586 auto const [txIDs, batchID] = submitBatch(
1598 validateClosedLedger(env, testCases);
1601 BEAST_EXPECT(env.seq(alice) ==
seq + 1);
1604 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1605 BEAST_EXPECT(env.balance(bob) == preBob);
1612 testcase(
"only one");
1614 using namespace test::jtx;
1619 auto const alice =
Account(
"alice");
1620 auto const bob =
Account(
"bob");
1621 auto const carol =
Account(
"carol");
1622 auto const dave =
Account(
"dave");
1623 auto const gw =
Account(
"gw");
1624 auto const USD = gw[
"USD"];
1625 env.fund(
XRP(10000), alice, bob, carol, dave, gw);
1630 auto const preAlice = env.balance(alice);
1631 auto const preBob = env.balance(bob);
1633 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1634 auto const seq = env.
seq(alice);
1635 auto const [txIDs, batchID] = submitBatch(
1649 {1,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[0], batchID},
1650 {2,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[1], batchID},
1651 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
1653 validateClosedLedger(env, testCases);
1656 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
1659 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1660 BEAST_EXPECT(env.balance(bob) == preBob);
1665 auto const preAlice = env.balance(alice);
1666 auto const preBob = env.balance(bob);
1668 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1669 auto const seq = env.
seq(alice);
1670 auto const [txIDs, batchID] = submitBatch(
1682 {1,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[0], batchID},
1683 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1685 validateClosedLedger(env, testCases);
1688 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1691 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
1692 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1697 auto const preAlice = env.balance(alice);
1698 auto const preBob = env.balance(bob);
1700 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1701 auto const seq = env.
seq(alice);
1702 auto const [txIDs, batchID] = submitBatch(
1714 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1716 validateClosedLedger(env, testCases);
1719 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1722 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
1723 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1728 auto const preAlice = env.balance(alice);
1729 auto const preBob = env.balance(bob);
1731 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1732 auto const seq = env.
seq(alice);
1733 auto const [txIDs, batchID] = submitBatch(
1745 {1,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1747 validateClosedLedger(env, testCases);
1750 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1753 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(1));
1754 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1759 auto const preAlice = env.balance(alice);
1760 auto const preBob = env.balance(bob);
1762 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1763 auto const seq = env.
seq(alice);
1764 auto const [txIDs, batchID] = submitBatch(
1776 {1,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1778 validateClosedLedger(env, testCases);
1781 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1784 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(1));
1785 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1790 auto const preAlice = env.balance(alice);
1791 auto const preBob = env.balance(bob);
1792 auto const preCarol = env.balance(carol);
1793 auto const seq = env.
seq(alice);
1794 auto const batchFee = batch::calcBatchFee(env, 0, 6);
1796 auto const [txIDs, batchID] = submitBatch(
1828 {1,
"OfferCreate",
"tecKILLED", txIDs[0], batchID},
1829 {2,
"OfferCreate",
"tecKILLED", txIDs[1], batchID},
1830 {3,
"OfferCreate",
"tecKILLED", txIDs[2], batchID},
1831 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
1833 validateClosedLedger(env, testCases);
1835 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(100) - batchFee);
1836 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(100));
1837 BEAST_EXPECT(env.balance(carol) == preCarol);
1844 testcase(
"until failure");
1846 using namespace test::jtx;
1851 auto const alice =
Account(
"alice");
1852 auto const bob =
Account(
"bob");
1853 auto const carol =
Account(
"carol");
1854 auto const dave =
Account(
"dave");
1855 auto const gw =
Account(
"gw");
1856 auto const USD = gw[
"USD"];
1857 env.fund(
XRP(10000), alice, bob, carol, dave, gw);
1862 auto const preAlice = env.balance(alice);
1863 auto const preBob = env.balance(bob);
1865 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1866 auto const seq = env.
seq(alice);
1867 auto const [txIDs, batchID] = submitBatch(
1880 {1,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[0], batchID},
1882 validateClosedLedger(env, testCases);
1885 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1888 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1889 BEAST_EXPECT(env.balance(bob) == preBob);
1894 auto const preAlice = env.balance(alice);
1895 auto const preBob = env.balance(bob);
1897 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1898 auto const seq = env.
seq(alice);
1899 auto const [txIDs, batchID] = submitBatch(
1911 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1912 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1913 {3,
"Payment",
"tesSUCCESS", txIDs[2], batchID},
1914 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
1916 validateClosedLedger(env, testCases);
1919 BEAST_EXPECT(env.seq(alice) ==
seq + 5);
1922 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(10) - batchFee);
1923 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(10));
1928 auto const preAlice = env.balance(alice);
1929 auto const preBob = env.balance(bob);
1931 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1932 auto const seq = env.
seq(alice);
1933 auto const [txIDs, batchID] = submitBatch(
1946 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1947 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1948 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
1950 validateClosedLedger(env, testCases);
1953 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
1956 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1957 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1962 auto const preAlice = env.balance(alice);
1963 auto const preBob = env.balance(bob);
1965 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1966 auto const seq = env.
seq(alice);
1967 auto const [txIDs, batchID] = submitBatch(
1980 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1981 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1983 validateClosedLedger(env, testCases);
1986 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1989 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1990 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1995 auto const preAlice = env.balance(alice);
1996 auto const preBob = env.balance(bob);
1998 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1999 auto const seq = env.
seq(alice);
2000 auto const [txIDs, batchID] = submitBatch(
2013 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2014 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2016 validateClosedLedger(env, testCases);
2019 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
2022 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
2023 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
2028 auto const preAlice = env.balance(alice);
2029 auto const preBob = env.balance(bob);
2030 auto const preCarol = env.balance(carol);
2031 auto const seq = env.
seq(alice);
2032 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2033 auto const [txIDs, batchID] = submitBatch(
2051 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2052 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2053 {3,
"OfferCreate",
"tecKILLED", txIDs[2], batchID},
2055 validateClosedLedger(env, testCases);
2057 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(200) - batchFee);
2058 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(100));
2059 BEAST_EXPECT(env.balance(carol) == preCarol +
XRP(100));
2066 testcase(
"independent");
2068 using namespace test::jtx;
2073 auto const alice =
Account(
"alice");
2074 auto const bob =
Account(
"bob");
2075 auto const carol =
Account(
"carol");
2076 auto const gw =
Account(
"gw");
2077 auto const USD = gw[
"USD"];
2078 env.fund(
XRP(10000), alice, bob, carol, gw);
2083 auto const preAlice = env.balance(alice);
2084 auto const preBob = env.balance(bob);
2086 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2087 auto const seq = env.
seq(alice);
2088 auto const [txIDs, batchID] = submitBatch(
2102 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2103 {2,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[1], batchID},
2104 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
2105 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2107 validateClosedLedger(env, testCases);
2110 BEAST_EXPECT(env.seq(alice) ==
seq + 5);
2113 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(4) - batchFee);
2114 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(4));
2119 auto const preAlice = env.balance(alice);
2120 auto const preBob = env.balance(bob);
2122 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2123 auto const seq = env.
seq(alice);
2124 auto const [txIDs, batchID] = submitBatch(
2137 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2138 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2139 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
2140 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2142 validateClosedLedger(env, testCases);
2145 BEAST_EXPECT(env.seq(alice) ==
seq + 5);
2148 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(6) - batchFee);
2149 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(6));
2154 auto const preAlice = env.balance(alice);
2155 auto const preBob = env.balance(bob);
2157 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2158 auto const seq = env.
seq(alice);
2159 auto const [txIDs, batchID] = submitBatch(
2172 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2173 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2174 {3,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2176 validateClosedLedger(env, testCases);
2179 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
2182 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(6));
2183 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(6));
2188 auto const preAlice = env.balance(alice);
2189 auto const preBob = env.balance(bob);
2191 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2192 auto const seq = env.
seq(alice);
2193 auto const [txIDs, batchID] = submitBatch(
2206 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2207 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2208 {3,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2210 validateClosedLedger(env, testCases);
2213 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
2216 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(6));
2217 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(6));
2222 auto const preAlice = env.balance(alice);
2223 auto const preBob = env.balance(bob);
2224 auto const preCarol = env.balance(carol);
2225 auto const seq = env.
seq(alice);
2226 auto const batchFee = batch::calcBatchFee(env, 0, 3);
2227 auto const [txIDs, batchID] = submitBatch(
2244 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2245 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2246 {3,
"OfferCreate",
"tecKILLED", txIDs[2], batchID},
2248 validateClosedLedger(env, testCases);
2250 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(200) - batchFee);
2251 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(100));
2252 BEAST_EXPECT(env.balance(carol) == preCarol +
XRP(100));
2259 bool const withInnerSigFix = features[fixBatchInnerSigs];
2263 ss <<
"inner submit rpc: batch "
2264 << (withBatch ?
"enabled" :
"disabled") <<
", inner sig fix: "
2265 << (withInnerSigFix ?
"enabled" :
"disabled") <<
": ";
2269 auto const amend = withBatch ? features : features - featureBatch;
2271 using namespace test::jtx;
2275 if (!BEAST_EXPECT(amend[featureBatch] == withBatch))
2278 auto const alice =
Account(
"alice");
2279 auto const bob =
Account(
"bob");
2281 env.fund(
XRP(10000), alice, bob);
2284 auto submitAndValidate =
2290 bool expectInvalidFlag =
false) {
2291 testcase << testName << caseName
2292 << (expectInvalidFlag
2293 ?
" - Expected to reach tx engine!"
2295 auto const jrr = env.rpc(
"submit",
strHex(
slice))[jss::result];
2296 auto const expected = withBatch
2297 ? expectedEnabled.value_or(
2298 "fails local checks: Malformed: Invalid inner batch "
2300 : expectedDisabled.value_or(
2301 "fails local checks: Empty SigningPubKey.");
2302 if (expectInvalidFlag)
2305 jrr[jss::status] ==
"success" &&
2306 jrr[jss::engine_result] ==
"temINVALID_FLAG",
2314 jrr[jss::status] ==
"error" &&
2315 jrr[jss::error] ==
"invalidTransaction" &&
2316 jrr[jss::error_exception] == expected,
2331 txn[sfTxnSignature] =
"DEADBEEF";
2335 submitAndValidate(
"TxnSignature set", s.
slice(), __LINE__);
2345 txn[sfSigningPubKey] =
strHex(alice.pk());
2350 "SigningPubKey set",
2354 "fails local checks: Invalid signature.");
2373 "fails local checks: Invalid Signers array size.");
2380 auto const jt = env.jt(txn.getTxn());
2405 "No signing fields set",
2408 "fails local checks: Empty SigningPubKey.",
2409 "fails local checks: Empty SigningPubKey.",
2410 withBatch && !withInnerSigFix);
2420 ttAMENDMENT, [
seq = env.closed()->header().
seq + 1](
auto& obj) {
2421 obj.setAccountID(sfAccount, AccountID());
2422 obj.setFieldH256(sfAmendment, fixBatchInnerSigs);
2423 obj.setFieldU32(sfLedgerSequence, seq);
2424 obj.setFieldU32(sfFlags, tfInnerBatchTxn);
2432 "Pseudo-transaction",
2436 ?
"fails local checks: Empty SigningPubKey."
2437 :
"fails local checks: Cannot submit pseudo transactions.",
2438 "fails local checks: Empty SigningPubKey.");
2445 for (
bool const withBatch : {
true,
false})
2447 doTestInnerSubmitRPC(features, withBatch);
2454 testcase(
"account activation");
2456 using namespace test::jtx;
2461 auto const alice =
Account(
"alice");
2462 auto const bob =
Account(
"bob");
2463 env.fund(
XRP(10000), alice);
2467 auto const preAlice = env.balance(alice);
2468 auto const ledSeq = env.current()->seq();
2469 auto const seq = env.
seq(alice);
2470 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2471 auto const [txIDs, batchID] = submitBatch(
2482 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2483 {2,
"AccountSet",
"tesSUCCESS", txIDs[1], batchID},
2485 validateClosedLedger(env, testCases);
2488 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
2491 BEAST_EXPECT(env.seq(bob) == ledSeq + 1);
2494 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1000) - batchFee);
2495 BEAST_EXPECT(env.balance(bob) ==
XRP(1000));
2501 testcase(
"account set");
2503 using namespace test::jtx;
2508 auto const alice =
Account(
"alice");
2509 auto const bob =
Account(
"bob");
2510 env.fund(
XRP(10000), alice, bob);
2513 auto const preAlice = env.balance(alice);
2514 auto const preBob = env.balance(bob);
2516 auto const seq = env.
seq(alice);
2517 auto const batchFee = batch::calcBatchFee(env, 0, 2);
2521 auto const [txIDs, batchID] = submitBatch(
2531 {1,
"AccountSet",
"tesSUCCESS", txIDs[0], batchID},
2532 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2534 validateClosedLedger(env, testCases);
2542 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
2545 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
2546 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
2552 testcase(
"account delete");
2554 using namespace test::jtx;
2561 auto const alice =
Account(
"alice");
2562 auto const bob =
Account(
"bob");
2563 env.fund(
XRP(10000), alice, bob);
2567 for (
int i = 0; i < 5; ++i)
2570 auto const preAlice = env.balance(alice);
2571 auto const preBob = env.balance(bob);
2573 auto const seq = env.
seq(alice);
2574 auto const batchFee = batch::calcBatchFee(env, 0, 2) +
2575 env.current()->fees().increment;
2576 auto const [txIDs, batchID] = submitBatch(
2588 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2589 {2,
"AccountDelete",
"tesSUCCESS", txIDs[1], batchID},
2591 validateClosedLedger(env, testCases);
2595 BEAST_EXPECT(env.balance(bob) == preBob + (preAlice - batchFee));
2602 auto const alice =
Account(
"alice");
2603 auto const bob =
Account(
"bob");
2604 env.fund(
XRP(10000), alice, bob);
2608 for (
int i = 0; i < 5; ++i)
2611 auto const preAlice = env.balance(alice);
2612 auto const preBob = env.balance(bob);
2614 env.trust(bob[
"USD"](1000), alice);
2617 auto const seq = env.
seq(alice);
2618 auto const batchFee = batch::calcBatchFee(env, 0, 2) +
2619 env.current()->fees().increment;
2620 auto const [txIDs, batchID] = submitBatch(
2632 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2633 {2,
"AccountDelete",
"tecHAS_OBLIGATIONS", txIDs[1], batchID},
2634 {3,
"Payment",
"tesSUCCESS", txIDs[2], batchID},
2636 validateClosedLedger(env, testCases);
2640 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
2647 auto const alice =
Account(
"alice");
2648 auto const bob =
Account(
"bob");
2649 env.fund(
XRP(10000), alice, bob);
2653 for (
int i = 0; i < 5; ++i)
2656 auto const preAlice = env.balance(alice);
2657 auto const preBob = env.balance(bob);
2659 auto const seq = env.
seq(alice);
2660 auto const batchFee = batch::calcBatchFee(env, 0, 2) +
2661 env.current()->fees().increment;
2662 auto const [txIDs, batchID] = submitBatch(
2675 validateClosedLedger(env, testCases);
2679 BEAST_EXPECT(env.balance(bob) == preBob);
2691 [](
auto const& disabled) {
return disabled == ttLOAN_BROKER_SET; });
2693 using namespace test::jtx;
2697 features | featureSingleAssetVault | featureLendingProtocol |
2700 Account const issuer{
"issuer"};
2703 Account const lender{
"lender"};
2705 Account const borrower{
"borrower"};
2709 env.fund(
XRP(100'000), issuer,
noripple(lender, borrower));
2717 auto const deposit = asset(50'000);
2718 auto const debtMaximumValue = asset(25'000).value();
2719 auto const coverDepositValue = asset(1000).value();
2721 auto [tx, vaultKeylet] =
2722 vault.create({.owner = lender, .asset = asset});
2725 BEAST_EXPECT(env.le(vaultKeylet));
2728 {.depositor = lender, .id = vaultKeylet.key, .amount = deposit}));
2731 auto const brokerKeylet =
2735 using namespace loanBroker;
2736 env(
set(lender, vaultKeylet.key),
2738 debtMaximum(debtMaximumValue),
2742 env(coverDeposit(lender, brokerKeylet.key, coverDepositValue));
2748 using namespace loan;
2749 using namespace std::chrono_literals;
2751 auto const lenderSeq = env.seq(lender);
2752 auto const batchFee = batch::calcBatchFee(env, 0, 2);
2754 auto const loanKeylet =
keylet::loan(brokerKeylet.key, 1);
2756 auto const [txIDs, batchID] = submitBatch(
2763 set(lender, brokerKeylet.key, asset(1000).value()),
2765 sig(sfCounterpartySignature, borrower),
2773 STAmount{asset, asset(500).value()}),
2777 auto const [txIDs, batchID] = submitBatch(
2783 set(lender, brokerKeylet.key, asset(1000).value()),
2792 STAmount{asset, asset(500).value()}),
2796 auto const [txIDs, batchID] = submitBatch(
2803 set(lender, brokerKeylet.key, asset(1000).value()),
2805 counterparty(borrower.id()),
2813 STAmount{asset, asset(500).value()}),
2820 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2821 auto const [txIDs, batchID] = submitBatch(
2828 set(lender, brokerKeylet.key, asset(1000).value()),
2829 counterparty(borrower.id()),
2841 STAmount{asset, asset(500).value()}),
2846 BEAST_EXPECT(env.le(brokerKeylet));
2847 BEAST_EXPECT(!env.le(loanKeylet));
2852 auto const lenderSeq = env.seq(lender);
2853 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2854 auto const [txIDs, batchID] = submitBatch(
2861 set(lender, brokerKeylet.key, asset(1000).value()),
2862 counterparty(borrower.id()),
2873 BEAST_EXPECT(env.le(brokerKeylet));
2874 if (
auto const sleLoan = env.le(loanKeylet); lendingBatchEnabled
2875 ? BEAST_EXPECT(sleLoan)
2876 : !BEAST_EXPECT(!sleLoan))
2886 testcase(
"object create w/ sequence");
2888 using namespace test::jtx;
2893 auto const alice =
Account(
"alice");
2894 auto const bob =
Account(
"bob");
2895 auto const gw =
Account(
"gw");
2896 auto const USD = gw[
"USD"];
2898 env.fund(
XRP(10000), alice, bob, gw);
2901 env.trust(USD(1000), alice, bob);
2902 env(pay(gw, alice, USD(100)));
2903 env(pay(gw, bob, USD(100)));
2908 auto const aliceSeq = env.seq(alice);
2909 auto const bobSeq = env.seq(bob);
2910 auto const preAlice = env.balance(alice);
2911 auto const preBob = env.balance(bob);
2912 auto const preAliceUSD = env.balance(alice, USD.issue());
2913 auto const preBobUSD = env.balance(bob, USD.issue());
2915 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2916 uint256 const chkID{getCheckIndex(bob, env.seq(bob))};
2917 auto const [txIDs, batchID] = submitBatch(
2921 batch::inner(check::create(bob, alice, USD(10)), bobSeq),
2922 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq + 1),
2928 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
2929 {2,
"CheckCash",
"tesSUCCESS", txIDs[1], batchID},
2931 validateClosedLedger(env, testCases);
2934 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
2937 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
2940 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
2941 BEAST_EXPECT(env.balance(bob) == preBob);
2945 env.balance(alice, USD.issue()) == preAliceUSD + USD(10));
2946 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10));
2954 auto const aliceSeq = env.seq(alice);
2955 auto const bobSeq = env.seq(bob);
2956 auto const preAlice = env.balance(alice);
2957 auto const preBob = env.balance(bob);
2958 auto const preAliceUSD = env.balance(alice, USD.issue());
2959 auto const preBobUSD = env.balance(bob, USD.issue());
2961 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2962 uint256 const chkID{getCheckIndex(bob, env.seq(bob))};
2963 auto const [txIDs, batchID] = submitBatch(
2968 batch::inner(check::create(bob, alice, USD(10)), bobSeq),
2969 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq + 1),
2975 {1,
"CheckCreate",
"tecDST_TAG_NEEDED", txIDs[0], batchID},
2976 {2,
"CheckCash",
"tecNO_ENTRY", txIDs[1], batchID},
2978 validateClosedLedger(env, testCases);
2981 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
2984 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
2987 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
2988 BEAST_EXPECT(env.balance(bob) == preBob);
2991 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
2992 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
2999 testcase(
"object create w/ ticket");
3001 using namespace test::jtx;
3006 auto const alice =
Account(
"alice");
3007 auto const bob =
Account(
"bob");
3008 auto const gw =
Account(
"gw");
3009 auto const USD = gw[
"USD"];
3011 env.fund(
XRP(10000), alice, bob, gw);
3014 env.trust(USD(1000), alice, bob);
3015 env(pay(gw, alice, USD(100)));
3016 env(pay(gw, bob, USD(100)));
3019 auto const aliceSeq = env.seq(alice);
3020 auto const bobSeq = env.seq(bob);
3021 auto const preAlice = env.balance(alice);
3022 auto const preBob = env.balance(bob);
3023 auto const preAliceUSD = env.balance(alice, USD.issue());
3024 auto const preBobUSD = env.balance(bob, USD.issue());
3026 auto const batchFee = batch::calcBatchFee(env, 1, 3);
3027 uint256 const chkID{getCheckIndex(bob, bobSeq + 1)};
3028 auto const [txIDs, batchID] = submitBatch(
3033 batch::inner(check::create(bob, alice, USD(10)), 0, bobSeq + 1),
3034 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq + 1),
3040 {1,
"TicketCreate",
"tesSUCCESS", txIDs[0], batchID},
3041 {2,
"CheckCreate",
"tesSUCCESS", txIDs[1], batchID},
3042 {3,
"CheckCash",
"tesSUCCESS", txIDs[2], batchID},
3044 validateClosedLedger(env, testCases);
3046 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
3047 BEAST_EXPECT(env.seq(bob) == bobSeq + 10 + 1);
3048 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
3049 BEAST_EXPECT(env.balance(bob) == preBob);
3050 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD + USD(10));
3051 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10));
3057 testcase(
"object create w/ 3rd party");
3059 using namespace test::jtx;
3064 auto const alice =
Account(
"alice");
3065 auto const bob =
Account(
"bob");
3066 auto const carol =
Account(
"carol");
3067 auto const gw =
Account(
"gw");
3068 auto const USD = gw[
"USD"];
3070 env.fund(
XRP(10000), alice, bob, carol, gw);
3073 env.trust(USD(1000), alice, bob);
3074 env(pay(gw, alice, USD(100)));
3075 env(pay(gw, bob, USD(100)));
3078 auto const aliceSeq = env.seq(alice);
3079 auto const bobSeq = env.seq(bob);
3080 auto const carolSeq = env.seq(carol);
3081 auto const preAlice = env.balance(alice);
3082 auto const preBob = env.balance(bob);
3083 auto const preCarol = env.balance(carol);
3084 auto const preAliceUSD = env.balance(alice, USD.issue());
3085 auto const preBobUSD = env.balance(bob, USD.issue());
3087 auto const batchFee = batch::calcBatchFee(env, 2, 2);
3088 uint256 const chkID{getCheckIndex(bob, env.seq(bob))};
3089 auto const [txIDs, batchID] = submitBatch(
3093 batch::inner(check::create(bob, alice, USD(10)), bobSeq),
3094 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq),
3100 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
3101 {2,
"CheckCash",
"tesSUCCESS", txIDs[1], batchID},
3103 validateClosedLedger(env, testCases);
3105 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
3106 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
3107 BEAST_EXPECT(env.seq(carol) == carolSeq + 1);
3108 BEAST_EXPECT(env.balance(alice) == preAlice);
3109 BEAST_EXPECT(env.balance(bob) == preBob);
3110 BEAST_EXPECT(env.balance(carol) == preCarol - batchFee);
3111 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD + USD(10));
3112 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10));
3119 testcase(
"tickets outer");
3121 using namespace test::jtx;
3126 auto const alice =
Account(
"alice");
3127 auto const bob =
Account(
"bob");
3129 env.fund(
XRP(10000), alice, bob);
3133 env(ticket::create(alice, 10));
3136 auto const aliceSeq = env.seq(alice);
3137 auto const preAlice = env.balance(alice);
3138 auto const preBob = env.balance(bob);
3140 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3141 auto const [txIDs, batchID] = submitBatch(
3152 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3153 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3155 validateClosedLedger(env, testCases);
3159 BEAST_EXPECT(sle->getFieldU32(sfOwnerCount) == 9);
3160 BEAST_EXPECT(sle->getFieldU32(sfTicketCount) == 9);
3162 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
3163 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3164 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3168 testcase(
"tickets inner");
3170 using namespace test::jtx;
3175 auto const alice =
Account(
"alice");
3176 auto const bob =
Account(
"bob");
3178 env.fund(
XRP(10000), alice, bob);
3182 env(ticket::create(alice, 10));
3185 auto const aliceSeq = env.seq(alice);
3186 auto const preAlice = env.balance(alice);
3187 auto const preBob = env.balance(bob);
3189 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3190 auto const [txIDs, batchID] = submitBatch(
3200 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3201 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3203 validateClosedLedger(env, testCases);
3207 BEAST_EXPECT(sle->getFieldU32(sfOwnerCount) == 8);
3208 BEAST_EXPECT(sle->getFieldU32(sfTicketCount) == 8);
3210 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
3211 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3212 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3216 testcase(
"tickets outer inner");
3218 using namespace test::jtx;
3223 auto const alice =
Account(
"alice");
3224 auto const bob =
Account(
"bob");
3226 env.fund(
XRP(10000), alice, bob);
3230 env(ticket::create(alice, 10));
3233 auto const aliceSeq = env.seq(alice);
3234 auto const preAlice = env.balance(alice);
3235 auto const preBob = env.balance(bob);
3237 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3238 auto const [txIDs, batchID] = submitBatch(
3249 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3250 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3252 validateClosedLedger(env, testCases);
3256 BEAST_EXPECT(sle->getFieldU32(sfOwnerCount) == 8);
3257 BEAST_EXPECT(sle->getFieldU32(sfTicketCount) == 8);
3259 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
3260 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3261 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3268 testcase(
"sequence open ledger");
3270 using namespace test::jtx;
3273 auto const alice =
Account(
"alice");
3274 auto const bob =
Account(
"bob");
3275 auto const carol =
Account(
"carol");
3285 env.fund(
XRP(10000), alice, bob, carol);
3288 auto const aliceSeq = env.seq(alice);
3289 auto const carolSeq = env.seq(carol);
3292 auto const noopTxn = env.jt(
noop(alice),
seq(aliceSeq + 2));
3293 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3297 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3298 auto const [txIDs, batchID] = submitBatch(
3310 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3311 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3313 validateClosedLedger(env, testCases);
3320 {0,
"AccountSet",
"tesSUCCESS", noopTxnID,
std::nullopt},
3322 validateClosedLedger(env, testCases);
3332 env.fund(
XRP(10000), alice, bob);
3335 auto const aliceSeq = env.seq(alice);
3338 auto const noopTxn = env.jt(
noop(alice),
seq(aliceSeq + 1));
3342 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3343 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);
3377 auto const aliceSeq = env.seq(alice);
3378 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3379 auto const [txIDs, batchID] = submitBatch(
3386 auto const noopTxn = env.jt(
noop(alice),
seq(aliceSeq + 1));
3387 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3394 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3395 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3397 validateClosedLedger(env, testCases);
3404 validateClosedLedger(env, testCases);
3411 env.fund(
XRP(10000), alice, bob, carol);
3414 auto const aliceSeq = env.seq(alice);
3415 auto const carolSeq = env.seq(carol);
3418 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3419 auto const [txIDs, batchID] = submitBatch(
3428 auto const noopTxn = env.jt(
noop(carol),
seq(carolSeq));
3429 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3435 {0,
"AccountSet",
"tesSUCCESS", noopTxnID,
std::nullopt},
3437 {2,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3438 {3,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3440 validateClosedLedger(env, testCases);
3447 validateClosedLedger(env, testCases);
3455 testcase(
"tickets open ledger");
3457 using namespace test::jtx;
3460 auto const alice =
Account(
"alice");
3461 auto const bob =
Account(
"bob");
3469 env.fund(
XRP(10000), alice, bob);
3473 env(ticket::create(alice, 10));
3476 auto const aliceSeq = env.seq(alice);
3479 auto const noopTxn =
3481 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3485 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3486 auto const [txIDs, batchID] = submitBatch(
3498 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3499 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3501 validateClosedLedger(env, testCases);
3508 validateClosedLedger(env, testCases);
3518 env.fund(
XRP(10000), alice, bob);
3522 env(ticket::create(alice, 10));
3525 auto const aliceSeq = env.seq(alice);
3528 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3529 auto const [txIDs, batchID] = submitBatch(
3538 auto const noopTxn =
3546 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3547 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3549 validateClosedLedger(env, testCases);
3556 validateClosedLedger(env, testCases);
3564 testcase(
"objects open ledger");
3566 using namespace test::jtx;
3569 auto const alice =
Account(
"alice");
3570 auto const bob =
Account(
"bob");
3580 env.fund(
XRP(10000), alice, bob);
3584 env(ticket::create(alice, 10));
3587 auto const aliceSeq = env.seq(alice);
3590 uint256 const chkID{getCheckIndex(alice, aliceSeq)};
3591 auto const objTxn = env.jt(check::cash(bob, chkID,
XRP(10)));
3592 auto const objTxnID =
to_string(objTxn.stx->getTransactionID());
3596 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3597 auto const [txIDs, batchID] = submitBatch(
3609 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
3610 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3611 {3,
"CheckCash",
"tesSUCCESS", objTxnID,
std::nullopt},
3613 validateClosedLedger(env, testCases);
3620 validateClosedLedger(env, testCases);
3627 env.fund(
XRP(10000), alice, bob);
3631 env(ticket::create(alice, 10));
3634 auto const aliceSeq = env.seq(alice);
3635 auto const bobSeq = env.seq(bob);
3638 uint256 const chkID{getCheckIndex(alice, aliceSeq)};
3639 auto const objTxn = env.jt(check::create(alice, bob,
XRP(10)));
3640 auto const objTxnID =
to_string(objTxn.stx->getTransactionID());
3644 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3645 auto const [txIDs, batchID] = submitBatch(
3657 {0,
"CheckCreate",
"tesSUCCESS", objTxnID,
std::nullopt},
3659 {2,
"CheckCash",
"tesSUCCESS", txIDs[0], batchID},
3660 {3,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3662 validateClosedLedger(env, testCases);
3674 env.fund(
XRP(10000), alice, bob);
3678 env(ticket::create(alice, 10));
3681 auto const aliceSeq = env.seq(alice);
3684 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3685 uint256 const chkID{getCheckIndex(alice, aliceSeq)};
3686 auto const [txIDs, batchID] = submitBatch(
3695 auto const objTxn = env.jt(check::cash(bob, chkID,
XRP(10)));
3696 auto const objTxnID =
to_string(objTxn.stx->getTransactionID());
3703 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
3704 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3705 {3,
"CheckCash",
"tesSUCCESS", objTxnID,
std::nullopt},
3707 validateClosedLedger(env, testCases);
3715 testcase(
"pseudo txn with tfInnerBatchTxn");
3717 using namespace test::jtx;
3722 auto const alice =
Account(
"alice");
3723 auto const bob =
Account(
"bob");
3724 env.fund(
XRP(10000), alice, bob);
3727 STTx const stx =
STTx(ttAMENDMENT, [&](
auto& obj) {
3728 obj.setAccountID(sfAccount,
AccountID());
3729 obj.setFieldH256(sfAmendment,
uint256(2));
3730 obj.setFieldU32(sfLedgerSequence, env.seq(alice));
3737 BEAST_EXPECT(reason ==
"Cannot submit pseudo transactions.");
3741 return result.applied;
3748 testcase(
"batch open ledger");
3756 using namespace test::jtx;
3760 XRPAmount const baseFee = env.current()->fees().base;
3762 auto const alice =
Account(
"alice");
3763 auto const bob =
Account(
"bob");
3765 env.fund(
XRP(10000), alice, bob);
3771 auto const aliceSeq = env.seq(alice);
3772 auto const preAlice = env.balance(alice);
3773 auto const preBob = env.balance(bob);
3774 auto const bobSeq = env.seq(bob);
3777 auto const payTxn1 = env.jt(pay(alice, bob,
XRP(10)),
seq(aliceSeq));
3778 auto const payTxn1ID =
to_string(payTxn1.stx->getTransactionID());
3782 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3783 auto const [txIDs, batchID] = submitBatch(
3792 auto const payTxn2 = env.jt(pay(bob, alice,
XRP(5)),
seq(bobSeq + 1));
3793 auto const payTxn2ID =
to_string(payTxn2.stx->getTransactionID());
3800 {2,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3801 {3,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3803 validateClosedLedger(env, testCases);
3811 validateClosedLedger(env, testCases);
3815 BEAST_EXPECT(env.seq(alice) == aliceSeq + 3);
3818 BEAST_EXPECT(env.seq(bob) == bobSeq + 2);
3822 env.balance(alice) == preAlice -
XRP(10) - batchFee - baseFee);
3823 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(10) - baseFee);
3829 testcase(
"batch tx queue");
3831 using namespace test::jtx;
3838 makeSmallQueueConfig(
3839 {{
"minimum_txn_in_ledger_standalone",
"2"}}),
3844 auto alice =
Account(
"alice");
3846 auto carol =
Account(
"carol");
3850 env.close(env.now() + 5s, 10000ms);
3852 env.close(env.now() + 5s, 10000ms);
3863 auto const aliceSeq = env.seq(alice);
3864 auto const bobSeq = env.seq(bob);
3865 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3883 openLedgerFee(env, batchFee),
3899 makeSmallQueueConfig(
3900 {{
"minimum_txn_in_ledger_standalone",
"2"}}),
3905 auto alice =
Account(
"alice");
3907 auto carol =
Account(
"carol");
3911 env.close(env.now() + 5s, 10000ms);
3913 env.close(env.now() + 5s, 10000ms);
3920 auto const aliceSeq = env.seq(alice);
3921 auto const bobSeq = env.seq(bob);
3922 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3943 testcase(
"batch network ops");
3945 using namespace test::jtx;
3955 auto alice =
Account(
"alice");
3957 env.
fund(
XRP(10000), alice, bob);
3965 return jt.stx->getTransactionID();
3977 return transaction->getID();
4002 testcase(
"batch delegate");
4004 using namespace test::jtx;
4011 auto const alice =
Account(
"alice");
4012 auto const bob =
Account(
"bob");
4013 auto const gw =
Account(
"gw");
4014 auto const USD = gw[
"USD"];
4015 env.fund(
XRP(10000), alice, bob, gw);
4018 env(delegate::set(alice, bob, {
"Payment"}));
4021 auto const preAlice = env.balance(alice);
4022 auto const preBob = env.balance(bob);
4024 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4025 auto const seq = env.
seq(alice);
4028 tx[jss::Delegate] = bob.human();
4029 auto const [txIDs, batchID] = submitBatch(
4039 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
4040 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
4042 validateClosedLedger(env, testCases);
4045 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
4048 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
4049 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
4056 auto const alice =
Account(
"alice");
4057 auto const bob =
Account(
"bob");
4058 auto const carol =
Account(
"carol");
4059 auto const gw =
Account(
"gw");
4060 auto const USD = gw[
"USD"];
4061 env.fund(
XRP(10000), alice, bob, carol, gw);
4064 env(delegate::set(bob, carol, {
"Payment"}));
4067 auto const preAlice = env.balance(alice);
4068 auto const preBob = env.balance(bob);
4069 auto const preCarol = env.balance(carol);
4071 auto const batchFee = batch::calcBatchFee(env, 1, 2);
4072 auto const aliceSeq = env.seq(alice);
4073 auto const bobSeq = env.seq(bob);
4076 tx[jss::Delegate] = carol.human();
4077 auto const [txIDs, batchID] = submitBatch(
4088 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
4089 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
4091 validateClosedLedger(env, testCases);
4093 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
4094 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
4095 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
4096 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
4099 BEAST_EXPECT(env.balance(carol) == preCarol);
4108 auto const alice =
Account(
"alice");
4109 auto const bob =
Account(
"bob");
4110 auto const gw =
Account(
"gw");
4111 auto const USD = gw[
"USD"];
4112 env.fund(
XRP(10000), alice, bob, gw);
4115 env(delegate::set(alice, bob, {
"AccountDomainSet"}));
4118 auto const preAlice = env.balance(alice);
4119 auto const preBob = env.balance(bob);
4121 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4122 auto const seq = env.
seq(alice);
4127 tx[jss::Delegate] = bob.human();
4128 auto const [txIDs, batchID] = submitBatch(
4138 {1,
"AccountSet",
"tesSUCCESS", txIDs[0], batchID},
4139 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
4141 validateClosedLedger(env, testCases);
4144 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
4147 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(2) - batchFee);
4148 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(2));
4158 env.fund(
XRP(100000), alice, bob);
4161 auto const mptID =
makeMptID(env.seq(alice), alice);
4162 MPTTester mpt(env, alice, {.fund =
false});
4169 alice, bob, {
"MPTokenIssuanceLock",
"MPTokenIssuanceUnlock"}));
4172 auto const seq = env.
seq(alice);
4173 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4176 jv1[sfTransactionType] = jss::MPTokenIssuanceSet;
4177 jv1[sfAccount] = alice.human();
4178 jv1[sfDelegate] = bob.human();
4179 jv1[sfSequence] =
seq + 1;
4180 jv1[sfMPTokenIssuanceID] =
to_string(mptID);
4184 jv2[sfTransactionType] = jss::MPTokenIssuanceSet;
4185 jv2[sfAccount] = alice.human();
4186 jv2[sfDelegate] = bob.human();
4187 jv2[sfSequence] =
seq + 2;
4188 jv2[sfMPTokenIssuanceID] =
to_string(mptID);
4191 auto const [txIDs, batchID] = submitBatch(
4201 {1,
"MPTokenIssuanceSet",
"tesSUCCESS", txIDs[0], batchID},
4202 {2,
"MPTokenIssuanceSet",
"tesSUCCESS", txIDs[1], batchID},
4204 validateClosedLedger(env, testCases);
4215 env.fund(
XRP(10000), gw, alice, bob);
4218 env(trust(alice, gw[
"USD"](50)));
4222 gw, bob, {
"TrustlineAuthorize",
"TrustlineFreeze"}));
4225 auto const seq = env.
seq(gw);
4226 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4228 auto jv1 = trust(gw, gw[
"USD"](0), alice,
tfSetfAuth);
4229 jv1[sfDelegate] = bob.human();
4230 auto jv2 = trust(gw, gw[
"USD"](0), alice,
tfSetFreeze);
4231 jv2[sfDelegate] = bob.human();
4233 auto const [txIDs, batchID] = submitBatch(
4243 {1,
"TrustSet",
"tesSUCCESS", txIDs[0], batchID},
4244 {2,
"TrustSet",
"tesSUCCESS", txIDs[1], batchID},
4246 validateClosedLedger(env, testCases);
4255 env.fund(
XRP(10000), gw, alice, bob);
4258 env(trust(alice, gw[
"USD"](50)));
4262 gw, bob, {
"TrustlineAuthorize",
"TrustlineFreeze"}));
4265 auto const seq = env.
seq(gw);
4266 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4268 auto jv1 = trust(gw, gw[
"USD"](0), alice,
tfSetFreeze);
4269 jv1[sfDelegate] = bob.human();
4271 jv2[sfDelegate] = bob.human();
4273 auto const [txIDs, batchID] = submitBatch(
4284 {1,
"TrustSet",
"tesSUCCESS", txIDs[0], batchID},
4286 validateClosedLedger(env, testCases);
4296 testcase(
"Validate RPC response");
4298 using namespace jtx;
4299 Env env(*
this, features);
4302 env.
fund(
XRP(10000), alice, bob);
4307 auto const baseFee = env.
current()->fees().base;
4308 auto const aliceSeq = env.
seq(alice);
4309 auto jtx = env.
jt(pay(alice, bob,
XRP(1)));
4313 auto const jr = env.
rpc(
"submit",
strHex(s.
slice()))[jss::result];
4316 BEAST_EXPECT(jr.isMember(jss::account_sequence_available));
4318 jr[jss::account_sequence_available].asUInt() == aliceSeq + 1);
4319 BEAST_EXPECT(jr.isMember(jss::account_sequence_next));
4321 jr[jss::account_sequence_next].asUInt() == aliceSeq + 1);
4322 BEAST_EXPECT(jr.isMember(jss::open_ledger_cost));
4323 BEAST_EXPECT(jr[jss::open_ledger_cost] ==
to_string(baseFee));
4324 BEAST_EXPECT(jr.isMember(jss::validated_ledger_index));
4329 auto const baseFee = env.
current()->fees().base;
4330 auto const aliceSeq = env.
seq(alice);
4332 auto jtx = env.
jt(pay(alice, bob,
XRP(1)),
seq(aliceSeq));
4336 auto const jr = env.
rpc(
"submit",
strHex(s.
slice()))[jss::result];
4339 BEAST_EXPECT(jr.isMember(jss::account_sequence_available));
4341 jr[jss::account_sequence_available].asUInt() == aliceSeq + 1);
4342 BEAST_EXPECT(jr.isMember(jss::account_sequence_next));
4344 jr[jss::account_sequence_next].asUInt() == aliceSeq + 1);
4345 BEAST_EXPECT(jr.isMember(jss::open_ledger_cost));
4346 BEAST_EXPECT(jr[jss::open_ledger_cost] ==
to_string(baseFee));
4347 BEAST_EXPECT(jr.isMember(jss::validated_ledger_index));
4352 auto const baseFee = env.
current()->fees().base;
4353 auto const aliceSeq = env.
seq(alice);
4354 auto jtx = env.
jt(pay(alice, bob,
XRP(1)),
seq(aliceSeq + 1));
4358 auto const jr = env.
rpc(
"submit",
strHex(s.
slice()))[jss::result];
4361 BEAST_EXPECT(jr.isMember(jss::account_sequence_available));
4363 jr[jss::account_sequence_available].asUInt() == aliceSeq);
4364 BEAST_EXPECT(jr.isMember(jss::account_sequence_next));
4365 BEAST_EXPECT(jr[jss::account_sequence_next].asUInt() == aliceSeq);
4366 BEAST_EXPECT(jr.isMember(jss::open_ledger_cost));
4367 BEAST_EXPECT(jr[jss::open_ledger_cost] ==
to_string(baseFee));
4368 BEAST_EXPECT(jr.isMember(jss::validated_ledger_index));
4375 using namespace jtx;
4376 Env env(*
this, features);
4380 env.
fund(
XRP(10000), alice, bob, carol);
4391 auto const seq = env.
seq(alice);
4392 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4398 XRPAmount const txBaseFee = getBaseFee(jtx);
4404 auto const seq = env.
seq(alice);
4405 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4419 XRPAmount const txBaseFee = getBaseFee(jtx);
4425 auto const seq = env.
seq(alice);
4426 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4443 XRPAmount const txBaseFee = getBaseFee(jtx);
4449 auto const seq = env.
seq(alice);
4450 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4455 XRPAmount const txBaseFee = getBaseFee(jtx);
4456 BEAST_EXPECT(txBaseFee == batchFee);
4463 testEnable(features);
4464 testPreflight(features);
4465 testPreclaim(features);
4466 testBadRawTxn(features);
4467 testBadSequence(features);
4468 testBadOuterFee(features);
4469 testCalculateBaseFee(features);
4470 testAllOrNothing(features);
4471 testOnlyOne(features);
4472 testUntilFailure(features);
4473 testIndependent(features);
4474 testInnerSubmitRPC(features);
4475 testAccountActivation(features);
4476 testAccountSet(features);
4477 testAccountDelete(features);
4479 testObjectCreateSequence(features);
4480 testObjectCreateTicket(features);
4481 testObjectCreate3rdParty(features);
4482 testTickets(features);
4483 testSequenceOpenLedger(features);
4484 testTicketsOpenLedger(features);
4485 testObjectsOpenLedger(features);
4486 testPseudoTxn(features);
4487 testOpenLedger(features);
4488 testBatchTxQueue(features);
4489 testBatchNetworkOps(features);
4490 testBatchDelegate(features);
4491 testValidateRPCResponse(features);
4492 testBatchCalculateBaseFee(features);
4499 using namespace test::jtx;
4501 testWithFeats(sa - fixBatchInnerSigs);
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.
Json::Value getJson(JsonOptions options) const override
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 doTestInnerSubmitRPC(FeatureBitset features, bool withBatch)
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.