20 #include <ripple/app/tx/apply.h>
21 #include <ripple/app/tx/impl/ApplyContext.h>
22 #include <ripple/app/tx/impl/Transactor.h>
23 #include <ripple/beast/utility/Journal.h>
24 #include <ripple/protocol/STLedgerEntry.h>
25 #include <boost/algorithm/string/predicate.hpp>
27 #include <test/jtx/Env.h>
51 using namespace test::jtx;
56 env.fund(
XRP(1000), A1, A2);
59 OpenView ov{*env.current()};
67 safe_cast<FeeUnit64>(env.current()->fees().units),
71 BEAST_EXPECT(precheck(A1, A2, ac));
74 if (!BEAST_EXPECT(ters.
size() == 2))
78 for (
TER const terExpect : ters)
80 terActual = ac.checkInvariants(terActual, fee);
81 BEAST_EXPECT(terExpect == terActual);
84 sink.messages().str(),
"Invariant failed:") ||
86 sink.messages().str(),
"Transaction caused an exception"));
89 for (
auto const& m : expect_logs)
92 sink.messages().str().find(m) != std::string::npos);
100 using namespace test::jtx;
101 testcase <<
"XRP created";
103 {{
"XRP net change was positive: 500"}},
104 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
109 auto amt = sle->getFieldAmount(
sfBalance);
111 ac.view().update(sle);
119 using namespace test::jtx;
120 testcase <<
"account root removed";
124 {{
"an account root was deleted"}},
125 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
130 ac.view().erase(sle);
140 {{
"account deletion succeeded without deleting an account"}},
150 {{
"account deletion succeeded but deleted multiple accounts"}},
151 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
155 if (!sleA1 || !sleA2)
157 ac.view().erase(sleA1);
158 ac.view().erase(sleA2);
168 using namespace test::jtx;
169 testcase <<
"ledger entry types don't match";
171 {{
"ledger entry type mismatch"},
172 {
"XRP net change of -1000000000 doesn't match fee 0"}},
173 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
178 auto sleNew = std::make_shared<SLE>(
ltTICKET, sle->key());
179 ac.rawView().rawReplace(sleNew);
184 {{
"invalid ledger entry type added"}},
185 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
193 auto sleNew = std::make_shared<SLE>(
196 ac.view().insert(sleNew);
204 using namespace test::jtx;
205 testcase <<
"trust lines with XRP not allowed";
207 {{
"an XRP trust line was created"}},
208 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
213 ac.view().insert(sleNew);
221 using namespace test::jtx;
222 testcase <<
"XRP balance checks";
225 {{
"Cannot return non-native STAmount as XRPAmount"}},
226 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
232 sle->setFieldAmount(
sfBalance, nonNative);
233 ac.view().update(sle);
238 {{
"incorrect account XRP balance"},
239 {
"XRP net change was positive: 99999999000000001"}},
240 [
this](Account
const& A1, Account
const&,
ApplyContext& ac) {
248 BEAST_EXPECT(!sle->getFieldAmount(
sfBalance).negative());
249 ac.view().update(sle);
254 {{
"incorrect account XRP balance"},
255 {
"XRP net change of -1000000001 doesn't match fee 0"}},
256 [
this](Account
const& A1, Account
const&,
ApplyContext& ac) {
262 BEAST_EXPECT(sle->getFieldAmount(
sfBalance).negative());
263 ac.view().update(sle);
271 using namespace test::jtx;
272 using namespace std::string_literals;
273 testcase <<
"Transaction fee checks";
276 {{
"fee paid was negative: -1"},
277 {
"XRP net change of 0 doesn't match fee -1"}},
278 [](Account
const&, Account
const&,
ApplyContext&) {
return true; },
283 {
"XRP net change of 0 doesn't match fee "s +
285 [](Account
const&, Account
const&,
ApplyContext&) {
return true; },
289 {{
"fee paid is 20 exceeds fee specified in transaction."},
290 {
"XRP net change of 0 doesn't match fee 20"}},
291 [](Account
const&, Account
const&,
ApplyContext&) {
return true; },
301 using namespace test::jtx;
302 testcase <<
"no bad offers";
305 {{
"offer with a bad amount"}},
306 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
311 auto const offer_index =
313 auto sleNew = std::make_shared<SLE>(
ltOFFER, offer_index);
314 sleNew->setAccountID(
sfAccount, A1.id());
317 ac.view().insert(sleNew);
322 {{
"offer with a bad amount"}},
323 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
328 auto const offer_index =
330 auto sleNew = std::make_shared<SLE>(
ltOFFER, offer_index);
331 sleNew->setAccountID(
sfAccount, A1.id());
333 sleNew->setFieldAmount(
sfTakerPays, A1[
"USD"](10));
335 ac.view().insert(sleNew);
340 {{
"offer with a bad amount"}},
341 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
346 auto const offer_index =
348 auto sleNew = std::make_shared<SLE>(
ltOFFER, offer_index);
349 sleNew->setAccountID(
sfAccount, A1.id());
353 ac.view().insert(sleNew);
361 using namespace test::jtx;
362 testcase <<
"no zero escrow";
365 {{
"Cannot return non-native STAmount as XRPAmount"}},
366 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
371 auto sleNew = std::make_shared<SLE>(
374 sleNew->setFieldAmount(
sfAmount, nonNative);
375 ac.view().insert(sleNew);
380 {{
"XRP net change of -1000000 doesn't match fee 0"},
381 {
"escrow specifies invalid amount"}},
382 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
387 auto sleNew = std::make_shared<SLE>(
389 sleNew->setFieldAmount(
sfAmount, XRP(-1));
390 ac.view().insert(sleNew);
395 {{
"XRP net change was positive: 100000000000000001"},
396 {
"escrow specifies invalid amount"}},
397 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
402 auto sleNew = std::make_shared<SLE>(
407 ac.view().insert(sleNew);
415 using namespace test::jtx;
416 testcase <<
"valid new account root";
419 {{
"account root created by a non-Payment"}},
423 const Account A3{
"A3"};
425 auto const sleNew = std::make_shared<SLE>(acctKeylet);
426 ac.view().insert(sleNew);
431 {{
"multiple accounts created in a single transaction"}},
435 const Account A3{
"A3"};
437 auto const sleA3 = std::make_shared<SLE>(acctKeylet);
438 ac.view().insert(sleA3);
441 const Account A4{
"A4"};
443 auto const sleA4 = std::make_shared<SLE>(acctKeylet);
444 ac.view().insert(sleA4);
450 {{
"account created with wrong starting sequence number"}},
453 const Account A3{
"A3"};
455 auto const sleNew = std::make_shared<SLE>(acctKeylet);
456 sleNew->setFieldU32(
sfSequence, ac.view().seq() + 1);
457 ac.view().insert(sleNew);
const XRP_t XRP
Converts to XRP Issue or STAmount.
A pair of SHAMap key and LedgerEntryType.
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
void testValidNewAccountRoot()
void testXRPBalanceCheck()
const SF_U32 sfSequence(access, STI_UINT32, 4, "Sequence")
uint256 getOfferIndex(AccountID const &account, std::uint32_t uSequence)
const SF_Account sfAccount(access, STI_ACCOUNT, 1, "Account")
const SF_Amount sfTakerPays(access, STI_AMOUNT, 4, "TakerPays")
std::string to_string(ListDisposition disposition)
const SF_Amount sfAmount(access, STI_AMOUNT, 1, "Amount")
constexpr XRPAmount INITIAL_XRP
Configure the native currency.
void testAccountRootsNotRemoved()
void setFieldAmount(SField const &field, STAmount const &)
static const account_t account
uint256 getRippleStateIndex(AccountID const &a, AccountID const &b, Currency const ¤cy)
void testNoXRPTrustLine()
TERSubset< CanCvtToTER > TER
Keylet escrow(AccountID const &source, std::uint32_t seq)
An escrow entry.
State information when applying a tx.
A generic endpoint for log messages.
const SF_Amount sfFee(access, STI_AMOUNT, 8, "Fee")
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
const SF_Amount sfBalance(access, STI_AMOUNT, 2, "Balance")
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})
const SF_Amount sfTakerGets(access, STI_AMOUNT, 5, "TakerGets")
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Immutable cryptographic account descriptor.
void testTransactionFeeCheck()