21#include <test/jtx/AMM.h>
22#include <test/jtx/Env.h>
24#include <xrpld/app/tx/apply.h>
25#include <xrpld/app/tx/detail/ApplyContext.h>
27#include <xrpl/beast/utility/Journal.h>
28#include <xrpl/protocol/InnerObjectFormats.h>
29#include <xrpl/protocol/STLedgerEntry.h>
31#include <boost/algorithm/string/predicate.hpp>
81 using namespace test::jtx;
83 featureInvariantsV1_1 | featureSingleAssetVault;
86 Account
const A1{
"A1"};
87 Account
const A2{
"A2"};
88 env.fund(
XRP(1000), A1, A2);
90 BEAST_EXPECT(preclose(A1, A2, env));
93 OpenView ov{*env.current()};
101 env.current()->fees().base,
105 BEAST_EXPECT(precheck(A1, A2, ac));
108 if (!BEAST_EXPECT(ters.
size() == 2))
112 for (
TER const& terExpect : ters)
114 terActual = ac.checkInvariants(terActual, fee);
115 BEAST_EXPECT(terExpect == terActual);
116 auto const messages = sink.messages().str();
118 messages.starts_with(
"Invariant failed:") ||
119 messages.starts_with(
"Transaction caused an exception"));
120 for (
auto const& m : expect_logs)
122 if (messages.find(m) == std::string::npos)
135 using namespace test::jtx;
138 {{
"XRP net change was positive: 500"}},
144 auto amt = sle->getFieldAmount(sfBalance);
145 sle->setFieldAmount(sfBalance, amt +
STAmount{500});
146 ac.view().update(sle);
154 using namespace test::jtx;
159 {{
"an account root was deleted"}},
165 ac.view().erase(sle);
175 {{
"account deletion succeeded without deleting an account"}},
185 {{
"account deletion succeeded but deleted multiple accounts"}},
190 if (!sleA1 || !sleA2)
192 ac.view().erase(sleA1);
193 ac.view().erase(sleA2);
203 using namespace test::jtx;
204 testcase <<
"account root deletion left artifact";
212 if (!keyletInfo.includeInTests)
214 auto const& keyletfunc = keyletInfo.function;
215 auto const& type = keyletInfo.expectedLEName;
217 using namespace std::string_literals;
220 {{
"account deletion left behind a "s + type.c_str() +
225 auto const a1 = A1.
id();
232 ac.view().insert(newSLE);
233 ac.view().erase(sleA1);
243 {{
"account deletion left behind a NFTokenPage object"}},
249 ac.view().erase(sle);
268 {{
"account deletion left behind a DirectoryNode object"}},
276 BEAST_EXPECT(sle->at(~sfAMMID));
277 BEAST_EXPECT(sle->at(~sfAMMID) == ammKey);
279 ac.view().erase(sle);
289 AMM const amm(env, A1,
XRP(100), A1[
"USD"](50));
290 ammAcctID = amm.ammAccount();
291 ammKey = amm.ammID();
292 ammIssue = amm.lptIssue();
296 {{
"account deletion left behind a AMM object"}},
305 BEAST_EXPECT(sle->at(~sfAMMID));
306 BEAST_EXPECT(sle->at(~sfAMMID) == ammKey);
308 for (
auto const& trustKeylet :
312 if (
auto const line = ac.view().peek(trustKeylet); !line)
318 STAmount const lowLimit = line->at(sfLowLimit);
319 STAmount const highLimit = line->at(sfHighLimit);
330 auto const ammSle = ac.view().peek(
keylet::amm(ammKey));
331 if (!BEAST_EXPECT(ammSle))
335 BEAST_EXPECT(ac.view().dirRemove(
336 ownerDirKeylet, ammSle->at(sfOwnerNode), ammKey,
false));
338 !ac.view().exists(ownerDirKeylet) ||
339 ac.view().emptyDirDelete(ownerDirKeylet));
341 ac.view().erase(sle);
351 AMM const amm(env, A1,
XRP(100), A1[
"USD"](50));
352 ammAcctID = amm.ammAccount();
353 ammKey = amm.ammID();
354 ammIssue = amm.lptIssue();
362 using namespace test::jtx;
363 testcase <<
"ledger entry types don't match";
365 {{
"ledger entry type mismatch"},
366 {
"XRP net change of -1000000000 doesn't match fee 0"}},
373 ac.rawView().rawReplace(sleNew);
378 {{
"invalid ledger entry type added"}},
394 ac.view().insert(sleNew);
402 using namespace test::jtx;
403 testcase <<
"trust lines with XRP not allowed";
405 {{
"an XRP trust line was created"}},
410 ac.view().insert(sleNew);
418 using namespace test::jtx;
419 testcase <<
"trust lines with deep freeze flag without freeze "
422 {{
"a trust line with deep freeze flag without normal freeze was "
427 sleNew->setFieldAmount(sfLowLimit, A1[
"USD"](0));
428 sleNew->setFieldAmount(sfHighLimit, A1[
"USD"](0));
432 sleNew->setFieldU32(sfFlags, uFlags);
433 ac.view().insert(sleNew);
438 {{
"a trust line with deep freeze flag without normal freeze was "
443 sleNew->setFieldAmount(sfLowLimit, A1[
"USD"](0));
444 sleNew->setFieldAmount(sfHighLimit, A1[
"USD"](0));
447 sleNew->setFieldU32(sfFlags, uFlags);
448 ac.view().insert(sleNew);
453 {{
"a trust line with deep freeze flag without normal freeze was "
458 sleNew->setFieldAmount(sfLowLimit, A1[
"USD"](0));
459 sleNew->setFieldAmount(sfHighLimit, A1[
"USD"](0));
462 sleNew->setFieldU32(sfFlags, uFlags);
463 ac.view().insert(sleNew);
468 {{
"a trust line with deep freeze flag without normal freeze was "
473 sleNew->setFieldAmount(sfLowLimit, A1[
"USD"](0));
474 sleNew->setFieldAmount(sfHighLimit, A1[
"USD"](0));
477 sleNew->setFieldU32(sfFlags, uFlags);
478 ac.view().insert(sleNew);
483 {{
"a trust line with deep freeze flag without normal freeze was "
488 sleNew->setFieldAmount(sfLowLimit, A1[
"USD"](0));
489 sleNew->setFieldAmount(sfHighLimit, A1[
"USD"](0));
492 sleNew->setFieldU32(sfFlags, uFlags);
493 ac.view().insert(sleNew);
501 using namespace test::jtx;
502 testcase <<
"transfers when frozen";
506 auto const createTrustlines =
509 env.fund(
XRP(1000), G1);
511 env.trust(G1[
"USD"](10000), A1);
512 env.trust(G1[
"USD"](10000), A2);
515 env(
pay(G1, A1, G1[
"USD"](1000)));
516 env(
pay(G1, A2, G1[
"USD"](1000)));
522 auto const A1FrozenByIssuer =
524 createTrustlines(A1, A2, env);
531 auto const A1DeepFrozenByIssuer =
533 A1FrozenByIssuer(A1, A2, env);
540 auto const changeBalances = [&](
Account const& A1,
545 auto const sleA1 = ac.view().peek(
keylet::line(A1, G1[
"USD"]));
546 auto const sleA2 = ac.view().peek(
keylet::line(A2, G1[
"USD"]));
548 sleA1->setFieldAmount(sfBalance, G1[
"USD"](A1Balance));
549 sleA2->setFieldAmount(sfBalance, G1[
"USD"](A2Balance));
551 ac.view().update(sleA1);
552 ac.view().update(sleA2);
557 {{
"Attempting to move frozen funds"}},
559 changeBalances(A1, A2, ac, -900, -1100);
569 {{
"Attempting to move frozen funds"}},
571 changeBalances(A1, A2, ac, -900, -1100);
577 A1DeepFrozenByIssuer);
581 {{
"Attempting to move frozen funds"}},
583 changeBalances(A1, A2, ac, -1100, -900);
589 A1DeepFrozenByIssuer);
595 using namespace test::jtx;
599 {{
"Cannot return non-native STAmount as XRPAmount"}},
605 STAmount const nonNative(A2[
"USD"](51));
606 sle->setFieldAmount(sfBalance, nonNative);
607 ac.view().update(sle);
612 {{
"incorrect account XRP balance"},
613 {
"XRP net change was positive: 99999999000000001"}},
622 BEAST_EXPECT(!sle->getFieldAmount(sfBalance).negative());
623 ac.view().update(sle);
628 {{
"incorrect account XRP balance"},
629 {
"XRP net change of -1000000001 doesn't match fee 0"}},
635 sle->setFieldAmount(sfBalance,
STAmount{1,
true});
636 BEAST_EXPECT(sle->getFieldAmount(sfBalance).negative());
637 ac.view().update(sle);
645 using namespace test::jtx;
646 using namespace std::string_literals;
647 testcase <<
"Transaction fee checks";
650 {{
"fee paid was negative: -1"},
651 {
"XRP net change of 0 doesn't match fee -1"}},
657 {
"XRP net change of 0 doesn't match fee "s +
663 {{
"fee paid is 20 exceeds fee specified in transaction."},
664 {
"XRP net change of 0 doesn't match fee 20"}},
675 using namespace test::jtx;
679 {{
"offer with a bad amount"}},
687 sleNew->setAccountID(sfAccount, A1.
id());
688 sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]);
689 sleNew->setFieldAmount(sfTakerPays,
XRP(-1));
690 ac.view().insert(sleNew);
695 {{
"offer with a bad amount"}},
703 sleNew->setAccountID(sfAccount, A1.
id());
704 sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]);
705 sleNew->setFieldAmount(sfTakerPays, A1[
"USD"](10));
706 sleNew->setFieldAmount(sfTakerGets,
XRP(-1));
707 ac.view().insert(sleNew);
712 {{
"offer with a bad amount"}},
720 sleNew->setAccountID(sfAccount, A1.
id());
721 sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]);
722 sleNew->setFieldAmount(sfTakerPays,
XRP(10));
723 sleNew->setFieldAmount(sfTakerGets,
XRP(11));
724 ac.view().insert(sleNew);
732 using namespace test::jtx;
736 {{
"XRP net change of -1000000 doesn't match fee 0"},
737 {
"escrow specifies invalid amount"}},
745 sleNew->setFieldAmount(sfAmount,
XRP(-1));
746 ac.view().insert(sleNew);
751 {{
"XRP net change was positive: 100000000000000001"},
752 {
"escrow specifies invalid amount"}},
763 ac.view().insert(sleNew);
769 {{
"escrow specifies invalid amount"}},
781 sleNew->setFieldAmount(sfAmount, amt);
782 ac.view().insert(sleNew);
788 {{
"escrow specifies invalid amount"}},
799 sleNew->setFieldAmount(sfAmount, amt);
800 ac.view().insert(sleNew);
806 {{
"escrow specifies invalid amount"}},
818 sleNew->setFieldAmount(sfAmount, amt);
819 ac.view().insert(sleNew);
825 {{
"escrow specifies invalid amount"}},
836 sleNew->setFieldU64(sfOutstandingAmount, -1);
837 ac.view().insert(sleNew);
843 {{
"escrow specifies invalid amount"}},
854 sleNew->setFieldU64(sfLockedAmount, -1);
855 ac.view().insert(sleNew);
861 {{
"escrow specifies invalid amount"}},
872 sleNew->setFieldU64(sfOutstandingAmount, 1);
873 sleNew->setFieldU64(sfLockedAmount, 10);
874 ac.view().insert(sleNew);
880 {{
"escrow specifies invalid amount"}},
891 sleNew->setFieldU64(sfMPTAmount, -1);
892 ac.view().insert(sleNew);
898 {{
"escrow specifies invalid amount"}},
909 sleNew->setFieldU64(sfLockedAmount, -1);
910 ac.view().insert(sleNew);
918 using namespace test::jtx;
919 testcase <<
"valid new account root";
922 {{
"account root created illegally"}},
929 ac.view().insert(sleNew);
934 {{
"multiple accounts created in a single transaction"}},
941 ac.view().insert(sleA3);
947 ac.view().insert(sleA4);
953 {{
"account created with wrong starting sequence number"}},
959 sleNew->setFieldU32(sfSequence, ac.view().seq() + 1);
960 ac.view().insert(sleNew);
967 {{
"pseudo-account created by a wrong transaction type"}},
972 sleNew->setFieldU32(sfSequence, 0);
973 sleNew->setFieldH256(sfAMMID,
uint256(1));
977 ac.view().insert(sleNew);
984 {{
"account created with wrong starting sequence number"}},
989 sleNew->setFieldU32(sfSequence, ac.view().seq());
990 sleNew->setFieldH256(sfAMMID,
uint256(1));
994 ac.view().insert(sleNew);
1001 {{
"pseudo-account created with wrong flags"}},
1006 sleNew->setFieldU32(sfSequence, 0);
1007 sleNew->setFieldH256(sfAMMID,
uint256(1));
1008 sleNew->setFieldU32(
1010 ac.view().insert(sleNew);
1017 {{
"pseudo-account created with wrong flags"}},
1022 sleNew->setFieldU32(sfSequence, 0);
1023 sleNew->setFieldH256(sfAMMID,
uint256(1));
1024 sleNew->setFieldU32(
1028 ac.view().insert(sleNew);
1038 using namespace test::jtx;
1043 "0000000000000000000000000000000000000001FFFFFFFFFFFFFFFF00000000");
1044 auto makeNFTokenIDs = [&firstNFTID](
unsigned int nftCount) {
1051 for (
int i = 0; i < nftCount; ++i)
1054 *nfTokenTemplate, sfNFToken, [&nftID](
STObject&
object) {
1055 object.setFieldH256(sfNFTokenID, nftID);
1064 {{
"NFT page has invalid size"}},
1068 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(0));
1070 ac.view().insert(nftPage);
1075 {{
"NFT page has invalid size"}},
1079 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(33));
1081 ac.view().insert(nftPage);
1086 {{
"NFTs on page are not sorted"}},
1089 STArray nfTokens = makeNFTokenIDs(2);
1093 nftPage->setFieldArray(sfNFTokens, nfTokens);
1095 ac.view().insert(nftPage);
1100 {{
"NFT contains empty URI"}},
1103 STArray nfTokens = makeNFTokenIDs(1);
1104 nfTokens[0].setFieldVL(sfURI,
Blob{});
1107 nftPage->setFieldArray(sfNFTokens, nfTokens);
1109 ac.view().insert(nftPage);
1114 {{
"NFT page is improperly linked"}},
1118 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1));
1119 nftPage->setFieldH256(
1122 ac.view().insert(nftPage);
1127 {{
"NFT page is improperly linked"}},
1131 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1));
1132 nftPage->setFieldH256(
1135 ac.view().insert(nftPage);
1140 {{
"NFT page is improperly linked"}},
1144 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1));
1145 nftPage->setFieldH256(sfNextPageMin, nftPage->key());
1147 ac.view().insert(nftPage);
1152 {{
"NFT page is improperly linked"}},
1155 STArray nfTokens = makeNFTokenIDs(1);
1158 ++(nfTokens[0].getFieldH256(sfNFTokenID))));
1159 nftPage->setFieldArray(sfNFTokens, std::move(nfTokens));
1160 nftPage->setFieldH256(
1163 ac.view().insert(nftPage);
1168 {{
"NFT found in incorrect page"}},
1171 STArray nfTokens = makeNFTokenIDs(2);
1174 (nfTokens[1].getFieldH256(sfNFTokenID))));
1175 nftPage->setFieldArray(sfNFTokens, std::move(nfTokens));
1177 ac.view().insert(nftPage);
1189 sle->setAccountID(sfOwner, A1);
1190 sle->setFieldU32(sfSequence, 10);
1192 STArray credentials(sfAcceptedCredentials, 2);
1196 cred.setAccountID(sfIssuer, A2);
1199 sfCredentialType,
Slice(credType.c_str(), credType.size()));
1202 sle->setFieldArray(sfAcceptedCredentials, credentials);
1209 using namespace test::jtx;
1213 {{
"permissioned domain with no rules."}},
1217 slePd->setAccountID(sfOwner, A1);
1218 slePd->setFieldU32(sfSequence, 10);
1220 ac.view().insert(slePd);
1227 testcase <<
"PermissionedDomain 2";
1231 {{
"permissioned domain bad credentials size " +
1236 slePd->setAccountID(sfOwner, A1);
1237 slePd->setFieldU32(sfSequence, 10);
1239 STArray credentials(sfAcceptedCredentials, tooBig);
1243 cred.setAccountID(sfIssuer, A2);
1248 Slice(credType.c_str(), credType.size()));
1251 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1252 ac.view().insert(slePd);
1259 testcase <<
"PermissionedDomain 3";
1261 {{
"permissioned domain credentials aren't sorted"}},
1265 slePd->setAccountID(sfOwner, A1);
1266 slePd->setFieldU32(sfSequence, 10);
1268 STArray credentials(sfAcceptedCredentials, 2);
1272 cred.setAccountID(sfIssuer, A2);
1277 Slice(credType.c_str(), credType.size()));
1280 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1281 ac.view().insert(slePd);
1288 testcase <<
"PermissionedDomain 4";
1290 {{
"permissioned domain credentials aren't unique"}},
1294 slePd->setAccountID(sfOwner, A1);
1295 slePd->setFieldU32(sfSequence, 10);
1297 STArray credentials(sfAcceptedCredentials, 2);
1301 cred.setAccountID(sfIssuer, A2);
1302 cred.setFieldVL(sfCredentialType,
Slice(
"cred_type", 9));
1305 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1306 ac.view().insert(slePd);
1313 testcase <<
"PermissionedDomain Set 1";
1315 {{
"permissioned domain with no rules."}},
1325 STArray credentials(sfAcceptedCredentials, 2);
1326 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1327 ac.view().update(slePd);
1336 testcase <<
"PermissionedDomain Set 2";
1338 {{
"permissioned domain bad credentials size " +
1349 STArray credentials(sfAcceptedCredentials, tooBig);
1354 cred.setAccountID(sfIssuer, A2);
1358 Slice(credType.c_str(), credType.size()));
1362 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1363 ac.view().update(slePd);
1372 testcase <<
"PermissionedDomain Set 3";
1374 {{
"permissioned domain credentials aren't sorted"}},
1384 STArray credentials(sfAcceptedCredentials, 2);
1388 cred.setAccountID(sfIssuer, A2);
1393 Slice(credType.c_str(), credType.size()));
1397 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1398 ac.view().update(slePd);
1407 testcase <<
"PermissionedDomain Set 4";
1409 {{
"permissioned domain credentials aren't unique"}},
1419 STArray credentials(sfAcceptedCredentials, 2);
1423 cred.setAccountID(sfIssuer, A2);
1425 sfCredentialType,
Slice(
"cred_type", 9));
1428 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1429 ac.view().update(slePd);
1442 testcase <<
"valid pseudo accounts";
1444 using namespace jtx;
1453 auto [tx, vKeylet] =
1454 vault.create({.owner = a, .asset = xrpAsset});
1457 if (
auto const vSle = env.le(vKeylet); BEAST_EXPECT(vSle))
1459 pseudoAccountID = vSle->at(sfAccount);
1479 "pseudo-account has 0 pseudo-account fields set",
1481 BEAST_EXPECT(sle->at(~sfVaultID));
1486 "pseudo-account sequence changed",
1487 [](
SLE::pointer& sle) { sle->at(sfSequence) = 12345; },
1490 "pseudo-account flags are not set",
1494 "pseudo-account has a regular key",
1496 sle->at(sfRegularKey) =
Account(
"regular").
id();
1501 for (
auto const& mod : mods)
1504 {{mod.expectedFailure}},
1510 ac.view().update(sle);
1522 if (pField == &sfVaultID)
1525 {{
"pseudo-account has 2 pseudo-account fields set"}},
1531 auto const vaultID = ~sle->at(~sfVaultID);
1532 BEAST_EXPECT(vaultID && !sle->isFieldPresent(*pField));
1533 sle->setFieldH256(*pField, *vaultID);
1535 ac.view().update(sle);
1547 {{
"pseudo-account has 0 pseudo-account fields set"},
1548 {
"pseudo-account sequence changed"},
1549 {
"pseudo-account flags are not set"}},
1554 sle->at(sfSequence) = 0;
1555 ac.view().update(sle);
1563 using namespace test::jtx;
1567 {{
"domain doesn't exist"}},
1571 sleOffer->setAccountID(sfAccount, A1);
1572 sleOffer->setFieldAmount(sfTakerPays, A1[
"USD"](10));
1573 sleOffer->setFieldAmount(sfTakerGets,
XRP(1));
1574 ac.view().insert(sleOffer);
1584 "F10D0CC9A0F9A3CBF585B80BE09A186483668FDBDD39AA7E33"
1587 tx.setFieldAmount(sfTakerPays, A1[
"USD"](10));
1588 tx.setFieldAmount(sfTakerGets,
XRP(1));
1594 {{
"hybrid offer is malformed"}},
1602 sleOffer->setAccountID(sfAccount, A2);
1603 sleOffer->setFieldAmount(sfTakerPays, A1[
"USD"](10));
1604 sleOffer->setFieldAmount(sfTakerGets,
XRP(1));
1609 sleOffer->setFieldArray(sfAdditionalBooks, bookArr);
1610 ac.view().insert(sleOffer);
1619 {{
"hybrid offer is malformed"}},
1627 sleOffer->setAccountID(sfAccount, A2);
1628 sleOffer->setFieldAmount(sfTakerPays, A1[
"USD"](10));
1629 sleOffer->setFieldAmount(sfTakerGets,
XRP(1));
1631 sleOffer->setFieldH256(sfDomainID, pdKeylet.
key);
1636 sleOffer->setFieldArray(sfAdditionalBooks, bookArr);
1637 ac.view().insert(sleOffer);
1646 {{
"hybrid offer is malformed"}},
1654 sleOffer->setAccountID(sfAccount, A2);
1655 sleOffer->setFieldAmount(sfTakerPays, A1[
"USD"](10));
1656 sleOffer->setFieldAmount(sfTakerGets,
XRP(1));
1658 sleOffer->setFieldH256(sfDomainID, pdKeylet.
key);
1659 ac.view().insert(sleOffer);
1667 {{
"transaction consumed wrong domains"}},
1673 Keylet const badDomainKeylet =
1680 sleOffer->setAccountID(sfAccount, A2);
1681 sleOffer->setFieldAmount(sfTakerPays, A1[
"USD"](10));
1682 sleOffer->setFieldAmount(sfTakerGets,
XRP(1));
1683 sleOffer->setFieldH256(sfDomainID, pdKeylet.
key);
1684 ac.view().insert(sleOffer);
1692 Keylet const badDomainKey =
1694 tx.setFieldH256(sfDomainID, badDomainKey.
key);
1695 tx.setFieldAmount(sfTakerPays, A1[
"USD"](10));
1696 tx.setFieldAmount(sfTakerGets,
XRP(1));
1701 {{
"domain transaction affected regular offers"}},
1709 sleOffer->setAccountID(sfAccount, A2);
1710 sleOffer->setFieldAmount(sfTakerPays, A1[
"USD"](10));
1711 sleOffer->setFieldAmount(sfTakerGets,
XRP(1));
1712 ac.view().insert(sleOffer);
1722 tx.setFieldH256(sfDomainID, domainKey.
key);
1723 tx.setFieldAmount(sfTakerPays, A1[
"USD"](10));
1724 tx.setFieldAmount(sfTakerGets,
XRP(1));
1752BEAST_DEFINE_TESTSUITE(Invariants, app,
ripple);
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.
State information when applying a tx.
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
A currency issued by an account.
Defines the fields and their attributes within a STObject.
AccountID const & getIssuer() const
void push_back(STObject const &object)
void setFieldH256(SField const &field, uint256 const &)
void setFieldAmount(SField const &field, STAmount const &)
static STObject makeInnerObject(SField const &name)
An immutable linear range of bytes.
void testNoXRPTrustLine()
void run() override
Runs the suite.
void testPermissionedDEX()
void createPermissionedDomain(ApplyContext &ac, std::shared_ptr< SLE > &sle, test::jtx::Account const &A1, test::jtx::Account const &A2)
void testXRPBalanceCheck()
void testNoDeepFreezeTrustLinesWithoutFreeze()
void testNFTokenPageInvariants()
void testValidNewAccountRoot()
void testAccountRootsNotRemoved()
std::function< bool(test::jtx::Account const &a, test::jtx::Account const &b, test::jtx::Env &env)> Preclose
void doInvariantCheck(std::vector< std::string > const &expect_logs, Precheck const &precheck, XRPAmount fee=XRPAmount{}, STTx tx=STTx{ttACCOUNT_SET, [](STObject &) {}}, std::initializer_list< TER > ters={tecINVARIANT_FAILED, tefINVARIANT_FAILED}, Preclose const &preclose={})
Run a specific test case to put the ledger into a state that will be detected by an invariant.
void testValidPseudoAccounts()
void testPermissionedDomainInvariants()
void testAccountRootsDeletedClean()
void testTransactionFeeCheck()
void testTransfersNotFrozen()
Convenience class to test AMM functionality.
Immutable cryptographic account descriptor.
AccountID id() const
Returns the Account ID.
A transaction testing environment.
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Keylet permissionedDomain(AccountID const &account, std::uint32_t seq) noexcept
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
Keylet const & amendments() noexcept
The index of the amendment table.
Keylet nftpage(Keylet const &k, uint256 const &token)
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet escrow(AccountID const &src, std::uint32_t seq) noexcept
An escrow entry.
Keylet nftpage_min(AccountID const &owner)
NFT page keylets.
Keylet nftpage_max(AccountID const &owner)
A keylet for the owner's last possible NFT page.
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Json::Value mint(jtx::Account const &account, std::uint32_t nfTokenTaxon)
Mint an NFToken.
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
FeatureBitset testable_amendments()
XRP_t const XRP
Converts to XRP Issue or STAmount.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
constexpr std::uint32_t tfSetDeepFreeze
std::size_t constexpr maxPermissionedDomainCredentialsArraySize
The maximum number of credentials can be passed in array for permissioned domain.
constexpr XRPAmount INITIAL_XRP
Configure the native currency.
std::array< keyletDesc< AccountID const & >, 6 > const directAccountKeylets
base_uint< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
TER trustDelete(ApplyView &view, std::shared_ptr< SLE > const &sleRippleState, AccountID const &uLowAccountID, AccountID const &uHighAccountID, beast::Journal j)
std::string to_string(base_uint< Bits, Tag > const &a)
LedgerEntryType
Identifiers for on-ledger objects.
MPTID makeMptID(std::uint32_t sequence, AccountID const &account)
std::vector< SField const * > const & getPseudoAccountFields()
TERSubset< CanCvtToTER > TER
constexpr std::uint32_t tfSetFreeze
A pair of SHAMap key and LedgerEntryType.