2#include <test/jtx/TestHelpers.h>
3#include <test/jtx/utility.h>
5#include <xrpld/app/misc/Transaction.h>
7#include <xrpl/core/HashRouter.h>
8#include <xrpl/protocol/Batch.h>
9#include <xrpl/protocol/Feature.h>
10#include <xrpl/protocol/STParsedJSON.h>
11#include <xrpl/protocol/Sign.h>
12#include <xrpl/protocol/TxFlags.h>
13#include <xrpl/protocol/jss.h>
14#include <xrpl/server/NetworkOPs.h>
15#include <xrpl/tx/apply.h>
16#include <xrpl/tx/transactors/system/Batch.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();
97 for (
auto const&
id : ids)
99 TxID const batchID = batchTxn.stx->getTransactionID();
115 auto& section = p->section(
"transaction_queue");
116 section.set(
"ledgers_in_queue",
"2");
117 section.set(
"minimum_queue_size",
"2");
118 section.set(
"min_ledgers_to_compute_size_limit",
"3");
119 section.set(
"max_ledger_counts_to_store",
"100");
120 section.set(
"retry_sequence_percent",
"25");
121 section.set(
"normal_consensus_increase_percent",
"0");
123 for (
auto const& [k, v] : extraTxQ)
134 auto const& view = *env.
current();
136 return toDrops(metrics.openLedgerFeeLevel, batchFee) + 1;
142 using namespace test::jtx;
145 bool const withInnerSigFix = features[fixBatchInnerSigs];
147 for (
bool const withBatch : {
true,
false})
149 testcase <<
"enabled: Batch " << (withBatch ?
"enabled" :
"disabled")
150 <<
", Inner Sig Fix: " << (withInnerSigFix ?
"enabled" :
"disabled");
152 auto const amend = withBatch ? features : features - featureBatch;
156 auto const alice =
Account(
"alice");
157 auto const bob =
Account(
"bob");
158 auto const carol =
Account(
"carol");
159 env.fund(
XRP(10000), alice, bob, carol);
164 auto const seq = env.
seq(alice);
193 using namespace test::jtx;
201 auto const alice =
Account(
"alice");
202 auto const bob =
Account(
"bob");
203 auto const carol =
Account(
"carol");
204 env.fund(
XRP(10000), alice, bob, carol);
216 auto const seq = env.
seq(alice);
224 auto const seq = env.
seq(alice);
232 auto const seq = env.
seq(alice);
235 txflags(tfAllOrNothing | tfOnlyOne),
242 auto const seq = env.
seq(alice);
250 auto const seq = env.
seq(alice);
261 auto const seq = env.
seq(alice);
280 auto const seq = env.
seq(alice);
281 auto jt = env.jtnofill(
282 batch::outer(alice, env.seq(alice), batchFee, tfAllOrNothing),
293 auto const seq = env.
seq(alice);
306 auto const seq = env.
seq(alice);
309 auto jt = env.jtnofill(
320 auto const seq = env.
seq(alice);
322 auto jt = env.jt(
pay(alice, bob,
XRP(1)));
332 auto const seq = env.
seq(alice);
334 auto tx1 =
pay(alice, bob,
XRP(1));
337 tx1[sfSigners.jsonName][0U][sfSigner.jsonName][sfAccount.jsonName] = alice.human();
338 tx1[sfSigners.jsonName][0U][sfSigner.jsonName][sfSigningPubKey.jsonName] =
340 tx1[sfSigners.jsonName][0U][sfSigner.jsonName][sfTxnSignature.jsonName] =
"DEADBEEF";
351 auto const seq = env.
seq(alice);
354 tx1[jss::SigningPubKey] =
strHex(alice.pk());
355 auto jt = env.jtnofill(
366 auto const seq = env.
seq(alice);
378 auto const seq = env.
seq(alice);
381 tx1[jss::Fee] =
to_string(env.current()->fees().base);
391 auto const seq = env.
seq(alice);
394 tx1[jss::Fee] =
"-1";
404 auto const seq = env.
seq(alice);
407 tx1[jss::Fee] =
"1.5";
408 env.set_parse_failure_expected(
true);
414 fail(
"Expected parse_error for fractional fee");
420 env.set_parse_failure_expected(
false);
426 auto const seq = env.
seq(alice);
429 tx1[jss::Sequence] =
seq + 1;
440 auto const seq = env.
seq(alice);
451 auto const seq = env.
seq(alice);
462 auto const seq = env.
seq(alice);
473 auto const seq = env.
seq(alice);
486 auto const seq = env.
seq(alice);
491 batch::sig(bob, carol, alice, bob, carol, alice, bob, carol, alice, alice),
498 auto const seq = env.
seq(alice);
510 auto const seq = env.
seq(alice);
523 auto const seq = env.
seq(alice);
535 auto const seq = env.
seq(alice);
547 auto const seq = env.
seq(alice);
548 auto const bobSeq = env.seq(bob);
550 auto jt = env.jtnofill(
551 batch::outer(alice, env.seq(alice), batchFee, tfAllOrNothing),
556 serializeBatch(msg, tfAllOrNothing, jt.stx->getBatchTransactionIDs());
558 jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName][sfAccount.jsonName] =
560 jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName][sfSigningPubKey.jsonName] =
562 jt.jv[sfBatchSigners.jsonName][0u][sfBatchSigner.jsonName][sfTxnSignature.jsonName] =
571 auto const seq = env.
seq(alice);
588 using namespace test::jtx;
596 auto const alice =
Account(
"alice");
597 auto const bob =
Account(
"bob");
598 auto const carol =
Account(
"carol");
599 auto const dave =
Account(
"dave");
600 auto const elsa =
Account(
"elsa");
601 auto const frank =
Account(
"frank");
602 auto const phantom =
Account(
"phantom");
603 env.memoize(phantom);
605 env.fund(
XRP(10000), alice, bob, carol, dave, elsa, frank);
613 auto const seq = env.
seq(alice);
628 auto const seq = env.
seq(alice);
638 env(
signers(alice, 2, {{bob, 1}, {carol, 1}}));
641 env(
signers(bob, 2, {{carol, 1}, {dave, 1}, {elsa, 1}}));
646 auto const seq = env.
seq(alice);
658 auto const seq = env.
seq(alice);
663 batch::msig(bob, {carol, Account(
"dave", KeyType::ed25519)}),
671 env(
fset(elsa, asfDisableMaster),
sig(elsa));
672 auto const seq = env.
seq(alice);
684 auto const seq = env.
seq(alice);
696 auto const seq = env.
seq(alice);
710 auto const seq = env.
seq(alice);
714 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
715 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
716 batch::msig(bob, {carol, Reg{dave, davo}}),
723 auto const seq = env.seq(alice);
726 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
727 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
728 batch::msig(bob, {carol}),
735 auto const seq = env.seq(alice);
738 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
739 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
740 batch::msig(bob, {carol, dave}),
747 auto const seq = env.seq(alice);
750 batch::inner(
pay(alice, bob,
XRP(10)), seq + 1),
751 batch::inner(
pay(bob, alice,
XRP(5)), env.seq(bob)),
752 batch::msig(bob, {carol, dave}),
763 auto const ledSeq = env.current()->seq();
764 auto const seq = env.seq(alice);
767 batch::inner(
pay(alice, phantom,
XRP(1000)), seq + 1),
768 batch::inner(
noop(phantom), ledSeq),
769 batch::sig(Reg{phantom, carol}),
776 auto const ledSeq = env.current()->seq();
777 auto const seq = env.seq(alice);
780 batch::inner(
pay(alice, bob,
XRP(1000)), seq + 1),
781 batch::inner(
noop(bob), ledSeq),
782 batch::sig(Reg{bob, carol}),
790 auto const seq = env.seq(alice);
793 batch::inner(
pay(alice, bob,
XRP(1)), seq + 1),
794 batch::inner(
pay(bob, alice,
XRP(2)), env.seq(bob)),
795 batch::sig(Reg{bob, carol}),
802 auto const seq = env.seq(alice);
805 batch::inner(
pay(alice, bob,
XRP(1)), seq + 1),
806 batch::inner(
pay(bob, alice,
XRP(2)), env.seq(bob)),
815 env(
fset(bob, asfDisableMaster), sig(bob));
816 auto const seq = env.seq(alice);
819 batch::inner(
pay(alice, bob,
XRP(1)), seq + 1),
820 batch::inner(
pay(bob, alice,
XRP(2)), env.seq(bob)),
830 testcase(
"bad raw txn");
832 using namespace test::jtx;
837 auto const alice =
Account(
"alice");
838 auto const bob =
Account(
"bob");
840 env.fund(
XRP(10000), alice, bob);
844 auto const batchFee = batch::calcBatchFee(env, 1, 2);
845 auto const seq = env.
seq(alice);
847 tx1.removeMember(jss::TransactionType);
848 auto jt = env.jtnofill(
849 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
859 auto const batchFee = batch::calcBatchFee(env, 1, 2);
860 auto const seq = env.
seq(alice);
862 tx1.removeMember(jss::Account);
863 auto jt = env.jtnofill(
864 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
874 auto const batchFee = batch::calcBatchFee(env, 1, 2);
875 auto const seq = env.
seq(alice);
877 tx1.removeMember(jss::Sequence);
878 auto jt = env.jtnofill(
879 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
889 auto const batchFee = batch::calcBatchFee(env, 1, 2);
890 auto const seq = env.
seq(alice);
892 tx1.removeMember(jss::Fee);
893 auto jt = env.jtnofill(
894 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
904 auto const batchFee = batch::calcBatchFee(env, 1, 2);
905 auto const seq = env.
seq(alice);
907 tx1.removeMember(jss::SigningPubKey);
908 auto jt = env.jtnofill(
909 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
921 testcase(
"bad sequence");
923 using namespace test::jtx;
928 auto const alice =
Account(
"alice");
929 auto const bob =
Account(
"bob");
931 auto const USD = gw[
"USD"];
933 env.fund(
XRP(10000), alice, bob, gw);
935 env.trust(USD(1000), alice, bob);
936 env(pay(gw, alice, USD(100)));
937 env(pay(gw, bob, USD(100)));
945 auto const preAliceSeq = env.seq(alice);
946 auto const preAlice = env.balance(alice);
947 auto const preAliceUSD = env.balance(alice, USD.issue());
948 auto const preBobSeq = env.seq(bob);
949 auto const preBob = env.balance(bob);
950 auto const preBobUSD = env.balance(bob, USD.issue());
952 auto const batchFee = batch::calcBatchFee(env, 1, 2);
953 auto const [txIDs, batchID] = submitBatch(
956 batch::outer(alice, preAliceSeq, batchFee, tfAllOrNothing),
966 validateClosedLedger(env, testCases);
973 validateClosedLedger(env, testCases);
977 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
978 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
979 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
980 BEAST_EXPECT(env.seq(bob) == preBobSeq);
981 BEAST_EXPECT(env.balance(bob) == preBob);
982 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
987 auto const preAliceSeq = env.seq(alice);
988 auto const preAlice = env.balance(alice);
989 auto const preAliceUSD = env.balance(alice, USD.issue());
990 auto const preBobSeq = env.seq(bob);
991 auto const preBob = env.balance(bob);
992 auto const preBobUSD = env.balance(bob, USD.issue());
994 auto const batchFee = batch::calcBatchFee(env, 1, 2);
995 auto const [txIDs, batchID] = submitBatch(
998 batch::outer(alice, preAliceSeq, batchFee, tfAllOrNothing),
1008 validateClosedLedger(env, testCases);
1015 validateClosedLedger(env, testCases);
1019 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1020 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1021 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1022 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1023 BEAST_EXPECT(env.balance(bob) == preBob);
1024 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1029 auto const preAliceSeq = env.seq(alice);
1030 auto const preAlice = env.balance(alice);
1031 auto const preAliceUSD = env.balance(alice, USD.issue());
1032 auto const preBobSeq = env.seq(bob);
1033 auto const preBob = env.balance(bob);
1034 auto const preBobUSD = env.balance(bob, USD.issue());
1036 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1037 auto const [txIDs, batchID] = submitBatch(
1040 batch::outer(alice, preAliceSeq, batchFee, tfAllOrNothing),
1050 validateClosedLedger(env, testCases);
1057 validateClosedLedger(env, testCases);
1061 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1062 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1063 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1064 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1065 BEAST_EXPECT(env.balance(bob) == preBob);
1066 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1071 auto const preAliceSeq = env.seq(alice);
1072 auto const preAlice = env.balance(alice);
1073 auto const preAliceUSD = env.balance(alice, USD.issue());
1074 auto const preBobSeq = env.seq(bob);
1075 auto const preBob = env.balance(bob);
1076 auto const preBobUSD = env.balance(bob, USD.issue());
1078 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1079 auto const [txIDs, batchID] = submitBatch(
1082 batch::outer(alice, preAliceSeq, batchFee, tfAllOrNothing),
1092 validateClosedLedger(env, testCases);
1099 validateClosedLedger(env, testCases);
1103 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1104 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1105 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1106 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1107 BEAST_EXPECT(env.balance(bob) == preBob);
1108 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1113 auto const preAliceSeq = env.seq(alice);
1114 auto const preAlice = env.balance(alice);
1115 auto const preAliceUSD = env.balance(alice, USD.issue());
1116 auto const preBobSeq = env.seq(bob);
1117 auto const preBob = env.balance(bob);
1118 auto const preBobUSD = env.balance(bob, USD.issue());
1120 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1121 auto const [txIDs, batchID] = submitBatch(
1124 batch::outer(alice, preAliceSeq, batchFee, tfAllOrNothing),
1134 validateClosedLedger(env, testCases);
1141 validateClosedLedger(env, testCases);
1145 BEAST_EXPECT(env.seq(alice) == preAliceSeq + 1);
1146 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1147 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
1148 BEAST_EXPECT(env.seq(bob) == preBobSeq);
1149 BEAST_EXPECT(env.balance(bob) == preBob);
1150 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
1157 testcase(
"bad outer fee");
1159 using namespace test::jtx;
1166 auto const alice =
Account(
"alice");
1167 auto const bob =
Account(
"bob");
1168 env.fund(
XRP(10000), alice, bob);
1175 auto const batchFee = batch::calcBatchFee(env, 0, 1);
1176 auto const aliceSeq = env.seq(alice);
1177 env(batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
1188 auto const alice =
Account(
"alice");
1189 auto const bob =
Account(
"bob");
1190 auto const carol =
Account(
"carol");
1191 env.fund(
XRP(10000), alice, bob, carol);
1197 env(signers(alice, 2, {{bob, 1}, {carol, 1}}));
1201 auto const batchFee = batch::calcBatchFee(env, 1, 2);
1202 auto const aliceSeq = env.seq(alice);
1203 env(batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
1215 auto const alice =
Account(
"alice");
1216 auto const bob =
Account(
"bob");
1217 auto const carol =
Account(
"carol");
1218 env.fund(
XRP(10000), alice, bob, carol);
1224 env(signers(alice, 2, {{bob, 1}, {carol, 1}}));
1228 auto const batchFee = batch::calcBatchFee(env, 2, 2);
1229 auto const aliceSeq = env.seq(alice);
1230 auto const bobSeq = env.seq(bob);
1231 env(batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
1244 auto const alice =
Account(
"alice");
1245 auto const bob =
Account(
"bob");
1246 auto const carol =
Account(
"carol");
1247 env.fund(
XRP(10000), alice, bob, carol);
1253 env(signers(alice, 2, {{bob, 1}, {carol, 1}}));
1256 env(signers(bob, 2, {{alice, 1}, {carol, 1}}));
1260 auto const batchFee = batch::calcBatchFee(env, 3, 2);
1261 auto const aliceSeq = env.seq(alice);
1262 auto const bobSeq = env.seq(bob);
1263 env(batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
1276 auto const alice =
Account(
"alice");
1277 auto const bob =
Account(
"bob");
1278 env.fund(
XRP(10000), alice, bob);
1285 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1286 auto const aliceSeq = env.seq(alice);
1287 auto const bobSeq = env.seq(bob);
1288 env(batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
1300 auto const alice =
Account(
"alice");
1301 auto const bob =
Account(
"bob");
1302 auto const gw =
Account(
"gw");
1303 auto const USD = gw[
"USD"];
1305 env.fund(
XRP(10000), alice, bob, gw);
1309 jv[jss::Account] = alice.human();
1312 jv[jss::TradingFee] = 0;
1313 jv[jss::TransactionType] = jss::AMMCreate;
1317 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1318 auto const seq = env.
seq(alice);
1319 env(batch::outer(alice,
seq, batchFee, tfAllOrNothing),
1330 testcase(
"calculate base fee");
1332 using namespace test::jtx;
1339 auto const alice =
Account(
"alice");
1340 auto const bob =
Account(
"bob");
1341 env.fund(
XRP(10000), alice, bob);
1344 auto const batchFee = batch::calcBatchFee(env, 0, 9);
1345 auto const aliceSeq = env.seq(alice);
1346 env(batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
1364 auto const alice =
Account(
"alice");
1365 auto const bob =
Account(
"bob");
1366 env.fund(
XRP(10000), alice, bob);
1369 auto const batchFee = batch::calcBatchFee(env, 0, 9);
1370 auto const aliceSeq = env.seq(alice);
1371 auto jt = env.jtnofill(
1372 batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
1386 return result.applied;
1394 auto const alice =
Account(
"alice");
1395 auto const bob =
Account(
"bob");
1396 env.fund(
XRP(10000), alice, bob);
1399 auto const aliceSeq = env.seq(alice);
1400 auto const batchFee = batch::calcBatchFee(env, 9, 2);
1401 env(batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
1404 batch::sig(bob, bob, bob, bob, bob, bob, bob, bob, bob, bob),
1413 auto const alice =
Account(
"alice");
1414 auto const bob =
Account(
"bob");
1415 env.fund(
XRP(10000), alice, bob);
1418 auto const batchFee = batch::calcBatchFee(env, 0, 9);
1419 auto const aliceSeq = env.seq(alice);
1420 auto jt = env.jtnofill(
1421 batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
1424 batch::sig(bob, bob, bob, bob, bob, bob, bob, bob, bob, bob));
1429 return result.applied;
1437 testcase(
"all or nothing");
1439 using namespace test::jtx;
1444 auto const alice =
Account(
"alice");
1445 auto const bob =
Account(
"bob");
1446 auto const gw =
Account(
"gw");
1447 auto const USD = gw[
"USD"];
1448 env.fund(
XRP(10000), alice, bob, gw);
1453 auto const preAlice = env.balance(alice);
1454 auto const preBob = env.balance(bob);
1456 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1457 auto const seq = env.
seq(alice);
1458 auto const [txIDs, batchID] = submitBatch(
1461 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
1468 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1469 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1471 validateClosedLedger(env, testCases);
1474 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1477 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1478 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1483 auto const preAlice = env.balance(alice);
1484 auto const preBob = env.balance(bob);
1486 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1487 auto const seq = env.
seq(alice);
1489 auto const [txIDs, batchID] = submitBatch(
1492 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
1501 validateClosedLedger(env, testCases);
1504 BEAST_EXPECT(env.seq(alice) ==
seq + 1);
1507 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1508 BEAST_EXPECT(env.balance(bob) == preBob);
1513 auto const preAlice = env.balance(alice);
1514 auto const preBob = env.balance(bob);
1516 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1517 auto const seq = env.
seq(alice);
1518 auto const [txIDs, batchID] = submitBatch(
1521 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
1530 validateClosedLedger(env, testCases);
1533 BEAST_EXPECT(env.seq(alice) ==
seq + 1);
1536 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1537 BEAST_EXPECT(env.balance(bob) == preBob);
1542 auto const preAlice = env.balance(alice);
1543 auto const preBob = env.balance(bob);
1545 auto const batchFee = batch::calcBatchFee(env, 0, 2);
1546 auto const seq = env.
seq(alice);
1547 auto const [txIDs, batchID] = submitBatch(
1550 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
1559 validateClosedLedger(env, testCases);
1562 BEAST_EXPECT(env.seq(alice) ==
seq + 1);
1565 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1566 BEAST_EXPECT(env.balance(bob) == preBob);
1573 testcase(
"only one");
1575 using namespace test::jtx;
1580 auto const alice =
Account(
"alice");
1581 auto const bob =
Account(
"bob");
1582 auto const carol =
Account(
"carol");
1583 auto const dave =
Account(
"dave");
1584 auto const gw =
Account(
"gw");
1585 auto const USD = gw[
"USD"];
1586 env.fund(
XRP(10000), alice, bob, carol, dave, gw);
1591 auto const preAlice = env.balance(alice);
1592 auto const preBob = env.balance(bob);
1594 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1595 auto const seq = env.
seq(alice);
1596 auto const [txIDs, batchID] = submitBatch(
1599 batch::outer(alice,
seq, batchFee, tfOnlyOne),
1610 {1,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[0], batchID},
1611 {2,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[1], batchID},
1612 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
1614 validateClosedLedger(env, testCases);
1617 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
1620 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1621 BEAST_EXPECT(env.balance(bob) == preBob);
1626 auto const preAlice = env.balance(alice);
1627 auto const preBob = env.balance(bob);
1629 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1630 auto const seq = env.
seq(alice);
1631 auto const [txIDs, batchID] = submitBatch(
1634 batch::outer(alice,
seq, batchFee, tfOnlyOne),
1643 {1,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[0], batchID},
1644 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1646 validateClosedLedger(env, testCases);
1649 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1652 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
1653 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1658 auto const preAlice = env.balance(alice);
1659 auto const preBob = env.balance(bob);
1661 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1662 auto const seq = env.
seq(alice);
1663 auto const [txIDs, batchID] = submitBatch(
1666 batch::outer(alice,
seq, batchFee, tfOnlyOne),
1675 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1677 validateClosedLedger(env, testCases);
1680 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1683 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
1684 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1689 auto const preAlice = env.balance(alice);
1690 auto const preBob = env.balance(bob);
1692 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1693 auto const seq = env.
seq(alice);
1694 auto const [txIDs, batchID] = submitBatch(
1697 batch::outer(alice,
seq, batchFee, tfOnlyOne),
1706 {1,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1708 validateClosedLedger(env, testCases);
1711 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1714 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(1));
1715 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1720 auto const preAlice = env.balance(alice);
1721 auto const preBob = env.balance(bob);
1723 auto const batchFee = batch::calcBatchFee(env, 0, 3);
1724 auto const seq = env.
seq(alice);
1725 auto const [txIDs, batchID] = submitBatch(
1728 batch::outer(alice,
seq, batchFee, tfOnlyOne),
1737 {1,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1739 validateClosedLedger(env, testCases);
1742 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1745 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(1));
1746 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
1751 auto const preAlice = env.balance(alice);
1752 auto const preBob = env.balance(bob);
1753 auto const preCarol = env.balance(carol);
1754 auto const seq = env.
seq(alice);
1755 auto const batchFee = batch::calcBatchFee(env, 0, 6);
1757 auto const [txIDs, batchID] = submitBatch(
1760 batch::outer(alice,
seq, batchFee, tfOnlyOne),
1762 offer(alice, alice[
"USD"](100),
XRP(100), tfImmediateOrCancel),
seq + 1),
1764 offer(alice, alice[
"USD"](100),
XRP(100), tfImmediateOrCancel),
seq + 2),
1766 offer(alice, alice[
"USD"](100),
XRP(100), tfImmediateOrCancel),
seq + 3),
1774 {1,
"OfferCreate",
"tecKILLED", txIDs[0], batchID},
1775 {2,
"OfferCreate",
"tecKILLED", txIDs[1], batchID},
1776 {3,
"OfferCreate",
"tecKILLED", txIDs[2], batchID},
1777 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
1779 validateClosedLedger(env, testCases);
1781 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(100) - batchFee);
1782 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(100));
1783 BEAST_EXPECT(env.balance(carol) == preCarol);
1790 testcase(
"until failure");
1792 using namespace test::jtx;
1797 auto const alice =
Account(
"alice");
1798 auto const bob =
Account(
"bob");
1799 auto const carol =
Account(
"carol");
1800 auto const dave =
Account(
"dave");
1801 auto const gw =
Account(
"gw");
1802 auto const USD = gw[
"USD"];
1803 env.fund(
XRP(10000), alice, bob, carol, dave, gw);
1808 auto const preAlice = env.balance(alice);
1809 auto const preBob = env.balance(bob);
1811 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1812 auto const seq = env.
seq(alice);
1813 auto const [txIDs, batchID] = submitBatch(
1816 batch::outer(alice,
seq, batchFee, tfUntilFailure),
1826 {1,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[0], batchID},
1828 validateClosedLedger(env, testCases);
1831 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
1834 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
1835 BEAST_EXPECT(env.balance(bob) == preBob);
1840 auto const preAlice = env.balance(alice);
1841 auto const preBob = env.balance(bob);
1843 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1844 auto const seq = env.
seq(alice);
1845 auto const [txIDs, batchID] = submitBatch(
1848 batch::outer(alice,
seq, batchFee, tfUntilFailure),
1857 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1858 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1859 {3,
"Payment",
"tesSUCCESS", txIDs[2], batchID},
1860 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
1862 validateClosedLedger(env, testCases);
1865 BEAST_EXPECT(env.seq(alice) ==
seq + 5);
1868 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(10) - batchFee);
1869 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(10));
1874 auto const preAlice = env.balance(alice);
1875 auto const preBob = env.balance(bob);
1877 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1878 auto const seq = env.
seq(alice);
1879 auto const [txIDs, batchID] = submitBatch(
1882 batch::outer(alice,
seq, batchFee, tfUntilFailure),
1892 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1893 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1894 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
1896 validateClosedLedger(env, testCases);
1899 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
1902 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1903 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1908 auto const preAlice = env.balance(alice);
1909 auto const preBob = env.balance(bob);
1911 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1912 auto const seq = env.
seq(alice);
1913 auto const [txIDs, batchID] = submitBatch(
1916 batch::outer(alice,
seq, batchFee, tfUntilFailure),
1926 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1927 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1929 validateClosedLedger(env, testCases);
1932 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1935 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1936 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1941 auto const preAlice = env.balance(alice);
1942 auto const preBob = env.balance(bob);
1944 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1945 auto const seq = env.
seq(alice);
1946 auto const [txIDs, batchID] = submitBatch(
1949 batch::outer(alice,
seq, batchFee, tfUntilFailure),
1959 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1960 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1962 validateClosedLedger(env, testCases);
1965 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
1968 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
1969 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
1974 auto const preAlice = env.balance(alice);
1975 auto const preBob = env.balance(bob);
1976 auto const preCarol = env.balance(carol);
1977 auto const seq = env.
seq(alice);
1978 auto const batchFee = batch::calcBatchFee(env, 0, 4);
1979 auto const [txIDs, batchID] = submitBatch(
1982 batch::outer(alice,
seq, batchFee, tfUntilFailure),
1986 offer(alice, alice[
"USD"](100),
XRP(100), tfImmediateOrCancel),
seq + 3),
1992 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
1993 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
1994 {3,
"OfferCreate",
"tecKILLED", txIDs[2], batchID},
1996 validateClosedLedger(env, testCases);
1998 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(200) - batchFee);
1999 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(100));
2000 BEAST_EXPECT(env.balance(carol) == preCarol +
XRP(100));
2007 testcase(
"independent");
2009 using namespace test::jtx;
2014 auto const alice =
Account(
"alice");
2015 auto const bob =
Account(
"bob");
2016 auto const carol =
Account(
"carol");
2017 auto const gw =
Account(
"gw");
2018 auto const USD = gw[
"USD"];
2019 env.fund(
XRP(10000), alice, bob, carol, gw);
2024 auto const preAlice = env.balance(alice);
2025 auto const preBob = env.balance(bob);
2027 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2028 auto const seq = env.
seq(alice);
2029 auto const [txIDs, batchID] = submitBatch(
2032 batch::outer(alice,
seq, batchFee, tfIndependent),
2043 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2044 {2,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[1], batchID},
2045 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
2046 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2048 validateClosedLedger(env, testCases);
2051 BEAST_EXPECT(env.seq(alice) ==
seq + 5);
2054 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(4) - batchFee);
2055 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(4));
2060 auto const preAlice = env.balance(alice);
2061 auto const preBob = env.balance(bob);
2063 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2064 auto const seq = env.
seq(alice);
2065 auto const [txIDs, batchID] = submitBatch(
2068 batch::outer(alice,
seq, batchFee, tfIndependent),
2078 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2079 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2080 {3,
"Payment",
"tecUNFUNDED_PAYMENT", txIDs[2], batchID},
2081 {4,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2083 validateClosedLedger(env, testCases);
2086 BEAST_EXPECT(env.seq(alice) ==
seq + 5);
2089 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(6) - batchFee);
2090 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(6));
2095 auto const preAlice = env.balance(alice);
2096 auto const preBob = env.balance(bob);
2098 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2099 auto const seq = env.
seq(alice);
2100 auto const [txIDs, batchID] = submitBatch(
2103 batch::outer(alice,
seq, batchFee, tfIndependent),
2113 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2114 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2115 {3,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2117 validateClosedLedger(env, testCases);
2120 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
2123 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(6));
2124 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(6));
2129 auto const preAlice = env.balance(alice);
2130 auto const preBob = env.balance(bob);
2132 auto const batchFee = batch::calcBatchFee(env, 0, 4);
2133 auto const seq = env.
seq(alice);
2134 auto const [txIDs, batchID] = submitBatch(
2137 batch::outer(alice,
seq, batchFee, tfIndependent),
2147 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2148 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2149 {3,
"Payment",
"tesSUCCESS", txIDs[3], batchID},
2151 validateClosedLedger(env, testCases);
2154 BEAST_EXPECT(env.seq(alice) ==
seq + 4);
2157 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee -
XRP(6));
2158 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(6));
2163 auto const preAlice = env.balance(alice);
2164 auto const preBob = env.balance(bob);
2165 auto const preCarol = env.balance(carol);
2166 auto const seq = env.
seq(alice);
2167 auto const batchFee = batch::calcBatchFee(env, 0, 3);
2168 auto const [txIDs, batchID] = submitBatch(
2171 batch::outer(alice,
seq, batchFee, tfIndependent),
2175 offer(alice, alice[
"USD"](100),
XRP(100), tfImmediateOrCancel),
seq + 3));
2180 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2181 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2182 {3,
"OfferCreate",
"tecKILLED", txIDs[2], batchID},
2184 validateClosedLedger(env, testCases);
2186 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(200) - batchFee);
2187 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(100));
2188 BEAST_EXPECT(env.balance(carol) == preCarol +
XRP(100));
2195 bool const withInnerSigFix = features[fixBatchInnerSigs];
2199 ss <<
"inner submit rpc: batch " << (withBatch ?
"enabled" :
"disabled")
2200 <<
", inner sig fix: " << (withInnerSigFix ?
"enabled" :
"disabled") <<
": ";
2204 auto const amend = withBatch ? features : features - featureBatch;
2206 using namespace test::jtx;
2210 if (!BEAST_EXPECT(amend[featureBatch] == withBatch))
2213 auto const alice =
Account(
"alice");
2214 auto const bob =
Account(
"bob");
2216 env.fund(
XRP(10000), alice, bob);
2219 auto submitAndValidate = [&](
std::string caseName,
2224 bool expectInvalidFlag =
false) {
2225 testcase << testName << caseName
2226 << (expectInvalidFlag ?
" - Expected to reach tx engine!" :
"");
2227 auto const jrr = env.rpc(
"submit",
strHex(
slice))[jss::result];
2228 auto const expected = withBatch
2229 ? expectedEnabled.value_or(
2230 "fails local checks: Malformed: Invalid inner batch "
2232 : expectedDisabled.value_or(
"fails local checks: Empty SigningPubKey.");
2233 if (expectInvalidFlag)
2236 jrr[jss::status] ==
"success" && jrr[jss::engine_result] ==
"temINVALID_FLAG",
2244 jrr[jss::status] ==
"error" && jrr[jss::error] ==
"invalidTransaction" &&
2245 jrr[jss::error_exception] == expected,
2260 txn[sfTxnSignature] =
"DEADBEEF";
2264 submitAndValidate(
"TxnSignature set", s.
slice(), __LINE__);
2274 txn[sfSigningPubKey] =
strHex(alice.pk());
2279 "SigningPubKey set",
2283 "fails local checks: Invalid signature.");
2302 "fails local checks: Invalid Signers array size.");
2307 auto const txn =
batch::inner(pay(alice, bob,
XRP(1)), env.seq(alice));
2308 auto const jt = env.jt(txn.getTxn());
2328 "No signing fields set",
2331 "fails local checks: Empty SigningPubKey.",
2332 "fails local checks: Empty SigningPubKey.",
2333 withBatch && !withInnerSigFix);
2342 STTx const amendTx(ttAMENDMENT, [
seq = env.closed()->header().
seq + 1](
auto& obj) {
2343 obj.setAccountID(sfAccount, AccountID());
2344 obj.setFieldH256(sfAmendment, fixBatchInnerSigs);
2345 obj.setFieldU32(sfLedgerSequence, seq);
2346 obj.setFieldU32(sfFlags, tfInnerBatchTxn);
2353 "Pseudo-transaction",
2356 withInnerSigFix ?
"fails local checks: Empty SigningPubKey."
2357 :
"fails local checks: Cannot submit pseudo transactions.",
2358 "fails local checks: Empty SigningPubKey.");
2365 for (
bool const withBatch : {
true,
false})
2367 doTestInnerSubmitRPC(features, withBatch);
2374 testcase(
"account activation");
2376 using namespace test::jtx;
2381 auto const alice =
Account(
"alice");
2382 auto const bob =
Account(
"bob");
2383 env.fund(
XRP(10000), alice);
2387 auto const preAlice = env.balance(alice);
2388 auto const ledSeq = env.current()->seq();
2389 auto const seq = env.
seq(alice);
2390 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2391 auto const [txIDs, batchID] = submitBatch(
2394 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
2402 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2403 {2,
"AccountSet",
"tesSUCCESS", txIDs[1], batchID},
2405 validateClosedLedger(env, testCases);
2408 BEAST_EXPECT(env.seq(alice) ==
seq + 2);
2411 BEAST_EXPECT(env.seq(bob) == ledSeq + 1);
2414 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1000) - batchFee);
2415 BEAST_EXPECT(env.balance(bob) ==
XRP(1000));
2421 testcase(
"account set");
2423 using namespace test::jtx;
2428 auto const alice =
Account(
"alice");
2429 auto const bob =
Account(
"bob");
2430 env.fund(
XRP(10000), alice, bob);
2433 auto const preAlice = env.balance(alice);
2434 auto const preBob = env.balance(bob);
2436 auto const seq = env.
seq(alice);
2437 auto const batchFee = batch::calcBatchFee(env, 0, 2);
2441 auto const [txIDs, batchID] = submitBatch(
2444 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
2451 {1,
"AccountSet",
"tesSUCCESS", txIDs[0], batchID},
2452 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
2454 validateClosedLedger(env, testCases);
2458 BEAST_EXPECT(sle->getFieldVL(sfDomain) ==
Blob(
domain.begin(),
domain.end()));
2461 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
2464 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
2465 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
2471 testcase(
"account delete");
2473 using namespace test::jtx;
2480 auto const alice =
Account(
"alice");
2481 auto const bob =
Account(
"bob");
2482 env.fund(
XRP(10000), alice, bob);
2486 for (
int i = 0; i < 5; ++i)
2489 auto const preAlice = env.balance(alice);
2490 auto const preBob = env.balance(bob);
2492 auto const seq = env.
seq(alice);
2493 auto const batchFee = batch::calcBatchFee(env, 0, 2) + env.current()->fees().increment;
2494 auto const [txIDs, batchID] = submitBatch(
2497 batch::outer(alice,
seq, batchFee, tfIndependent),
2506 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2507 {2,
"AccountDelete",
"tesSUCCESS", txIDs[1], batchID},
2509 validateClosedLedger(env, testCases);
2513 BEAST_EXPECT(env.balance(bob) == preBob + (preAlice - batchFee));
2520 auto const alice =
Account(
"alice");
2521 auto const bob =
Account(
"bob");
2522 env.fund(
XRP(10000), alice, bob);
2526 for (
int i = 0; i < 5; ++i)
2529 auto const preAlice = env.balance(alice);
2530 auto const preBob = env.balance(bob);
2532 env.trust(bob[
"USD"](1000), alice);
2535 auto const seq = env.
seq(alice);
2536 auto const batchFee = batch::calcBatchFee(env, 0, 2) + env.current()->fees().increment;
2537 auto const [txIDs, batchID] = submitBatch(
2540 batch::outer(alice,
seq, batchFee, tfIndependent),
2549 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
2550 {2,
"AccountDelete",
"tecHAS_OBLIGATIONS", txIDs[1], batchID},
2551 {3,
"Payment",
"tesSUCCESS", txIDs[2], batchID},
2553 validateClosedLedger(env, testCases);
2557 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
2564 auto const alice =
Account(
"alice");
2565 auto const bob =
Account(
"bob");
2566 env.fund(
XRP(10000), alice, bob);
2570 for (
int i = 0; i < 5; ++i)
2573 auto const preAlice = env.balance(alice);
2574 auto const preBob = env.balance(bob);
2576 auto const seq = env.
seq(alice);
2577 auto const batchFee = batch::calcBatchFee(env, 0, 2) + env.current()->fees().increment;
2578 auto const [txIDs, batchID] = submitBatch(
2581 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
2591 validateClosedLedger(env, testCases);
2595 BEAST_EXPECT(env.balance(bob) == preBob);
2606 return disabled == ttLOAN_BROKER_SET;
2609 using namespace test::jtx;
2612 *
this, features | featureSingleAssetVault | featureLendingProtocol | featureMPTokensV1};
2614 Account const issuer{
"issuer"};
2617 Account const lender{
"lender"};
2619 Account const borrower{
"borrower"};
2623 env.fund(
XRP(100'000), issuer,
noripple(lender, borrower));
2629 Vault const vault{env};
2631 auto const deposit = asset(50'000);
2632 auto const debtMaximumValue = asset(25'000).value();
2633 auto const coverDepositValue = asset(1000).value();
2635 auto [tx, vaultKeylet] = vault.create({.owner = lender, .asset = asset});
2638 BEAST_EXPECT(env.le(vaultKeylet));
2640 env(vault.deposit({.depositor = lender, .id = vaultKeylet.key, .amount = deposit}));
2646 using namespace loanBroker;
2647 env(
set(lender, vaultKeylet.key),
2649 debtMaximum(debtMaximumValue),
2653 env(coverDeposit(lender, brokerKeylet.key, coverDepositValue));
2659 using namespace loan;
2660 using namespace std::chrono_literals;
2662 auto const lenderSeq = env.seq(lender);
2663 auto const batchFee = batch::calcBatchFee(env, 0, 2);
2665 auto const loanKeylet =
keylet::loan(brokerKeylet.key, 1);
2667 auto const [txIDs, batchID] = submitBatch(
2670 batch::outer(lender, lenderSeq, batchFee, tfAllOrNothing),
2673 set(lender, brokerKeylet.key, asset(1000).value()),
2675 sig(sfCounterpartySignature, borrower),
2681 pay(lender, loanKeylet.key,
STAmount{asset, asset(500).value()}),
2685 auto const [txIDs, batchID] = submitBatch(
2688 batch::outer(lender, lenderSeq, batchFee, tfAllOrNothing),
2691 set(lender, brokerKeylet.key, asset(1000).value()),
2698 pay(lender, loanKeylet.key,
STAmount{asset, asset(500).value()}),
2702 auto const [txIDs, batchID] = submitBatch(
2705 batch::outer(lender, lenderSeq, batchFee, tfAllOrNothing),
2708 set(lender, brokerKeylet.key, asset(1000).value()),
2710 counterparty(borrower.id()),
2716 pay(lender, loanKeylet.key,
STAmount{asset, asset(500).value()}),
2723 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2724 auto const [txIDs, batchID] = submitBatch(
2727 batch::outer(lender, lenderSeq, batchFee, tfAllOrNothing),
2730 set(lender, brokerKeylet.key, asset(1000).value()),
2731 counterparty(borrower.id()),
2743 STAmount{asset, asset(500).value()}),
2748 BEAST_EXPECT(env.le(brokerKeylet));
2749 BEAST_EXPECT(!env.le(loanKeylet));
2754 auto const lenderSeq = env.seq(lender);
2755 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2756 auto const [txIDs, batchID] = submitBatch(
2759 batch::outer(lender, lenderSeq, batchFee, tfAllOrNothing),
2762 set(lender, brokerKeylet.key, asset(1000).value()),
2763 counterparty(borrower.id()),
2768 batch::inner(manage(lender, loanKeylet.key, tfLoanImpair), lenderSeq + 2),
2772 BEAST_EXPECT(env.le(brokerKeylet));
2773 if (
auto const sleLoan = env.le(loanKeylet);
2774 lendingBatchEnabled ? BEAST_EXPECT(sleLoan) : !BEAST_EXPECT(!sleLoan))
2776 BEAST_EXPECT(sleLoan->isFlag(lsfLoanImpaired));
2784 testcase(
"object create w/ sequence");
2786 using namespace test::jtx;
2791 auto const alice =
Account(
"alice");
2792 auto const bob =
Account(
"bob");
2793 auto const gw =
Account(
"gw");
2794 auto const USD = gw[
"USD"];
2796 env.fund(
XRP(10000), alice, bob, gw);
2799 env.trust(USD(1000), alice, bob);
2800 env(pay(gw, alice, USD(100)));
2801 env(pay(gw, bob, USD(100)));
2806 auto const aliceSeq = env.seq(alice);
2807 auto const bobSeq = env.seq(bob);
2808 auto const preAlice = env.balance(alice);
2809 auto const preBob = env.balance(bob);
2810 auto const preAliceUSD = env.balance(alice, USD.issue());
2811 auto const preBobUSD = env.balance(bob, USD.issue());
2813 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2814 uint256 const chkID{getCheckIndex(bob, env.seq(bob))};
2815 auto const [txIDs, batchID] = submitBatch(
2818 batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
2819 batch::inner(check::create(bob, alice, USD(10)), bobSeq),
2820 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq + 1),
2826 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
2827 {2,
"CheckCash",
"tesSUCCESS", txIDs[1], batchID},
2829 validateClosedLedger(env, testCases);
2832 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
2835 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
2838 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
2839 BEAST_EXPECT(env.balance(bob) == preBob);
2842 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD + USD(10));
2843 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10));
2848 env(
fset(alice, asfRequireDest));
2851 auto const aliceSeq = env.seq(alice);
2852 auto const bobSeq = env.seq(bob);
2853 auto const preAlice = env.balance(alice);
2854 auto const preBob = env.balance(bob);
2855 auto const preAliceUSD = env.balance(alice, USD.issue());
2856 auto const preBobUSD = env.balance(bob, USD.issue());
2858 auto const batchFee = batch::calcBatchFee(env, 1, 2);
2859 uint256 const chkID{getCheckIndex(bob, env.seq(bob))};
2860 auto const [txIDs, batchID] = submitBatch(
2863 batch::outer(alice, aliceSeq, batchFee, tfIndependent),
2865 batch::inner(check::create(bob, alice, USD(10)), bobSeq),
2866 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq + 1),
2872 {1,
"CheckCreate",
"tecDST_TAG_NEEDED", txIDs[0], batchID},
2873 {2,
"CheckCash",
"tecNO_ENTRY", txIDs[1], batchID},
2875 validateClosedLedger(env, testCases);
2878 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
2881 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
2884 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
2885 BEAST_EXPECT(env.balance(bob) == preBob);
2888 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD);
2889 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD);
2896 testcase(
"object create w/ ticket");
2898 using namespace test::jtx;
2903 auto const alice =
Account(
"alice");
2904 auto const bob =
Account(
"bob");
2905 auto const gw =
Account(
"gw");
2906 auto const USD = gw[
"USD"];
2908 env.fund(
XRP(10000), alice, bob, gw);
2911 env.trust(USD(1000), alice, bob);
2912 env(pay(gw, alice, USD(100)));
2913 env(pay(gw, bob, USD(100)));
2916 auto const aliceSeq = env.seq(alice);
2917 auto const bobSeq = env.seq(bob);
2918 auto const preAlice = env.balance(alice);
2919 auto const preBob = env.balance(bob);
2920 auto const preAliceUSD = env.balance(alice, USD.issue());
2921 auto const preBobUSD = env.balance(bob, USD.issue());
2923 auto const batchFee = batch::calcBatchFee(env, 1, 3);
2924 uint256 const chkID{getCheckIndex(bob, bobSeq + 1)};
2925 auto const [txIDs, batchID] = submitBatch(
2928 batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
2930 batch::inner(check::create(bob, alice, USD(10)), 0, bobSeq + 1),
2931 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq + 1),
2937 {1,
"TicketCreate",
"tesSUCCESS", txIDs[0], batchID},
2938 {2,
"CheckCreate",
"tesSUCCESS", txIDs[1], batchID},
2939 {3,
"CheckCash",
"tesSUCCESS", txIDs[2], batchID},
2941 validateClosedLedger(env, testCases);
2943 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
2944 BEAST_EXPECT(env.seq(bob) == bobSeq + 10 + 1);
2945 BEAST_EXPECT(env.balance(alice) == preAlice - batchFee);
2946 BEAST_EXPECT(env.balance(bob) == preBob);
2947 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD + USD(10));
2948 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10));
2954 testcase(
"object create w/ 3rd party");
2956 using namespace test::jtx;
2961 auto const alice =
Account(
"alice");
2962 auto const bob =
Account(
"bob");
2963 auto const carol =
Account(
"carol");
2964 auto const gw =
Account(
"gw");
2965 auto const USD = gw[
"USD"];
2967 env.fund(
XRP(10000), alice, bob, carol, gw);
2970 env.trust(USD(1000), alice, bob);
2971 env(pay(gw, alice, USD(100)));
2972 env(pay(gw, bob, USD(100)));
2975 auto const aliceSeq = env.seq(alice);
2976 auto const bobSeq = env.seq(bob);
2977 auto const carolSeq = env.seq(carol);
2978 auto const preAlice = env.balance(alice);
2979 auto const preBob = env.balance(bob);
2980 auto const preCarol = env.balance(carol);
2981 auto const preAliceUSD = env.balance(alice, USD.issue());
2982 auto const preBobUSD = env.balance(bob, USD.issue());
2984 auto const batchFee = batch::calcBatchFee(env, 2, 2);
2985 uint256 const chkID{getCheckIndex(bob, env.seq(bob))};
2986 auto const [txIDs, batchID] = submitBatch(
2989 batch::outer(carol, carolSeq, batchFee, tfAllOrNothing),
2990 batch::inner(check::create(bob, alice, USD(10)), bobSeq),
2991 batch::inner(check::cash(alice, chkID, USD(10)), aliceSeq),
2997 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
2998 {2,
"CheckCash",
"tesSUCCESS", txIDs[1], batchID},
3000 validateClosedLedger(env, testCases);
3002 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
3003 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
3004 BEAST_EXPECT(env.seq(carol) == carolSeq + 1);
3005 BEAST_EXPECT(env.balance(alice) == preAlice);
3006 BEAST_EXPECT(env.balance(bob) == preBob);
3007 BEAST_EXPECT(env.balance(carol) == preCarol - batchFee);
3008 BEAST_EXPECT(env.balance(alice, USD.issue()) == preAliceUSD + USD(10));
3009 BEAST_EXPECT(env.balance(bob, USD.issue()) == preBobUSD - USD(10));
3016 testcase(
"tickets outer");
3018 using namespace test::jtx;
3023 auto const alice =
Account(
"alice");
3024 auto const bob =
Account(
"bob");
3026 env.fund(
XRP(10000), alice, bob);
3030 env(ticket::create(alice, 10));
3033 auto const aliceSeq = env.seq(alice);
3034 auto const preAlice = env.balance(alice);
3035 auto const preBob = env.balance(bob);
3037 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3038 auto const [txIDs, batchID] = submitBatch(
3041 batch::outer(alice, 0, batchFee, tfAllOrNothing),
3049 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3050 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3052 validateClosedLedger(env, testCases);
3056 BEAST_EXPECT(sle->getFieldU32(sfOwnerCount) == 9);
3057 BEAST_EXPECT(sle->getFieldU32(sfTicketCount) == 9);
3059 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
3060 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3061 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3065 testcase(
"tickets inner");
3067 using namespace test::jtx;
3072 auto const alice =
Account(
"alice");
3073 auto const bob =
Account(
"bob");
3075 env.fund(
XRP(10000), alice, bob);
3079 env(ticket::create(alice, 10));
3082 auto const aliceSeq = env.seq(alice);
3083 auto const preAlice = env.balance(alice);
3084 auto const preBob = env.balance(bob);
3086 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3087 auto const [txIDs, batchID] = submitBatch(
3090 batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
3097 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3098 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3100 validateClosedLedger(env, testCases);
3104 BEAST_EXPECT(sle->getFieldU32(sfOwnerCount) == 8);
3105 BEAST_EXPECT(sle->getFieldU32(sfTicketCount) == 8);
3107 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
3108 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3109 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3113 testcase(
"tickets outer inner");
3115 using namespace test::jtx;
3120 auto const alice =
Account(
"alice");
3121 auto const bob =
Account(
"bob");
3123 env.fund(
XRP(10000), alice, bob);
3127 env(ticket::create(alice, 10));
3130 auto const aliceSeq = env.seq(alice);
3131 auto const preAlice = env.balance(alice);
3132 auto const preBob = env.balance(bob);
3134 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3135 auto const [txIDs, batchID] = submitBatch(
3138 batch::outer(alice, 0, batchFee, tfAllOrNothing),
3146 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3147 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3149 validateClosedLedger(env, testCases);
3153 BEAST_EXPECT(sle->getFieldU32(sfOwnerCount) == 8);
3154 BEAST_EXPECT(sle->getFieldU32(sfTicketCount) == 8);
3156 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
3157 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3158 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3165 testcase(
"sequence open ledger");
3167 using namespace test::jtx;
3170 auto const alice =
Account(
"alice");
3171 auto const bob =
Account(
"bob");
3172 auto const carol =
Account(
"carol");
3182 env.fund(
XRP(10000), alice, bob, carol);
3185 auto const aliceSeq = env.seq(alice);
3186 auto const carolSeq = env.seq(carol);
3189 auto const noopTxn = env.jt(
noop(alice),
seq(aliceSeq + 2));
3190 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3194 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3195 auto const [txIDs, batchID] = submitBatch(
3198 batch::outer(carol, carolSeq, batchFee, tfAllOrNothing),
3207 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3208 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3210 validateClosedLedger(env, testCases);
3217 {0,
"AccountSet",
"tesSUCCESS", noopTxnID,
std::nullopt},
3219 validateClosedLedger(env, testCases);
3229 env.fund(
XRP(10000), alice, bob);
3232 auto const aliceSeq = env.seq(alice);
3235 auto const noopTxn = env.jt(
noop(alice),
seq(aliceSeq + 1));
3239 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3240 auto const [txIDs, batchID] = submitBatch(
3243 batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
3251 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3252 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3254 validateClosedLedger(env, testCases);
3261 validateClosedLedger(env, testCases);
3271 env.fund(
XRP(10000), alice, bob);
3274 auto const aliceSeq = env.seq(alice);
3275 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3276 auto const [txIDs, batchID] = submitBatch(
3279 batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
3283 auto const noopTxn = env.jt(
noop(alice),
seq(aliceSeq + 1));
3290 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3291 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3293 validateClosedLedger(env, testCases);
3300 validateClosedLedger(env, testCases);
3307 env.fund(
XRP(10000), alice, bob, carol);
3310 auto const aliceSeq = env.seq(alice);
3311 auto const carolSeq = env.seq(carol);
3314 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3315 auto const [txIDs, batchID] = submitBatch(
3318 batch::outer(carol, carolSeq + 1, batchFee, tfAllOrNothing),
3324 auto const noopTxn = env.jt(
noop(carol),
seq(carolSeq));
3325 auto const noopTxnID =
to_string(noopTxn.stx->getTransactionID());
3331 {0,
"AccountSet",
"tesSUCCESS", noopTxnID,
std::nullopt},
3333 {2,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3334 {3,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3336 validateClosedLedger(env, testCases);
3343 validateClosedLedger(env, testCases);
3351 testcase(
"tickets open ledger");
3353 using namespace test::jtx;
3356 auto const alice =
Account(
"alice");
3357 auto const bob =
Account(
"bob");
3365 env.fund(
XRP(10000), alice, bob);
3369 env(ticket::create(alice, 10));
3372 auto const aliceSeq = env.seq(alice);
3375 auto const noopTxn = env.jt(
noop(alice),
ticket::use(aliceTicketSeq + 1));
3379 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3380 auto const [txIDs, batchID] = submitBatch(
3383 batch::outer(alice, 0, batchFee, tfAllOrNothing),
3392 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3393 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3395 validateClosedLedger(env, testCases);
3402 validateClosedLedger(env, testCases);
3412 env.fund(
XRP(10000), alice, bob);
3416 env(ticket::create(alice, 10));
3419 auto const aliceSeq = env.seq(alice);
3422 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3423 auto const [txIDs, batchID] = submitBatch(
3426 batch::outer(alice, 0, batchFee, tfAllOrNothing),
3432 auto const noopTxn = env.jt(
noop(alice),
ticket::use(aliceTicketSeq + 1));
3439 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3440 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3442 validateClosedLedger(env, testCases);
3449 validateClosedLedger(env, testCases);
3457 testcase(
"objects open ledger");
3459 using namespace test::jtx;
3462 auto const alice =
Account(
"alice");
3463 auto const bob =
Account(
"bob");
3473 env.fund(
XRP(10000), alice, bob);
3477 env(ticket::create(alice, 10));
3480 auto const aliceSeq = env.seq(alice);
3483 uint256 const chkID{getCheckIndex(alice, aliceSeq)};
3484 auto const objTxn = env.jt(check::cash(bob, chkID,
XRP(10)));
3485 auto const objTxnID =
to_string(objTxn.stx->getTransactionID());
3489 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3490 auto const [txIDs, batchID] = submitBatch(
3493 batch::outer(alice, 0, batchFee, tfAllOrNothing),
3502 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
3503 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3504 {3,
"CheckCash",
"tesSUCCESS", objTxnID,
std::nullopt},
3506 validateClosedLedger(env, testCases);
3513 validateClosedLedger(env, testCases);
3520 env.fund(
XRP(10000), alice, bob);
3524 env(ticket::create(alice, 10));
3527 auto const aliceSeq = env.seq(alice);
3528 auto const bobSeq = env.seq(bob);
3531 uint256 const chkID{getCheckIndex(alice, aliceSeq)};
3532 auto const objTxn = env.jt(check::create(alice, bob,
XRP(10)));
3533 auto const objTxnID =
to_string(objTxn.stx->getTransactionID());
3537 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3538 auto const [txIDs, batchID] = submitBatch(
3541 batch::outer(alice, 0, batchFee, tfAllOrNothing),
3550 {0,
"CheckCreate",
"tesSUCCESS", objTxnID,
std::nullopt},
3552 {2,
"CheckCash",
"tesSUCCESS", txIDs[0], batchID},
3553 {3,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3555 validateClosedLedger(env, testCases);
3567 env.fund(
XRP(10000), alice, bob);
3571 env(ticket::create(alice, 10));
3574 auto const aliceSeq = env.seq(alice);
3577 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3578 uint256 const chkID{getCheckIndex(alice, aliceSeq)};
3579 auto const [txIDs, batchID] = submitBatch(
3582 batch::outer(alice, 0, batchFee, tfAllOrNothing),
3588 auto const objTxn = env.jt(check::cash(bob, chkID,
XRP(10)));
3589 auto const objTxnID =
to_string(objTxn.stx->getTransactionID());
3596 {1,
"CheckCreate",
"tesSUCCESS", txIDs[0], batchID},
3597 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3598 {3,
"CheckCash",
"tesSUCCESS", objTxnID,
std::nullopt},
3600 validateClosedLedger(env, testCases);
3608 testcase(
"pseudo txn with tfInnerBatchTxn");
3610 using namespace test::jtx;
3615 auto const alice =
Account(
"alice");
3616 auto const bob =
Account(
"bob");
3617 env.fund(
XRP(10000), alice, bob);
3620 STTx const stx =
STTx(ttAMENDMENT, [&](
auto& obj) {
3621 obj.setAccountID(sfAccount,
AccountID());
3622 obj.setFieldH256(sfAmendment,
uint256(2));
3623 obj.setFieldU32(sfLedgerSequence, env.seq(alice));
3630 BEAST_EXPECT(reason ==
"Cannot submit pseudo transactions.");
3634 return result.applied;
3641 testcase(
"batch open ledger");
3649 using namespace test::jtx;
3653 XRPAmount const baseFee = env.current()->fees().base;
3655 auto const alice =
Account(
"alice");
3656 auto const bob =
Account(
"bob");
3658 env.fund(
XRP(10000), alice, bob);
3664 auto const aliceSeq = env.seq(alice);
3665 auto const preAlice = env.balance(alice);
3666 auto const preBob = env.balance(bob);
3667 auto const bobSeq = env.seq(bob);
3670 auto const payTxn1 = env.jt(pay(alice, bob,
XRP(10)),
seq(aliceSeq));
3671 auto const payTxn1ID =
to_string(payTxn1.stx->getTransactionID());
3675 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3676 auto const [txIDs, batchID] = submitBatch(
3679 batch::outer(alice, aliceSeq + 1, batchFee, tfAllOrNothing),
3685 auto const payTxn2 = env.jt(pay(bob, alice,
XRP(5)),
seq(bobSeq + 1));
3686 auto const payTxn2ID =
to_string(payTxn2.stx->getTransactionID());
3693 {2,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3694 {3,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3696 validateClosedLedger(env, testCases);
3704 validateClosedLedger(env, testCases);
3708 BEAST_EXPECT(env.seq(alice) == aliceSeq + 3);
3711 BEAST_EXPECT(env.seq(bob) == bobSeq + 2);
3714 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(10) - batchFee - baseFee);
3715 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(10) - baseFee);
3721 testcase(
"batch tx queue");
3723 using namespace test::jtx;
3730 makeSmallQueueConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}),
3735 auto alice =
Account(
"alice");
3737 auto carol =
Account(
"carol");
3741 env.close(env.now() + 5s, 10000ms);
3743 env.close(env.now() + 5s, 10000ms);
3754 auto const aliceSeq = env.seq(alice);
3755 auto const bobSeq = env.seq(bob);
3756 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3760 env(batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
3771 env(batch::outer(alice, aliceSeq, openLedgerFee(env, batchFee), tfAllOrNothing),
3786 makeSmallQueueConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}),
3791 auto alice =
Account(
"alice");
3793 auto carol =
Account(
"carol");
3797 env.close(env.now() + 5s, 10000ms);
3799 env.close(env.now() + 5s, 10000ms);
3806 auto const aliceSeq = env.seq(alice);
3807 auto const bobSeq = env.seq(bob);
3808 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3812 env(batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
3829 testcase(
"batch network ops");
3831 using namespace test::jtx;
3836 auto alice =
Account(
"alice");
3838 env.
fund(
XRP(10000), alice, bob);
3846 return jt.stx->getTransactionID();
3857 return transaction->getID();
3878 testcase(
"batch delegate");
3880 using namespace test::jtx;
3887 auto const alice =
Account(
"alice");
3888 auto const bob =
Account(
"bob");
3889 auto const gw =
Account(
"gw");
3890 auto const USD = gw[
"USD"];
3891 env.fund(
XRP(10000), alice, bob, gw);
3894 env(delegate::set(alice, bob, {
"Payment"}));
3897 auto const preAlice = env.balance(alice);
3898 auto const preBob = env.balance(bob);
3900 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3901 auto const seq = env.
seq(alice);
3904 tx[jss::Delegate] = bob.human();
3905 auto const [txIDs, batchID] = submitBatch(
3908 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
3915 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3916 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3918 validateClosedLedger(env, testCases);
3921 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
3924 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(3) - batchFee);
3925 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(3));
3932 auto const alice =
Account(
"alice");
3933 auto const bob =
Account(
"bob");
3934 auto const carol =
Account(
"carol");
3935 auto const gw =
Account(
"gw");
3936 auto const USD = gw[
"USD"];
3937 env.fund(
XRP(10000), alice, bob, carol, gw);
3940 env(delegate::set(bob, carol, {
"Payment"}));
3943 auto const preAlice = env.balance(alice);
3944 auto const preBob = env.balance(bob);
3945 auto const preCarol = env.balance(carol);
3947 auto const batchFee = batch::calcBatchFee(env, 1, 2);
3948 auto const aliceSeq = env.seq(alice);
3949 auto const bobSeq = env.seq(bob);
3952 tx[jss::Delegate] = carol.human();
3953 auto const [txIDs, batchID] = submitBatch(
3956 batch::outer(alice, aliceSeq, batchFee, tfAllOrNothing),
3964 {1,
"Payment",
"tesSUCCESS", txIDs[0], batchID},
3965 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
3967 validateClosedLedger(env, testCases);
3969 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
3970 BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
3971 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(1) - batchFee);
3972 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(1));
3975 BEAST_EXPECT(env.balance(carol) == preCarol);
3984 auto const alice =
Account(
"alice");
3985 auto const bob =
Account(
"bob");
3986 auto const gw =
Account(
"gw");
3987 auto const USD = gw[
"USD"];
3988 env.fund(
XRP(10000), alice, bob, gw);
3991 env(delegate::set(alice, bob, {
"AccountDomainSet"}));
3994 auto const preAlice = env.balance(alice);
3995 auto const preBob = env.balance(bob);
3997 auto const batchFee = batch::calcBatchFee(env, 0, 2);
3998 auto const seq = env.
seq(alice);
4003 tx[jss::Delegate] = bob.human();
4004 auto const [txIDs, batchID] = submitBatch(
4007 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
4014 {1,
"AccountSet",
"tesSUCCESS", txIDs[0], batchID},
4015 {2,
"Payment",
"tesSUCCESS", txIDs[1], batchID},
4017 validateClosedLedger(env, testCases);
4020 BEAST_EXPECT(env.seq(alice) ==
seq + 3);
4023 BEAST_EXPECT(env.balance(alice) == preAlice -
XRP(2) - batchFee);
4024 BEAST_EXPECT(env.balance(bob) == preBob +
XRP(2));
4034 env.fund(
XRP(100000), alice, bob);
4037 auto const mptID =
makeMptID(env.seq(alice), alice);
4038 MPTTester mpt(env, alice, {.fund =
false});
4040 mpt.
create({.flags = tfMPTCanLock});
4044 env(delegate::set(alice, bob, {
"MPTokenIssuanceLock",
"MPTokenIssuanceUnlock"}));
4047 auto const seq = env.
seq(alice);
4048 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4051 jv1[sfTransactionType] = jss::MPTokenIssuanceSet;
4052 jv1[sfAccount] = alice.human();
4053 jv1[sfDelegate] = bob.human();
4054 jv1[sfSequence] =
seq + 1;
4055 jv1[sfMPTokenIssuanceID] =
to_string(mptID);
4056 jv1[sfFlags] = tfMPTLock;
4059 jv2[sfTransactionType] = jss::MPTokenIssuanceSet;
4060 jv2[sfAccount] = alice.human();
4061 jv2[sfDelegate] = bob.human();
4062 jv2[sfSequence] =
seq + 2;
4063 jv2[sfMPTokenIssuanceID] =
to_string(mptID);
4064 jv2[sfFlags] = tfMPTUnlock;
4066 auto const [txIDs, batchID] = submitBatch(
4069 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
4076 {1,
"MPTokenIssuanceSet",
"tesSUCCESS", txIDs[0], batchID},
4077 {2,
"MPTokenIssuanceSet",
"tesSUCCESS", txIDs[1], batchID},
4079 validateClosedLedger(env, testCases);
4090 env.fund(
XRP(10000), gw, alice, bob);
4091 env(
fset(gw, asfRequireAuth));
4093 env(trust(alice, gw[
"USD"](50)));
4096 env(delegate::set(gw, bob, {
"TrustlineAuthorize",
"TrustlineFreeze"}));
4099 auto const seq = env.
seq(gw);
4100 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4102 auto jv1 = trust(gw, gw[
"USD"](0), alice, tfSetfAuth);
4103 jv1[sfDelegate] = bob.human();
4104 auto jv2 = trust(gw, gw[
"USD"](0), alice, tfSetFreeze);
4105 jv2[sfDelegate] = bob.human();
4107 auto const [txIDs, batchID] = submitBatch(
4110 batch::outer(gw,
seq, batchFee, tfAllOrNothing),
4117 {1,
"TrustSet",
"tesSUCCESS", txIDs[0], batchID},
4118 {2,
"TrustSet",
"tesSUCCESS", txIDs[1], batchID},
4120 validateClosedLedger(env, testCases);
4129 env.fund(
XRP(10000), gw, alice, bob);
4130 env(
fset(gw, asfRequireAuth));
4132 env(trust(alice, gw[
"USD"](50)));
4135 env(delegate::set(gw, bob, {
"TrustlineAuthorize",
"TrustlineFreeze"}));
4138 auto const seq = env.
seq(gw);
4139 auto const batchFee = batch::calcBatchFee(env, 0, 2);
4141 auto jv1 = trust(gw, gw[
"USD"](0), alice, tfSetFreeze);
4142 jv1[sfDelegate] = bob.human();
4143 auto jv2 = trust(gw, gw[
"USD"](0), alice, tfClearFreeze);
4144 jv2[sfDelegate] = bob.human();
4146 auto const [txIDs, batchID] = submitBatch(
4149 batch::outer(gw,
seq, batchFee, tfIndependent),
4157 {1,
"TrustSet",
"tesSUCCESS", txIDs[0], batchID},
4159 validateClosedLedger(env, testCases);
4169 testcase(
"Validate RPC response");
4171 using namespace jtx;
4172 Env env(*
this, features);
4175 env.
fund(
XRP(10000), alice, bob);
4180 auto const baseFee = env.
current()->fees().base;
4181 auto const aliceSeq = env.
seq(alice);
4182 auto jtx = env.
jt(pay(alice, bob,
XRP(1)));
4186 auto const jr = env.
rpc(
"submit",
strHex(s.
slice()))[jss::result];
4189 BEAST_EXPECT(jr.isMember(jss::account_sequence_available));
4190 BEAST_EXPECT(jr[jss::account_sequence_available].asUInt() == aliceSeq + 1);
4191 BEAST_EXPECT(jr.isMember(jss::account_sequence_next));
4192 BEAST_EXPECT(jr[jss::account_sequence_next].asUInt() == aliceSeq + 1);
4193 BEAST_EXPECT(jr.isMember(jss::open_ledger_cost));
4194 BEAST_EXPECT(jr[jss::open_ledger_cost] ==
to_string(baseFee));
4195 BEAST_EXPECT(jr.isMember(jss::validated_ledger_index));
4200 auto const baseFee = env.
current()->fees().base;
4201 auto const aliceSeq = env.
seq(alice);
4202 env(
fset(bob, asfRequireDest));
4203 auto jtx = env.
jt(pay(alice, bob,
XRP(1)),
seq(aliceSeq));
4207 auto const jr = env.
rpc(
"submit",
strHex(s.
slice()))[jss::result];
4210 BEAST_EXPECT(jr.isMember(jss::account_sequence_available));
4211 BEAST_EXPECT(jr[jss::account_sequence_available].asUInt() == aliceSeq + 1);
4212 BEAST_EXPECT(jr.isMember(jss::account_sequence_next));
4213 BEAST_EXPECT(jr[jss::account_sequence_next].asUInt() == aliceSeq + 1);
4214 BEAST_EXPECT(jr.isMember(jss::open_ledger_cost));
4215 BEAST_EXPECT(jr[jss::open_ledger_cost] ==
to_string(baseFee));
4216 BEAST_EXPECT(jr.isMember(jss::validated_ledger_index));
4221 auto const baseFee = env.
current()->fees().base;
4222 auto const aliceSeq = env.
seq(alice);
4223 auto jtx = env.
jt(pay(alice, bob,
XRP(1)),
seq(aliceSeq + 1));
4227 auto const jr = env.
rpc(
"submit",
strHex(s.
slice()))[jss::result];
4230 BEAST_EXPECT(jr.isMember(jss::account_sequence_available));
4231 BEAST_EXPECT(jr[jss::account_sequence_available].asUInt() == aliceSeq);
4232 BEAST_EXPECT(jr.isMember(jss::account_sequence_next));
4233 BEAST_EXPECT(jr[jss::account_sequence_next].asUInt() == aliceSeq);
4234 BEAST_EXPECT(jr.isMember(jss::open_ledger_cost));
4235 BEAST_EXPECT(jr[jss::open_ledger_cost] ==
to_string(baseFee));
4236 BEAST_EXPECT(jr.isMember(jss::validated_ledger_index));
4243 using namespace jtx;
4244 Env env(*
this, features);
4248 env.
fund(
XRP(10000), alice, bob, carol);
4259 auto const seq = env.
seq(alice);
4260 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4262 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
4265 XRPAmount const txBaseFee = getBaseFee(jtx);
4271 auto const seq = env.
seq(alice);
4272 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4275 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
4286 XRPAmount const txBaseFee = getBaseFee(jtx);
4292 auto const seq = env.
seq(alice);
4293 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4296 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
4299 batch::sig(bob, carol, alice, bob, carol, alice, bob, carol, alice, alice));
4300 XRPAmount const txBaseFee = getBaseFee(jtx);
4306 auto const seq = env.
seq(alice);
4307 XRPAmount const batchFee = batch::calcBatchFee(env, 0, 2);
4309 batch::outer(alice,
seq, batchFee, tfAllOrNothing),
4312 XRPAmount const txBaseFee = getBaseFee(jtx);
4313 BEAST_EXPECT(txBaseFee == batchFee);
4320 testEnable(features);
4321 testPreflight(features);
4322 testPreclaim(features);
4323 testBadRawTxn(features);
4324 testBadSequence(features);
4325 testBadOuterFee(features);
4326 testCalculateBaseFee(features);
4327 testAllOrNothing(features);
4328 testOnlyOne(features);
4329 testUntilFailure(features);
4330 testIndependent(features);
4331 testInnerSubmitRPC(features);
4332 testAccountActivation(features);
4333 testAccountSet(features);
4334 testAccountDelete(features);
4336 testObjectCreateSequence(features);
4337 testObjectCreateTicket(features);
4338 testObjectCreate3rdParty(features);
4339 testTickets(features);
4340 testSequenceOpenLedger(features);
4341 testTicketsOpenLedger(features);
4342 testObjectsOpenLedger(features);
4343 testPseudoTxn(features);
4344 testOpenLedger(features);
4345 testBatchTxQueue(features);
4346 testBatchNetworkOps(features);
4347 testBatchDelegate(features);
4348 testValidateRPCResponse(features);
4349 testBatchCalculateBaseFee(features);
4356 using namespace test::jtx;
4359 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)
static Json::Value getTxByIndex(Json::Value const &jrr, int const index)
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)
static Json::Value getLastLedger(jtx::Env &env)
static auto openLedgerFee(jtx::Env &env, XRPAmount const &batchFee)
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)
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.
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,...
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
constexpr FlagValue tfInnerBatchTxn
ApplyResult apply(ServiceRegistry ®istry, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
std::string to_string(base_uint< Bits, Tag > const &a)
std::string strHex(FwdIt begin, FwdIt end)
constexpr TenthBips32 percentageToTenthBips(std::uint32_t percentage)
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.
TERSubset< CanCvtToTER > TER
bool passesLocalChecks(STObject const &st, std::string &)
TenthBips< std::uint16_t > TenthBips16
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.
void serializeBatch(Serializer &msg, std::uint32_t const &flags, std::vector< uint256 > const &txids)
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.