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;
63 BEAST_EXPECT(jrr[sfTransactionType.jsonName] == ledgerResult.
txType);
64 BEAST_EXPECT(jrr[jss::meta][sfTransactionResult.jsonName] == ledgerResult.
result);
65 BEAST_EXPECT(jrr[jss::meta][sfParentBatchID.jsonName] == batchID);
72 auto const transactions = jrr[jss::result][jss::ledger][jss::transactions];
73 BEAST_EXPECT(transactions.size() == ledgerResults.
size());
77 BEAST_EXPECT(txn[jss::hash].asString() == ledgerResult.txHash);
78 BEAST_EXPECT(txn.isMember(jss::metaData));
80 BEAST_EXPECT(txn[sfTransactionType.jsonName] == ledgerResult.txType);
81 BEAST_EXPECT(meta[sfTransactionResult.jsonName] == ledgerResult.result);
82 if (ledgerResult.batchID)
87 template <
typename... Args>
94 auto const ids = batchTxn.stx->getBatchTransactionIDs();
96 for (
auto const&
id : ids)
98 TxID const batchID = batchTxn.stx->getTransactionID();
114 auto& section = p->section(
"transaction_queue");
115 section.set(
"ledgers_in_queue",
"2");
116 section.set(
"minimum_queue_size",
"2");
117 section.set(
"min_ledgers_to_compute_size_limit",
"3");
118 section.set(
"max_ledger_counts_to_store",
"100");
119 section.set(
"retry_sequence_percent",
"25");
120 section.set(
"normal_consensus_increase_percent",
"0");
122 for (
auto const& [k, v] : extraTxQ)
133 auto const& view = *env.
current();
135 return toDrops(metrics.openLedgerFeeLevel, batchFee) + 1;
141 using namespace test::jtx;
144 bool const withInnerSigFix = features[fixBatchInnerSigs];
146 for (
bool const withBatch : {
true,
false})
148 testcase <<
"enabled: Batch " << (withBatch ?
"enabled" :
"disabled")
149 <<
", Inner Sig Fix: " << (withInnerSigFix ?
"enabled" :
"disabled");
151 auto const amend = withBatch ? features : features - featureBatch;
155 auto const alice =
Account(
"alice");
156 auto const bob =
Account(
"bob");
157 auto const carol =
Account(
"carol");
158 env.fund(
XRP(10000), alice, bob, carol);
163 auto const seq = env.
seq(alice);
192 using namespace test::jtx;
200 auto const alice =
Account(
"alice");
201 auto const bob =
Account(
"bob");
202 auto const carol =
Account(
"carol");
203 env.fund(
XRP(10000), alice, bob, carol);
215 auto const seq = env.
seq(alice);
223 auto const seq = env.
seq(alice);
231 auto const seq = env.
seq(alice);
241 auto const seq = env.
seq(alice);
249 auto const seq = env.
seq(alice);
260 auto const seq = env.
seq(alice);
279 auto const seq = env.
seq(alice);
280 auto jt = env.jtnofill(
292 auto const seq = env.
seq(alice);
305 auto const seq = env.
seq(alice);
308 auto jt = env.jtnofill(
319 auto const seq = env.
seq(alice);
321 auto jt = env.jt(
pay(alice, bob,
XRP(1)));
331 auto const seq = env.
seq(alice);
333 auto tx1 =
pay(alice, bob,
XRP(1));
336 tx1[sfSigners.jsonName][0U][sfSigner.jsonName][sfAccount.jsonName] = alice.human();
337 tx1[sfSigners.jsonName][0U][sfSigner.jsonName][sfSigningPubKey.jsonName] =
strHex(alice.pk());
338 tx1[sfSigners.jsonName][0U][sfSigner.jsonName][sfTxnSignature.jsonName] =
"DEADBEEF";
349 auto const seq = env.
seq(alice);
352 tx1[jss::SigningPubKey] =
strHex(alice.pk());
353 auto jt = env.jtnofill(
364 auto const seq = env.
seq(alice);
376 auto const seq = env.
seq(alice);
379 tx1[jss::Fee] =
to_string(env.current()->fees().base);
389 auto const seq = env.
seq(alice);
392 tx1[jss::Fee] =
"-1";
402 auto const seq = env.
seq(alice);
405 tx1[jss::Fee] =
"1.5";
406 env.set_parse_failure_expected(
true);
412 fail(
"Expected parse_error for fractional fee");
418 env.set_parse_failure_expected(
false);
424 auto const seq = env.
seq(alice);
427 tx1[jss::Sequence] =
seq + 1;
438 auto const seq = env.
seq(alice);
449 auto const seq = env.
seq(alice);
460 auto const seq = env.
seq(alice);
471 auto const seq = env.
seq(alice);
484 auto const seq = env.
seq(alice);
489 batch::sig(bob, carol, alice, bob, carol, alice, bob, carol, alice, alice),
496 auto const seq = env.
seq(alice);
508 auto const seq = env.
seq(alice);
521 auto const seq = env.
seq(alice);
533 auto const seq = env.
seq(alice);
545 auto const seq = env.
seq(alice);
546 auto const bobSeq = env.seq(bob);
548 auto jt = env.jtnofill(
556 jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName][sfAccount.jsonName] = bob.human();
557 jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName][sfSigningPubKey.jsonName] =
strHex(alice.pk());
558 jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName][sfTxnSignature.jsonName] =
567 auto const seq = env.
seq(alice);
584 using namespace test::jtx;
592 auto const alice =
Account(
"alice");
593 auto const bob =
Account(
"bob");
594 auto const carol =
Account(
"carol");
595 auto const dave =
Account(
"dave");
596 auto const elsa =
Account(
"elsa");
597 auto const frank =
Account(
"frank");
598 auto const phantom =
Account(
"phantom");
599 env.memoize(phantom);
601 env.fund(
XRP(10000), alice, bob, carol, dave, elsa, frank);
609 auto const seq = env.
seq(alice);
624 auto const seq = env.
seq(alice);
634 env(
signers(alice, 2, {{bob, 1}, {carol, 1}}));
637 env(
signers(bob, 2, {{carol, 1}, {dave, 1}, {elsa, 1}}));
642 auto const seq = env.
seq(alice);
654 auto const seq = env.
seq(alice);
659 batch::msig(bob, {carol, Account(
"dave", KeyType::ed25519)}),
668 auto const seq = env.
seq(alice);
680 auto const seq = env.
seq(alice);
692 auto const seq = env.
seq(alice);
706 auto const seq = env.
seq(alice);
710 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
711 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
712 batch::msig(bob, {carol, Reg{dave, davo}}),
719 auto const seq = env.seq(alice);
722 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
723 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
724 batch::msig(bob, {carol}),
731 auto const seq = env.seq(alice);
734 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
735 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
736 batch::msig(bob, {carol, dave}),
743 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, dave}),
759 auto const ledSeq = env.current()->seq();
760 auto const seq = env.seq(alice);
763 batch::inner(
pay(alice, phantom,
XRP(1000)), seq + 1),
764 batch::inner(
noop(phantom), ledSeq),
765 batch::sig(Reg{phantom, carol}),
772 auto const ledSeq = env.current()->seq();
773 auto const seq = env.seq(alice);
776 batch::inner(
pay(alice, bob,
XRP(1000)), seq + 1),
777 batch::inner(
noop(bob), ledSeq),
778 batch::sig(Reg{bob, carol}),
786 auto const seq = env.seq(alice);
789 batch::inner(
pay(alice, bob,
XRP(1)), seq + 1),
790 batch::inner(
pay(bob, alice,
XRP(2)), env.seq(bob)),
791 batch::sig(Reg{bob, carol}),
798 auto const seq = env.seq(alice);
801 batch::inner(
pay(alice, bob,
XRP(1)), seq + 1),
802 batch::inner(
pay(bob, alice,
XRP(2)), env.seq(bob)),
812 auto const seq = env.seq(alice);
815 batch::inner(
pay(alice, bob,
XRP(1)), seq + 1),
816 batch::inner(
pay(bob, alice,
XRP(2)), env.seq(bob)),
826 testcase(
"bad raw txn");
828 using namespace test::jtx;
833 auto const alice =
Account(
"alice");
834 auto const bob =
Account(
"bob");
836 env.fund(
XRP(10000), alice, bob);
840 auto const batchFee = batch::calcBatchFee(env, 1, 2);
841 auto const seq = env.
seq(alice);
843 tx1.removeMember(jss::TransactionType);
844 auto jt = env.jtnofill(
855 auto const batchFee = batch::calcBatchFee(env, 1, 2);
856 auto const seq = env.
seq(alice);
858 tx1.removeMember(jss::Account);
859 auto jt = env.jtnofill(
870 auto const batchFee = batch::calcBatchFee(env, 1, 2);
871 auto const seq = env.
seq(alice);
873 tx1.removeMember(jss::Sequence);
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::Fee);
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::SigningPubKey);
904 auto jt = env.jtnofill(
917 testcase(
"bad sequence");
919 using namespace test::jtx;
924 auto const alice =
Account(
"alice");
925 auto const bob =
Account(
"bob");
927 auto const USD = gw[
"USD"];
929 env.fund(
XRP(10000), alice, bob, gw);
931 env.trust(USD(1000), alice, bob);
932 env(pay(gw, alice, USD(100)));
933 env(pay(gw, bob, USD(100)));
941 auto const preAliceSeq = env.seq(alice);
942 auto const preAlice = env.balance(alice);
943 auto const preAliceUSD = env.balance(alice, USD.issue());
944 auto const preBobSeq = env.seq(bob);
945 auto const preBob = env.balance(bob);
946 auto const preBobUSD = env.balance(bob, USD.issue());
948 auto const batchFee = batch::calcBatchFee(env, 1, 2);
949 auto const [txIDs, batchID] = submitBatch(
962 validateClosedLedger(env, testCases);
969 validateClosedLedger(env, testCases);
973 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
974 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
975 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
976 BEAST_EXPECT(env.seq(bob) == preBobSeq);
977 BEAST_EXPECT(env.balance(bob) == preBob);
978 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
983 auto const preAliceSeq = env.seq(alice);
984 auto const preAlice = env.balance(alice);
985 auto const preAliceUSD = env.balance(alice, USD.issue());
986 auto const preBobSeq = env.seq(bob);
987 auto const preBob = env.balance(bob);
988 auto const preBobUSD = env.balance(bob, USD.issue());
990 auto const batchFee = batch::calcBatchFee(env, 1, 2);
991 auto const [txIDs, batchID] = submitBatch(
1004 validateClosedLedger(env, testCases);
1011 validateClosedLedger(env, testCases);
1015 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1016 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1017 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1018 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1019 BEAST_EXPECT(env.balance(bob) == preBob);
1020 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1025 auto const preAliceSeq = env.seq(alice);
1026 auto const preAlice = env.balance(alice);
1027 auto const preAliceUSD = env.balance(alice, USD.issue());
1028 auto const preBobSeq = env.seq(bob);
1029 auto const preBob = env.balance(bob);
1030 auto const preBobUSD = env.balance(bob, USD.issue());
1032 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1033 auto const [txIDs, batchID] = submitBatch(
1046 validateClosedLedger(env, testCases);
1053 validateClosedLedger(env, testCases);
1057 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1058 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1059 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1060 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1061 BEAST_EXPECT(env.balance(bob) == preBob);
1062 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1067 auto const preAliceSeq = env.seq(alice);
1068 auto const preAlice = env.balance(alice);
1069 auto const preAliceUSD = env.balance(alice, USD.issue());
1070 auto const preBobSeq = env.seq(bob);
1071 auto const preBob = env.balance(bob);
1072 auto const preBobUSD = env.balance(bob, USD.issue());
1074 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1075 auto const [txIDs, batchID] = submitBatch(
1088 validateClosedLedger(env, testCases);
1095 validateClosedLedger(env, testCases);
1099 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1100 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1101 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1102 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1103 BEAST_EXPECT(env.balance(bob) == preBob);
1104 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1109 auto const preAliceSeq = env.seq(alice);
1110 auto const preAlice = env.balance(alice);
1111 auto const preAliceUSD = env.balance(alice, USD.issue());
1112 auto const preBobSeq = env.seq(bob);
1113 auto const preBob = env.balance(bob);
1114 auto const preBobUSD = env.balance(bob, USD.issue());
1116 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1117 auto const [txIDs, batchID] = submitBatch(
1130 validateClosedLedger(env, testCases);
1137 validateClosedLedger(env, testCases);
1141 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1142 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1143 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1144 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1145 BEAST_EXPECT(env.balance(bob) == preBob);
1146 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1153 testcase(
"bad outer fee");
1155 using namespace test::jtx;
1162 auto const alice =
Account(
"alice");
1163 auto const bob =
Account(
"bob");
1164 env.fund(
XRP(10000), alice, bob);
1171 auto const batchFee = batch::calcBatchFee(env, 0, 1);
1172 auto const aliceSeq = env.seq(alice);
1184 auto const alice =
Account(
"alice");
1185 auto const bob =
Account(
"bob");
1186 auto const carol =
Account(
"carol");
1187 env.fund(
XRP(10000), alice, bob, carol);
1193 env(signers(alice, 2, {{bob, 1}, {carol, 1}}));
1197 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1198 auto const aliceSeq = env.seq(alice);
1211 auto const alice =
Account(
"alice");
1212 auto const bob =
Account(
"bob");
1213 auto const carol =
Account(
"carol");
1214 env.fund(
XRP(10000), alice, bob, carol);
1220 env(signers(alice, 2, {{bob, 1}, {carol, 1}}));
1224 auto const batchFee = batch::calcBatchFee(env, 2, 2);
1225 auto const aliceSeq = env.seq(alice);
1226 auto const bobSeq = env.seq(bob);
1240 auto const alice =
Account(
"alice");
1241 auto const bob =
Account(
"bob");
1242 auto const carol =
Account(
"carol");
1243 env.fund(
XRP(10000), alice, bob, carol);
1249 env(signers(alice, 2, {{bob, 1}, {carol, 1}}));
1252 env(signers(bob, 2, {{alice, 1}, {carol, 1}}));
1256 auto const batchFee = batch::calcBatchFee(env, 3, 2);
1257 auto const aliceSeq = env.seq(alice);
1258 auto const bobSeq = env.seq(bob);
1272 auto const alice =
Account(
"alice");
1273 auto const bob =
Account(
"bob");
1274 env.fund(
XRP(10000), alice, bob);
1281 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1282 auto const aliceSeq = env.seq(alice);
1283 auto const bobSeq = env.seq(bob);
1296 auto const alice =
Account(
"alice");
1297 auto const bob =
Account(
"bob");
1298 auto const gw =
Account(
"gw");
1299 auto const USD = gw[
"USD"];
1301 env.fund(
XRP(10000), alice, bob, gw);
1305 jv[jss::Account] = alice.human();
1308 jv[jss::TradingFee] = 0;
1309 jv[jss::TransactionType] = jss::AMMCreate;
1313 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1314 auto const seq = env.
seq(alice);
1326 testcase(
"calculate base fee");
1328 using namespace test::jtx;
1335 auto const alice =
Account(
"alice");
1336 auto const bob =
Account(
"bob");
1337 env.fund(
XRP(10000), alice, bob);
1340 auto const batchFee = batch::calcBatchFee(env, 0, 9);
1341 auto const aliceSeq = env.seq(alice);
1360 auto const alice =
Account(
"alice");
1361 auto const bob =
Account(
"bob");
1362 env.fund(
XRP(10000), alice, bob);
1365 auto const batchFee = batch::calcBatchFee(env, 0, 9);
1366 auto const aliceSeq = env.seq(alice);
1367 auto jt = env.jtnofill(
1382 return result.applied;
1390 auto const alice =
Account(
"alice");
1391 auto const bob =
Account(
"bob");
1392 env.fund(
XRP(10000), alice, bob);
1395 auto const aliceSeq = env.seq(alice);
1396 auto const batchFee = batch::calcBatchFee(env, 9, 2);
1400 batch::sig(bob, bob, bob, bob, bob, bob, bob, bob, bob, bob),
1409 auto const alice =
Account(
"alice");
1410 auto const bob =
Account(
"bob");
1411 env.fund(
XRP(10000), alice, bob);
1414 auto const batchFee = batch::calcBatchFee(env, 0, 9);
1415 auto const aliceSeq = env.seq(alice);
1416 auto jt = env.jtnofill(
1420 batch::sig(bob, bob, bob, bob, bob, bob, bob, bob, bob, bob));
1425 return result.applied;
1433 testcase(
"all or nothing");
1435 using namespace test::jtx;
1440 auto const alice =
Account(
"alice");
1441 auto const bob =
Account(
"bob");
1442 auto const gw =
Account(
"gw");
1443 auto const USD = gw[
"USD"];
1444 env.fund(
XRP(10000), alice, bob, gw);
1449 auto const preAlice = env.balance(alice);
1450 auto const preBob = env.balance(bob);
1452 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1453 auto const seq = env.
seq(alice);
1454 auto const [txIDs, batchID] = submitBatch(
1464 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1465 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1467 validateClosedLedger(env, testCases);
1470 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1473 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1474 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1479 auto const preAlice = env.balance(alice);
1480 auto const preBob = env.balance(bob);
1482 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1483 auto const seq = env.
seq(alice);
1485 auto const [txIDs, batchID] = submitBatch(
1497 validateClosedLedger(env, testCases);
1500 BEAST_EXPECT(env.seq(alice) ==
seq + 1);
1503 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1504 BEAST_EXPECT(env.balance(bob) == preBob);
1509 auto const preAlice = env.balance(alice);
1510 auto const preBob = env.balance(bob);
1512 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1513 auto const seq = env.
seq(alice);
1514 auto const [txIDs, batchID] = submitBatch(
1526 validateClosedLedger(env, testCases);
1529 BEAST_EXPECT(env.seq(alice) ==
seq + 1);
1532 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1533 BEAST_EXPECT(env.balance(bob) == preBob);
1538 auto const preAlice = env.balance(alice);
1539 auto const preBob = env.balance(bob);
1541 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1542 auto const seq = env.
seq(alice);
1543 auto const [txIDs, batchID] = submitBatch(
1555 validateClosedLedger(env, testCases);
1558 BEAST_EXPECT(env.seq(alice) ==
seq + 1);
1561 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1562 BEAST_EXPECT(env.balance(bob) == preBob);
1569 testcase(
"only one");
1571 using namespace test::jtx;
1576 auto const alice =
Account(
"alice");
1577 auto const bob =
Account(
"bob");
1578 auto const carol =
Account(
"carol");
1579 auto const dave =
Account(
"dave");
1580 auto const gw =
Account(
"gw");
1581 auto const USD = gw[
"USD"];
1582 env.fund(
XRP(10000), alice, bob, carol, dave, gw);
1587 auto const preAlice = env.balance(alice);
1588 auto const preBob = env.balance(bob);
1590 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1591 auto const seq = env.
seq(alice);
1592 auto const [txIDs, batchID] = submitBatch(
1606 {1,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[0], batchID},
1607 {2,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[1], batchID},
1608 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
1610 validateClosedLedger(env, testCases);
1613 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
1616 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1617 BEAST_EXPECT(env.balance(bob) == preBob);
1622 auto const preAlice = env.balance(alice);
1623 auto const preBob = env.balance(bob);
1625 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1626 auto const seq = env.
seq(alice);
1627 auto const [txIDs, batchID] = submitBatch(
1639 {1,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[0], batchID},
1640 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1642 validateClosedLedger(env, testCases);
1645 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1648 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
1649 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1654 auto const preAlice = env.balance(alice);
1655 auto const preBob = env.balance(bob);
1657 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1658 auto const seq = env.
seq(alice);
1659 auto const [txIDs, batchID] = submitBatch(
1671 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1673 validateClosedLedger(env, testCases);
1676 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1679 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
1680 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1685 auto const preAlice = env.balance(alice);
1686 auto const preBob = env.balance(bob);
1688 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1689 auto const seq = env.
seq(alice);
1690 auto const [txIDs, batchID] = submitBatch(
1702 {1,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1704 validateClosedLedger(env, testCases);
1707 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1710 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(1));
1711 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1716 auto const preAlice = env.balance(alice);
1717 auto const preBob = env.balance(bob);
1719 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1720 auto const seq = env.
seq(alice);
1721 auto const [txIDs, batchID] = submitBatch(
1733 {1,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1735 validateClosedLedger(env, testCases);
1738 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1741 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(1));
1742 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1747 auto const preAlice = env.balance(alice);
1748 auto const preBob = env.balance(bob);
1749 auto const preCarol = env.balance(carol);
1750 auto const seq = env.
seq(alice);
1751 auto const batchFee = batch::calcBatchFee(env, 0, 6);
1753 auto const [txIDs, batchID] = submitBatch(
1767 {1,
"OfferCreate",
"tecKILLED", txIDs[0], batchID},
1768 {2,
"OfferCreate",
"tecKILLED", txIDs[1], batchID},
1769 {3,
"OfferCreate",
"tecKILLED", txIDs[2], batchID},
1770 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
1772 validateClosedLedger(env, testCases);
1774 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(100) - batchFee);
1775 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(100));
1776 BEAST_EXPECT(env.balance(carol) == preCarol);
1783 testcase(
"until failure");
1785 using namespace test::jtx;
1790 auto const alice =
Account(
"alice");
1791 auto const bob =
Account(
"bob");
1792 auto const carol =
Account(
"carol");
1793 auto const dave =
Account(
"dave");
1794 auto const gw =
Account(
"gw");
1795 auto const USD = gw[
"USD"];
1796 env.fund(
XRP(10000), alice, bob, carol, dave, gw);
1801 auto const preAlice = env.balance(alice);
1802 auto const preBob = env.balance(bob);
1804 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1805 auto const seq = env.
seq(alice);
1806 auto const [txIDs, batchID] = submitBatch(
1819 {1,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[0], batchID},
1821 validateClosedLedger(env, testCases);
1824 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1827 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1828 BEAST_EXPECT(env.balance(bob) == preBob);
1833 auto const preAlice = env.balance(alice);
1834 auto const preBob = env.balance(bob);
1836 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1837 auto const seq = env.
seq(alice);
1838 auto const [txIDs, batchID] = submitBatch(
1850 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1851 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1852 {3,
"Payment",
"tesSUCCESS", txIDs[2], batchID},
1853 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
1855 validateClosedLedger(env, testCases);
1858 BEAST_EXPECT(env.seq(alice) ==
seq + 5);
1861 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(10) - batchFee);
1862 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(10));
1867 auto const preAlice = env.balance(alice);
1868 auto const preBob = env.balance(bob);
1870 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1871 auto const seq = env.
seq(alice);
1872 auto const [txIDs, batchID] = submitBatch(
1885 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1886 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1887 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
1889 validateClosedLedger(env, testCases);
1892 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
1895 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1896 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1901 auto const preAlice = env.balance(alice);
1902 auto const preBob = env.balance(bob);
1904 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1905 auto const seq = env.
seq(alice);
1906 auto const [txIDs, batchID] = submitBatch(
1919 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1920 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1922 validateClosedLedger(env, testCases);
1925 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1928 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1929 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1934 auto const preAlice = env.balance(alice);
1935 auto const preBob = env.balance(bob);
1937 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1938 auto const seq = env.
seq(alice);
1939 auto const [txIDs, batchID] = submitBatch(
1952 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1953 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1955 validateClosedLedger(env, testCases);
1958 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1961 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1962 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1967 auto const preAlice = env.balance(alice);
1968 auto const preBob = env.balance(bob);
1969 auto const preCarol = env.balance(carol);
1970 auto const seq = env.
seq(alice);
1971 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1972 auto const [txIDs, batchID] = submitBatch(
1984 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1985 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1986 {3,
"OfferCreate",
"tecKILLED", txIDs[2], batchID},
1988 validateClosedLedger(env, testCases);
1990 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(200) - batchFee);
1991 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(100));
1992 BEAST_EXPECT(env.balance(carol) == preCarol +
XRP(100));
1999 testcase(
"independent");
2001 using namespace test::jtx;
2006 auto const alice =
Account(
"alice");
2007 auto const bob =
Account(
"bob");
2008 auto const carol =
Account(
"carol");
2009 auto const gw =
Account(
"gw");
2010 auto const USD = gw[
"USD"];
2011 env.fund(
XRP(10000), alice, bob, carol, gw);
2016 auto const preAlice = env.balance(alice);
2017 auto const preBob = env.balance(bob);
2019 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2020 auto const seq = env.
seq(alice);
2021 auto const [txIDs, batchID] = submitBatch(
2035 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2036 {2,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[1], batchID},
2037 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
2038 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2040 validateClosedLedger(env, testCases);
2043 BEAST_EXPECT(env.seq(alice) ==
seq + 5);
2046 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(4) - batchFee);
2047 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(4));
2052 auto const preAlice = env.balance(alice);
2053 auto const preBob = env.balance(bob);
2055 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2056 auto const seq = env.
seq(alice);
2057 auto const [txIDs, batchID] = submitBatch(
2070 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2071 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2072 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
2073 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2075 validateClosedLedger(env, testCases);
2078 BEAST_EXPECT(env.seq(alice) ==
seq + 5);
2081 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(6) - batchFee);
2082 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(6));
2087 auto const preAlice = env.balance(alice);
2088 auto const preBob = env.balance(bob);
2090 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2091 auto const seq = env.
seq(alice);
2092 auto const [txIDs, batchID] = submitBatch(
2105 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2106 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2107 {3,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2109 validateClosedLedger(env, testCases);
2112 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
2115 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(6));
2116 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(6));
2121 auto const preAlice = env.balance(alice);
2122 auto const preBob = env.balance(bob);
2124 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2125 auto const seq = env.
seq(alice);
2126 auto const [txIDs, batchID] = submitBatch(
2139 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2140 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2141 {3,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2143 validateClosedLedger(env, testCases);
2146 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
2149 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(6));
2150 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(6));
2155 auto const preAlice = env.balance(alice);
2156 auto const preBob = env.balance(bob);
2157 auto const preCarol = env.balance(carol);
2158 auto const seq = env.
seq(alice);
2159 auto const batchFee = batch::calcBatchFee(env, 0, 3);
2160 auto const [txIDs, batchID] = submitBatch(
2171 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2172 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2173 {3,
"OfferCreate",
"tecKILLED", txIDs[2], batchID},
2175 validateClosedLedger(env, testCases);
2177 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(200) - batchFee);
2178 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(100));
2179 BEAST_EXPECT(env.balance(carol) == preCarol +
XRP(100));
2186 bool const withInnerSigFix = features[fixBatchInnerSigs];
2190 ss <<
"inner submit rpc: batch " << (withBatch ?
"enabled" :
"disabled")
2191 <<
", inner sig fix: " << (withInnerSigFix ?
"enabled" :
"disabled") <<
": ";
2195 auto const amend = withBatch ? features : features - featureBatch;
2197 using namespace test::jtx;
2201 if (!BEAST_EXPECT(amend[featureBatch] == withBatch))
2204 auto const alice =
Account(
"alice");
2205 auto const bob =
Account(
"bob");
2207 env.fund(
XRP(10000), alice, bob);
2210 auto submitAndValidate = [&](
std::string caseName,
2215 bool expectInvalidFlag =
false) {
2216 testcase << testName << caseName << (expectInvalidFlag ?
" - Expected to reach tx engine!" :
"");
2217 auto const jrr = env.rpc(
"submit",
strHex(
slice))[jss::result];
2218 auto const expected = withBatch ? expectedEnabled.value_or(
2219 "fails local checks: Malformed: Invalid inner batch "
2221 : expectedDisabled.value_or(
"fails local checks: Empty SigningPubKey.");
2222 if (expectInvalidFlag)
2225 jrr[jss::status] ==
"success" && jrr[jss::engine_result] ==
"temINVALID_FLAG",
2233 jrr[jss::status] ==
"error" && jrr[jss::error] ==
"invalidTransaction" &&
2234 jrr[jss::error_exception] == expected,
2249 txn[sfTxnSignature] =
"DEADBEEF";
2253 submitAndValidate(
"TxnSignature set", s.
slice(), __LINE__);
2263 txn[sfSigningPubKey] =
strHex(alice.pk());
2268 "SigningPubKey set", s.
slice(), __LINE__,
std::nullopt,
"fails local checks: Invalid signature.");
2283 "Signers set", s.
slice(), __LINE__,
std::nullopt,
"fails local checks: Invalid Signers array size.");
2288 auto const txn =
batch::inner(pay(alice, bob,
XRP(1)), env.seq(alice));
2289 auto const jt = env.jt(txn.getTxn());
2308 "No signing fields set",
2311 "fails local checks: Empty SigningPubKey.",
2312 "fails local checks: Empty SigningPubKey.",
2313 withBatch && !withInnerSigFix);
2322 STTx amendTx(ttAMENDMENT, [
seq = env.closed()->header().
seq + 1](
auto& obj) {
2323 obj.setAccountID(sfAccount, AccountID());
2324 obj.setFieldH256(sfAmendment, fixBatchInnerSigs);
2325 obj.setFieldU32(sfLedgerSequence, seq);
2326 obj.setFieldU32(sfFlags, tfInnerBatchTxn);
2333 "Pseudo-transaction",
2336 withInnerSigFix ?
"fails local checks: Empty SigningPubKey."
2337 :
"fails local checks: Cannot submit pseudo transactions.",
2338 "fails local checks: Empty SigningPubKey.");
2345 for (
bool const withBatch : {
true,
false})
2347 doTestInnerSubmitRPC(features, withBatch);
2354 testcase(
"account activation");
2356 using namespace test::jtx;
2361 auto const alice =
Account(
"alice");
2362 auto const bob =
Account(
"bob");
2363 env.fund(
XRP(10000), alice);
2367 auto const preAlice = env.balance(alice);
2368 auto const ledSeq = env.current()->seq();
2369 auto const seq = env.
seq(alice);
2370 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2371 auto const [txIDs, batchID] = submitBatch(
2382 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2383 {2,
"AccountSet",
"tesSUCCESS", txIDs[1], batchID},
2385 validateClosedLedger(env, testCases);
2388 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
2391 BEAST_EXPECT(env.seq(bob) == ledSeq + 1);
2394 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1000) - batchFee);
2395 BEAST_EXPECT(env.balance(bob) ==
XRP(1000));
2401 testcase(
"account set");
2403 using namespace test::jtx;
2408 auto const alice =
Account(
"alice");
2409 auto const bob =
Account(
"bob");
2410 env.fund(
XRP(10000), alice, bob);
2413 auto const preAlice = env.balance(alice);
2414 auto const preBob = env.balance(bob);
2416 auto const seq = env.
seq(alice);
2417 auto const batchFee = batch::calcBatchFee(env, 0, 2);
2421 auto const [txIDs, batchID] = submitBatch(
2431 {1,
"AccountSet",
"tesSUCCESS", txIDs[0], batchID},
2432 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2434 validateClosedLedger(env, testCases);
2438 BEAST_EXPECT(sle->getFieldVL(sfDomain) ==
Blob(
domain.begin(),
domain.end()));
2441 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
2444 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
2445 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
2451 testcase(
"account delete");
2453 using namespace test::jtx;
2460 auto const alice =
Account(
"alice");
2461 auto const bob =
Account(
"bob");
2462 env.fund(
XRP(10000), alice, bob);
2466 for (
int i = 0; i < 5; ++i)
2469 auto const preAlice = env.balance(alice);
2470 auto const preBob = env.balance(bob);
2472 auto const seq = env.
seq(alice);
2473 auto const batchFee = batch::calcBatchFee(env, 0, 2) + env.current()->fees().increment;
2474 auto const [txIDs, batchID] = submitBatch(
2486 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2487 {2,
"AccountDelete",
"tesSUCCESS", txIDs[1], batchID},
2489 validateClosedLedger(env, testCases);
2493 BEAST_EXPECT(env.balance(bob) == preBob + (preAlice - batchFee));
2500 auto const alice =
Account(
"alice");
2501 auto const bob =
Account(
"bob");
2502 env.fund(
XRP(10000), alice, bob);
2506 for (
int i = 0; i < 5; ++i)
2509 auto const preAlice = env.balance(alice);
2510 auto const preBob = env.balance(bob);
2512 env.trust(bob[
"USD"](1000), alice);
2515 auto const seq = env.
seq(alice);
2516 auto const batchFee = batch::calcBatchFee(env, 0, 2) + env.current()->fees().increment;
2517 auto const [txIDs, batchID] = submitBatch(
2529 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2530 {2,
"AccountDelete",
"tecHAS_OBLIGATIONS", txIDs[1], batchID},
2531 {3,
"Payment",
"tesSUCCESS", txIDs[2], batchID},
2533 validateClosedLedger(env, testCases);
2537 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
2544 auto const alice =
Account(
"alice");
2545 auto const bob =
Account(
"bob");
2546 env.fund(
XRP(10000), alice, bob);
2550 for (
int i = 0; i < 5; ++i)
2553 auto const preAlice = env.balance(alice);
2554 auto const preBob = env.balance(bob);
2556 auto const seq = env.
seq(alice);
2557 auto const batchFee = batch::calcBatchFee(env, 0, 2) + env.current()->fees().increment;
2558 auto const [txIDs, batchID] = submitBatch(
2571 validateClosedLedger(env, testCases);
2575 BEAST_EXPECT(env.balance(bob) == preBob);
2584 bool const lendingBatchEnabled =
2586 return disabled == ttLOAN_BROKER_SET;
2589 using namespace test::jtx;
2591 test::jtx::Env env{*
this, features | featureSingleAssetVault | featureLendingProtocol | featureMPTokensV1};
2593 Account const issuer{
"issuer"};
2596 Account const lender{
"lender"};
2598 Account const borrower{
"borrower"};
2602 env.fund(
XRP(100'000), issuer,
noripple(lender, borrower));
2610 auto const deposit = asset(50'000);
2611 auto const debtMaximumValue = asset(25'000).value();
2612 auto const coverDepositValue = asset(1000).value();
2614 auto [tx, vaultKeylet] = vault.create({.owner = lender, .asset = asset});
2617 BEAST_EXPECT(env.le(vaultKeylet));
2619 env(vault.deposit({.depositor = lender, .id = vaultKeylet.key, .amount = deposit}));
2625 using namespace loanBroker;
2626 env(
set(lender, vaultKeylet.key),
2628 debtMaximum(debtMaximumValue),
2632 env(coverDeposit(lender, brokerKeylet.key, coverDepositValue));
2638 using namespace loan;
2639 using namespace std::chrono_literals;
2641 auto const lenderSeq = env.seq(lender);
2642 auto const batchFee = batch::calcBatchFee(env, 0, 2);
2644 auto const loanKeylet =
keylet::loan(brokerKeylet.key, 1);
2646 auto const [txIDs, batchID] = submitBatch(
2652 set(lender, brokerKeylet.key, asset(1000).value()),
2654 sig(sfCounterpartySignature, borrower),
2659 batch::inner(pay(lender, loanKeylet.key,
STAmount{asset, asset(500).value()}), lenderSeq + 2));
2662 auto const [txIDs, batchID] = submitBatch(
2668 set(lender, brokerKeylet.key, asset(1000).value()),
2674 batch::inner(pay(lender, loanKeylet.key,
STAmount{asset, asset(500).value()}), lenderSeq + 2));
2677 auto const [txIDs, batchID] = submitBatch(
2683 set(lender, brokerKeylet.key, asset(1000).value()),
2685 counterparty(borrower.id()),
2690 batch::inner(pay(lender, loanKeylet.key,
STAmount{asset, asset(500).value()}), lenderSeq + 2));
2696 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2697 auto const [txIDs, batchID] = submitBatch(
2703 set(lender, brokerKeylet.key, asset(1000).value()),
2704 counterparty(borrower.id()),
2716 STAmount{asset, asset(500).value()}),
2721 BEAST_EXPECT(env.le(brokerKeylet));
2722 BEAST_EXPECT(!env.le(loanKeylet));
2727 auto const lenderSeq = env.seq(lender);
2728 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2729 auto const [txIDs, batchID] = submitBatch(
2735 set(lender, brokerKeylet.key, asset(1000).value()),
2736 counterparty(borrower.id()),
2745 BEAST_EXPECT(env.le(brokerKeylet));
2746 if (
auto const sleLoan = env.le(loanKeylet);
2747 lendingBatchEnabled ? BEAST_EXPECT(sleLoan) : !BEAST_EXPECT(!sleLoan))
2757 testcase(
"object create w/ sequence");
2759 using namespace test::jtx;
2764 auto const alice =
Account(
"alice");
2765 auto const bob =
Account(
"bob");
2766 auto const gw =
Account(
"gw");
2767 auto const USD = gw[
"USD"];
2769 env.fund(
XRP(10000), alice, bob, gw);
2772 env.trust(USD(1000), alice, bob);
2773 env(pay(gw, alice, USD(100)));
2774 env(pay(gw, bob, USD(100)));
2779 auto const aliceSeq = env.seq(alice);
2780 auto const bobSeq = env.seq(bob);
2781 auto const preAlice = env.balance(alice);
2782 auto const preBob = env.balance(bob);
2783 auto const preAliceUSD = env.balance(alice, USD.issue());
2784 auto const preBobUSD = env.balance(bob, USD.issue());
2786 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2787 uint256 const chkID{getCheckIndex(bob, env.seq(bob))};
2788 auto const [txIDs, batchID] = submitBatch(
2792 batch::inner(check::create(bob, alice, USD(10)), bobSeq),
2793 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq + 1),
2799 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
2800 {2,
"CheckCash",
"tesSUCCESS", txIDs[1], batchID},
2802 validateClosedLedger(env, testCases);
2805 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
2808 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
2811 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
2812 BEAST_EXPECT(env.balance(bob) == preBob);
2815 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD + USD(10));
2816 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10));
2824 auto const aliceSeq = env.seq(alice);
2825 auto const bobSeq = env.seq(bob);
2826 auto const preAlice = env.balance(alice);
2827 auto const preBob = env.balance(bob);
2828 auto const preAliceUSD = env.balance(alice, USD.issue());
2829 auto const preBobUSD = env.balance(bob, USD.issue());
2831 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2832 uint256 const chkID{getCheckIndex(bob, env.seq(bob))};
2833 auto const [txIDs, batchID] = submitBatch(
2838 batch::inner(check::create(bob, alice, USD(10)), bobSeq),
2839 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq + 1),
2845 {1,
"CheckCreate",
"tecDST_TAG_NEEDED", txIDs[0], batchID},
2846 {2,
"CheckCash",
"tecNO_ENTRY", txIDs[1], batchID},
2848 validateClosedLedger(env, testCases);
2851 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
2854 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
2857 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
2858 BEAST_EXPECT(env.balance(bob) == preBob);
2861 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
2862 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
2869 testcase(
"object create w/ ticket");
2871 using namespace test::jtx;
2876 auto const alice =
Account(
"alice");
2877 auto const bob =
Account(
"bob");
2878 auto const gw =
Account(
"gw");
2879 auto const USD = gw[
"USD"];
2881 env.fund(
XRP(10000), alice, bob, gw);
2884 env.trust(USD(1000), alice, bob);
2885 env(pay(gw, alice, USD(100)));
2886 env(pay(gw, bob, USD(100)));
2889 auto const aliceSeq = env.seq(alice);
2890 auto const bobSeq = env.seq(bob);
2891 auto const preAlice = env.balance(alice);
2892 auto const preBob = env.balance(bob);
2893 auto const preAliceUSD = env.balance(alice, USD.issue());
2894 auto const preBobUSD = env.balance(bob, USD.issue());
2896 auto const batchFee = batch::calcBatchFee(env, 1, 3);
2897 uint256 const chkID{getCheckIndex(bob, bobSeq + 1)};
2898 auto const [txIDs, batchID] = submitBatch(
2903 batch::inner(check::create(bob, alice, USD(10)), 0, bobSeq + 1),
2904 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq + 1),
2910 {1,
"TicketCreate",
"tesSUCCESS", txIDs[0], batchID},
2911 {2,
"CheckCreate",
"tesSUCCESS", txIDs[1], batchID},
2912 {3,
"CheckCash",
"tesSUCCESS", txIDs[2], batchID},
2914 validateClosedLedger(env, testCases);
2916 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
2917 BEAST_EXPECT(env.seq(bob) == bobSeq + 10 + 1);
2918 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
2919 BEAST_EXPECT(env.balance(bob) == preBob);
2920 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD + USD(10));
2921 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10));
2927 testcase(
"object create w/ 3rd party");
2929 using namespace test::jtx;
2934 auto const alice =
Account(
"alice");
2935 auto const bob =
Account(
"bob");
2936 auto const carol =
Account(
"carol");
2937 auto const gw =
Account(
"gw");
2938 auto const USD = gw[
"USD"];
2940 env.fund(
XRP(10000), alice, bob, carol, gw);
2943 env.trust(USD(1000), alice, bob);
2944 env(pay(gw, alice, USD(100)));
2945 env(pay(gw, bob, USD(100)));
2948 auto const aliceSeq = env.seq(alice);
2949 auto const bobSeq = env.seq(bob);
2950 auto const carolSeq = env.seq(carol);
2951 auto const preAlice = env.balance(alice);
2952 auto const preBob = env.balance(bob);
2953 auto const preCarol = env.balance(carol);
2954 auto const preAliceUSD = env.balance(alice, USD.issue());
2955 auto const preBobUSD = env.balance(bob, USD.issue());
2957 auto const batchFee = batch::calcBatchFee(env, 2, 2);
2958 uint256 const chkID{getCheckIndex(bob, env.seq(bob))};
2959 auto const [txIDs, batchID] = submitBatch(
2963 batch::inner(check::create(bob, alice, USD(10)), bobSeq),
2964 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq),
2970 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
2971 {2,
"CheckCash",
"tesSUCCESS", txIDs[1], batchID},
2973 validateClosedLedger(env, testCases);
2975 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
2976 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
2977 BEAST_EXPECT(env.seq(carol) == carolSeq + 1);
2978 BEAST_EXPECT(env.balance(alice) == preAlice);
2979 BEAST_EXPECT(env.balance(bob) == preBob);
2980 BEAST_EXPECT(env.balance(carol) == preCarol - batchFee);
2981 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD + USD(10));
2982 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10));
2989 testcase(
"tickets outer");
2991 using namespace test::jtx;
2996 auto const alice =
Account(
"alice");
2997 auto const bob =
Account(
"bob");
2999 env.fund(
XRP(10000), alice, bob);
3003 env(ticket::create(alice, 10));
3006 auto const aliceSeq = env.seq(alice);
3007 auto const preAlice = env.balance(alice);
3008 auto const preBob = env.balance(bob);
3010 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3011 auto const [txIDs, batchID] = submitBatch(
3022 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3023 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3025 validateClosedLedger(env, testCases);
3029 BEAST_EXPECT(sle->getFieldU32(sfOwnerCount) == 9);
3030 BEAST_EXPECT(sle->getFieldU32(sfTicketCount) == 9);
3032 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
3033 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3034 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3038 testcase(
"tickets inner");
3040 using namespace test::jtx;
3045 auto const alice =
Account(
"alice");
3046 auto const bob =
Account(
"bob");
3048 env.fund(
XRP(10000), alice, bob);
3052 env(ticket::create(alice, 10));
3055 auto const aliceSeq = env.seq(alice);
3056 auto const preAlice = env.balance(alice);
3057 auto const preBob = env.balance(bob);
3059 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3060 auto const [txIDs, batchID] = submitBatch(
3070 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3071 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3073 validateClosedLedger(env, testCases);
3077 BEAST_EXPECT(sle->getFieldU32(sfOwnerCount) == 8);
3078 BEAST_EXPECT(sle->getFieldU32(sfTicketCount) == 8);
3080 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
3081 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3082 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3086 testcase(
"tickets outer inner");
3088 using namespace test::jtx;
3093 auto const alice =
Account(
"alice");
3094 auto const bob =
Account(
"bob");
3096 env.fund(
XRP(10000), alice, bob);
3100 env(ticket::create(alice, 10));
3103 auto const aliceSeq = env.seq(alice);
3104 auto const preAlice = env.balance(alice);
3105 auto const preBob = env.balance(bob);
3107 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3108 auto const [txIDs, batchID] = submitBatch(
3119 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3120 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3122 validateClosedLedger(env, testCases);
3126 BEAST_EXPECT(sle->getFieldU32(sfOwnerCount) == 8);
3127 BEAST_EXPECT(sle->getFieldU32(sfTicketCount) == 8);
3129 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
3130 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3131 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3138 testcase(
"sequence open ledger");
3140 using namespace test::jtx;
3143 auto const alice =
Account(
"alice");
3144 auto const bob =
Account(
"bob");
3145 auto const carol =
Account(
"carol");
3155 env.fund(
XRP(10000), alice, bob, carol);
3158 auto const aliceSeq = env.seq(alice);
3159 auto const carolSeq = env.seq(carol);
3162 auto const noopTxn = env.jt(
noop(alice),
seq(aliceSeq + 2));
3163 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3167 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3168 auto const [txIDs, batchID] = submitBatch(
3180 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3181 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3183 validateClosedLedger(env, testCases);
3190 {0,
"AccountSet",
"tesSUCCESS", noopTxnID,
std::nullopt},
3192 validateClosedLedger(env, testCases);
3202 env.fund(
XRP(10000), alice, bob);
3205 auto const aliceSeq = env.seq(alice);
3208 auto const noopTxn = env.jt(
noop(alice),
seq(aliceSeq + 1));
3212 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3213 auto const [txIDs, batchID] = submitBatch(
3224 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3225 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3227 validateClosedLedger(env, testCases);
3234 validateClosedLedger(env, testCases);
3244 env.fund(
XRP(10000), alice, bob);
3247 auto const aliceSeq = env.seq(alice);
3248 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3249 auto const [txIDs, batchID] = submitBatch(
3256 auto const noopTxn = env.jt(
noop(alice),
seq(aliceSeq + 1));
3257 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3264 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3265 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3267 validateClosedLedger(env, testCases);
3274 validateClosedLedger(env, testCases);
3281 env.fund(
XRP(10000), alice, bob, carol);
3284 auto const aliceSeq = env.seq(alice);
3285 auto const carolSeq = env.seq(carol);
3288 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3289 auto const [txIDs, batchID] = submitBatch(
3298 auto const noopTxn = env.jt(
noop(carol),
seq(carolSeq));
3299 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3305 {0,
"AccountSet",
"tesSUCCESS", noopTxnID,
std::nullopt},
3307 {2,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3308 {3,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3310 validateClosedLedger(env, testCases);
3317 validateClosedLedger(env, testCases);
3325 testcase(
"tickets open ledger");
3327 using namespace test::jtx;
3330 auto const alice =
Account(
"alice");
3331 auto const bob =
Account(
"bob");
3339 env.fund(
XRP(10000), alice, bob);
3343 env(ticket::create(alice, 10));
3346 auto const aliceSeq = env.seq(alice);
3349 auto const noopTxn = env.jt(
noop(alice),
ticket::use(aliceTicketSeq + 1));
3350 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3354 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3355 auto const [txIDs, batchID] = submitBatch(
3367 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3368 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3370 validateClosedLedger(env, testCases);
3377 validateClosedLedger(env, testCases);
3387 env.fund(
XRP(10000), alice, bob);
3391 env(ticket::create(alice, 10));
3394 auto const aliceSeq = env.seq(alice);
3397 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3398 auto const [txIDs, batchID] = submitBatch(
3407 auto const noopTxn = env.jt(
noop(alice),
ticket::use(aliceTicketSeq + 1));
3414 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3415 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3417 validateClosedLedger(env, testCases);
3424 validateClosedLedger(env, testCases);
3432 testcase(
"objects open ledger");
3434 using namespace test::jtx;
3437 auto const alice =
Account(
"alice");
3438 auto const bob =
Account(
"bob");
3448 env.fund(
XRP(10000), alice, bob);
3452 env(ticket::create(alice, 10));
3455 auto const aliceSeq = env.seq(alice);
3458 uint256 const chkID{getCheckIndex(alice, aliceSeq)};
3459 auto const objTxn = env.jt(check::cash(bob, chkID,
XRP(10)));
3460 auto const objTxnID =
to_string(objTxn.stx->getTransactionID());
3464 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3465 auto const [txIDs, batchID] = submitBatch(
3477 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
3478 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3479 {3,
"CheckCash",
"tesSUCCESS", objTxnID,
std::nullopt},
3481 validateClosedLedger(env, testCases);
3488 validateClosedLedger(env, testCases);
3495 env.fund(
XRP(10000), alice, bob);
3499 env(ticket::create(alice, 10));
3502 auto const aliceSeq = env.seq(alice);
3503 auto const bobSeq = env.seq(bob);
3506 uint256 const chkID{getCheckIndex(alice, aliceSeq)};
3507 auto const objTxn = env.jt(check::create(alice, bob,
XRP(10)));
3508 auto const objTxnID =
to_string(objTxn.stx->getTransactionID());
3512 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3513 auto const [txIDs, batchID] = submitBatch(
3525 {0,
"CheckCreate",
"tesSUCCESS", objTxnID,
std::nullopt},
3527 {2,
"CheckCash",
"tesSUCCESS", txIDs[0], batchID},
3528 {3,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3530 validateClosedLedger(env, testCases);
3542 env.fund(
XRP(10000), alice, bob);
3546 env(ticket::create(alice, 10));
3549 auto const aliceSeq = env.seq(alice);
3552 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3553 uint256 const chkID{getCheckIndex(alice, aliceSeq)};
3554 auto const [txIDs, batchID] = submitBatch(
3563 auto const objTxn = env.jt(check::cash(bob, chkID,
XRP(10)));
3564 auto const objTxnID =
to_string(objTxn.stx->getTransactionID());
3571 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
3572 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3573 {3,
"CheckCash",
"tesSUCCESS", objTxnID,
std::nullopt},
3575 validateClosedLedger(env, testCases);
3583 testcase(
"pseudo txn with tfInnerBatchTxn");
3585 using namespace test::jtx;
3590 auto const alice =
Account(
"alice");
3591 auto const bob =
Account(
"bob");
3592 env.fund(
XRP(10000), alice, bob);
3595 STTx const stx =
STTx(ttAMENDMENT, [&](
auto& obj) {
3596 obj.setAccountID(sfAccount,
AccountID());
3597 obj.setFieldH256(sfAmendment,
uint256(2));
3598 obj.setFieldU32(sfLedgerSequence, env.seq(alice));
3605 BEAST_EXPECT(reason ==
"Cannot submit pseudo transactions.");
3609 return result.applied;
3616 testcase(
"batch open ledger");
3624 using namespace test::jtx;
3628 XRPAmount const baseFee = env.current()->fees().base;
3630 auto const alice =
Account(
"alice");
3631 auto const bob =
Account(
"bob");
3633 env.fund(
XRP(10000), alice, bob);
3639 auto const aliceSeq = env.seq(alice);
3640 auto const preAlice = env.balance(alice);
3641 auto const preBob = env.balance(bob);
3642 auto const bobSeq = env.seq(bob);
3645 auto const payTxn1 = env.jt(pay(alice, bob,
XRP(10)),
seq(aliceSeq));
3646 auto const payTxn1ID =
to_string(payTxn1.stx->getTransactionID());
3650 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3651 auto const [txIDs, batchID] = submitBatch(
3660 auto const payTxn2 = env.jt(pay(bob, alice,
XRP(5)),
seq(bobSeq + 1));
3661 auto const payTxn2ID =
to_string(payTxn2.stx->getTransactionID());
3668 {2,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3669 {3,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3671 validateClosedLedger(env, testCases);
3679 validateClosedLedger(env, testCases);
3683 BEAST_EXPECT(env.seq(alice) == aliceSeq + 3);
3686 BEAST_EXPECT(env.seq(bob) == bobSeq + 2);
3689 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(10) - batchFee - baseFee);
3690 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(10) - baseFee);
3696 testcase(
"batch tx queue");
3698 using namespace test::jtx;
3705 makeSmallQueueConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}),
3710 auto alice =
Account(
"alice");
3712 auto carol =
Account(
"carol");
3716 env.close(env.now() + 5s, 10000ms);
3718 env.close(env.now() + 5s, 10000ms);
3729 auto const aliceSeq = env.seq(alice);
3730 auto const bobSeq = env.seq(bob);
3731 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3746 env(batch::outer(alice, aliceSeq, openLedgerFee(env, batchFee),
tfAllOrNothing),
3761 makeSmallQueueConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}),
3766 auto alice =
Account(
"alice");
3768 auto carol =
Account(
"carol");
3772 env.close(env.now() + 5s, 10000ms);
3774 env.close(env.now() + 5s, 10000ms);
3781 auto const aliceSeq = env.seq(alice);
3782 auto const bobSeq = env.seq(bob);
3783 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3804 testcase(
"batch network ops");
3806 using namespace test::jtx;
3811 auto alice =
Account(
"alice");
3813 env.
fund(
XRP(10000), alice, bob);
3821 return jt.stx->getTransactionID();
3831 return transaction->getID();
3852 testcase(
"batch delegate");
3854 using namespace test::jtx;
3861 auto const alice =
Account(
"alice");
3862 auto const bob =
Account(
"bob");
3863 auto const gw =
Account(
"gw");
3864 auto const USD = gw[
"USD"];
3865 env.fund(
XRP(10000), alice, bob, gw);
3868 env(delegate::set(alice, bob, {
"Payment"}));
3871 auto const preAlice = env.balance(alice);
3872 auto const preBob = env.balance(bob);
3874 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3875 auto const seq = env.
seq(alice);
3878 tx[jss::Delegate] = bob.human();
3879 auto const [txIDs, batchID] = submitBatch(
3889 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3890 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3892 validateClosedLedger(env, testCases);
3895 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
3898 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3899 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3906 auto const alice =
Account(
"alice");
3907 auto const bob =
Account(
"bob");
3908 auto const carol =
Account(
"carol");
3909 auto const gw =
Account(
"gw");
3910 auto const USD = gw[
"USD"];
3911 env.fund(
XRP(10000), alice, bob, carol, gw);
3914 env(delegate::set(bob, carol, {
"Payment"}));
3917 auto const preAlice = env.balance(alice);
3918 auto const preBob = env.balance(bob);
3919 auto const preCarol = env.balance(carol);
3921 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3922 auto const aliceSeq = env.seq(alice);
3923 auto const bobSeq = env.seq(bob);
3926 tx[jss::Delegate] = carol.human();
3927 auto const [txIDs, batchID] = submitBatch(
3938 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3939 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3941 validateClosedLedger(env, testCases);
3943 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
3944 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
3945 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
3946 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
3949 BEAST_EXPECT(env.balance(carol) == preCarol);
3958 auto const alice =
Account(
"alice");
3959 auto const bob =
Account(
"bob");
3960 auto const gw =
Account(
"gw");
3961 auto const USD = gw[
"USD"];
3962 env.fund(
XRP(10000), alice, bob, gw);
3965 env(delegate::set(alice, bob, {
"AccountDomainSet"}));
3968 auto const preAlice = env.balance(alice);
3969 auto const preBob = env.balance(bob);
3971 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3972 auto const seq = env.
seq(alice);
3977 tx[jss::Delegate] = bob.human();
3978 auto const [txIDs, batchID] = submitBatch(
3988 {1,
"AccountSet",
"tesSUCCESS", txIDs[0], batchID},
3989 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3991 validateClosedLedger(env, testCases);
3994 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
3997 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(2) - batchFee);
3998 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(2));
4008 env.fund(
XRP(100000), alice, bob);
4011 auto const mptID =
makeMptID(env.seq(alice), alice);
4012 MPTTester mpt(env, alice, {.fund =
false});
4018 env(delegate::set(alice, bob, {
"MPTokenIssuanceLock",
"MPTokenIssuanceUnlock"}));
4021 auto const seq = env.
seq(alice);
4022 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4025 jv1[sfTransactionType] = jss::MPTokenIssuanceSet;
4026 jv1[sfAccount] = alice.human();
4027 jv1[sfDelegate] = bob.human();
4028 jv1[sfSequence] =
seq + 1;
4029 jv1[sfMPTokenIssuanceID] =
to_string(mptID);
4033 jv2[sfTransactionType] = jss::MPTokenIssuanceSet;
4034 jv2[sfAccount] = alice.human();
4035 jv2[sfDelegate] = bob.human();
4036 jv2[sfSequence] =
seq + 2;
4037 jv2[sfMPTokenIssuanceID] =
to_string(mptID);
4040 auto const [txIDs, batchID] = submitBatch(
4050 {1,
"MPTokenIssuanceSet",
"tesSUCCESS", txIDs[0], batchID},
4051 {2,
"MPTokenIssuanceSet",
"tesSUCCESS", txIDs[1], batchID},
4053 validateClosedLedger(env, testCases);
4064 env.fund(
XRP(10000), gw, alice, bob);
4067 env(trust(alice, gw[
"USD"](50)));
4070 env(delegate::set(gw, bob, {
"TrustlineAuthorize",
"TrustlineFreeze"}));
4073 auto const seq = env.
seq(gw);
4074 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4076 auto jv1 = trust(gw, gw[
"USD"](0), alice,
tfSetfAuth);
4077 jv1[sfDelegate] = bob.human();
4078 auto jv2 = trust(gw, gw[
"USD"](0), alice,
tfSetFreeze);
4079 jv2[sfDelegate] = bob.human();
4081 auto const [txIDs, batchID] = submitBatch(
4091 {1,
"TrustSet",
"tesSUCCESS", txIDs[0], batchID},
4092 {2,
"TrustSet",
"tesSUCCESS", txIDs[1], batchID},
4094 validateClosedLedger(env, testCases);
4103 env.fund(
XRP(10000), gw, alice, bob);
4106 env(trust(alice, gw[
"USD"](50)));
4109 env(delegate::set(gw, bob, {
"TrustlineAuthorize",
"TrustlineFreeze"}));
4112 auto const seq = env.
seq(gw);
4113 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4115 auto jv1 = trust(gw, gw[
"USD"](0), alice,
tfSetFreeze);
4116 jv1[sfDelegate] = bob.human();
4118 jv2[sfDelegate] = bob.human();
4120 auto const [txIDs, batchID] = submitBatch(
4131 {1,
"TrustSet",
"tesSUCCESS", txIDs[0], batchID},
4133 validateClosedLedger(env, testCases);
4143 testcase(
"Validate RPC response");
4145 using namespace jtx;
4146 Env env(*
this, features);
4149 env.
fund(
XRP(10000), alice, bob);
4154 auto const baseFee = env.
current()->fees().base;
4155 auto const aliceSeq = env.
seq(alice);
4156 auto jtx = env.
jt(pay(alice, bob,
XRP(1)));
4160 auto const jr = env.
rpc(
"submit",
strHex(s.
slice()))[jss::result];
4163 BEAST_EXPECT(jr.isMember(jss::account_sequence_available));
4164 BEAST_EXPECT(jr[jss::account_sequence_available].asUInt() == aliceSeq + 1);
4165 BEAST_EXPECT(jr.isMember(jss::account_sequence_next));
4166 BEAST_EXPECT(jr[jss::account_sequence_next].asUInt() == aliceSeq + 1);
4167 BEAST_EXPECT(jr.isMember(jss::open_ledger_cost));
4168 BEAST_EXPECT(jr[jss::open_ledger_cost] ==
to_string(baseFee));
4169 BEAST_EXPECT(jr.isMember(jss::validated_ledger_index));
4174 auto const baseFee = env.
current()->fees().base;
4175 auto const aliceSeq = env.
seq(alice);
4177 auto jtx = env.
jt(pay(alice, bob,
XRP(1)),
seq(aliceSeq));
4181 auto const jr = env.
rpc(
"submit",
strHex(s.
slice()))[jss::result];
4184 BEAST_EXPECT(jr.isMember(jss::account_sequence_available));
4185 BEAST_EXPECT(jr[jss::account_sequence_available].asUInt() == aliceSeq + 1);
4186 BEAST_EXPECT(jr.isMember(jss::account_sequence_next));
4187 BEAST_EXPECT(jr[jss::account_sequence_next].asUInt() == aliceSeq + 1);
4188 BEAST_EXPECT(jr.isMember(jss::open_ledger_cost));
4189 BEAST_EXPECT(jr[jss::open_ledger_cost] ==
to_string(baseFee));
4190 BEAST_EXPECT(jr.isMember(jss::validated_ledger_index));
4195 auto const baseFee = env.
current()->fees().base;
4196 auto const aliceSeq = env.
seq(alice);
4197 auto jtx = env.
jt(pay(alice, bob,
XRP(1)),
seq(aliceSeq + 1));
4201 auto const jr = env.
rpc(
"submit",
strHex(s.
slice()))[jss::result];
4204 BEAST_EXPECT(jr.isMember(jss::account_sequence_available));
4205 BEAST_EXPECT(jr[jss::account_sequence_available].asUInt() == aliceSeq);
4206 BEAST_EXPECT(jr.isMember(jss::account_sequence_next));
4207 BEAST_EXPECT(jr[jss::account_sequence_next].asUInt() == aliceSeq);
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));
4217 using namespace jtx;
4218 Env env(*
this, features);
4222 env.
fund(
XRP(10000), alice, bob, carol);
4233 auto const seq = env.
seq(alice);
4234 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4239 XRPAmount const txBaseFee = getBaseFee(jtx);
4245 auto const seq = env.
seq(alice);
4246 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4260 XRPAmount const txBaseFee = getBaseFee(jtx);
4266 auto const seq = env.
seq(alice);
4267 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4273 batch::sig(bob, carol, alice, bob, carol, alice, bob, carol, alice, alice));
4274 XRPAmount const txBaseFee = getBaseFee(jtx);
4280 auto const seq = env.
seq(alice);
4281 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4286 XRPAmount const txBaseFee = getBaseFee(jtx);
4287 BEAST_EXPECT(txBaseFee == batchFee);
4294 testEnable(features);
4295 testPreflight(features);
4296 testPreclaim(features);
4297 testBadRawTxn(features);
4298 testBadSequence(features);
4299 testBadOuterFee(features);
4300 testCalculateBaseFee(features);
4301 testAllOrNothing(features);
4302 testOnlyOne(features);
4303 testUntilFailure(features);
4304 testIndependent(features);
4305 testInnerSubmitRPC(features);
4306 testAccountActivation(features);
4307 testAccountSet(features);
4308 testAccountDelete(features);
4310 testObjectCreateSequence(features);
4311 testObjectCreateTicket(features);
4312 testObjectCreate3rdParty(features);
4313 testTickets(features);
4314 testSequenceOpenLedger(features);
4315 testTicketsOpenLedger(features);
4316 testObjectsOpenLedger(features);
4317 testPseudoTxn(features);
4318 testOpenLedger(features);
4319 testBatchTxQueue(features);
4320 testBatchNetworkOps(features);
4321 testBatchDelegate(features);
4322 testValidateRPCResponse(features);
4323 testBatchCalculateBaseFee(features);
4330 using namespace test::jtx;
4332 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.
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
virtual NetworkOPs & getOPs()=0
virtual HashRouter & getHashRouter()=0
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 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(), std::source_location const location=std::source_location::current())
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.
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.