Skip to content

Commit f234682

Browse files
committed
add a boatload of tests (AI)
1 parent 530e09d commit f234682

8 files changed

Lines changed: 2021 additions & 25 deletions

File tree

src/test/app/Invariants_test.cpp

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <test/jtx/mpt.h>
88
#include <test/jtx/pay.h>
99
#include <test/jtx/permissioned_domains.h>
10+
#include <test/jtx/sig.h>
11+
#include <test/jtx/sponsor.h>
1012
#include <test/jtx/tags.h>
1113
#include <test/jtx/token.h>
1214
#include <test/jtx/trust.h>
@@ -5769,6 +5771,139 @@ class Invariants_test : public beast::unit_test::Suite
57695771
return true;
57705772
});
57715773
}
5774+
5775+
{
5776+
// XRPNotCreated: the sfFeeAmount escrowed in a Sponsorship entry
5777+
// counts toward the XRP total. Creating a Sponsorship holding a
5778+
// FeeAmount without debiting any account manufactures XRP.
5779+
doInvariantCheck(
5780+
{{"XRP net change was positive: 100000000"}},
5781+
[](Account const& a1, Account const& a2, ApplyContext& ac) {
5782+
auto const sleNew =
5783+
std::make_shared<SLE>(keylet::sponsorship(a1.id(), a2.id()));
5784+
sleNew->setAccountID(sfOwner, a1.id());
5785+
sleNew->setAccountID(sfSponsee, a2.id());
5786+
sleNew->setFieldAmount(sfFeeAmount, XRP(100));
5787+
ac.view().insert(sleNew);
5788+
return true;
5789+
});
5790+
5791+
// ... and deleting a Sponsorship entry without refunding its
5792+
// escrowed FeeAmount destroys XRP beyond the transaction fee.
5793+
doInvariantCheck(
5794+
{{"XRP net change of -100000000 doesn't match fee 0"}},
5795+
[](Account const& a1, Account const& a2, ApplyContext& ac) {
5796+
auto const sle = ac.view().peek(keylet::sponsorship(a2.id(), a1.id()));
5797+
if (!sle)
5798+
return false;
5799+
ac.view().erase(sle);
5800+
return true;
5801+
},
5802+
XRPAmount{},
5803+
STTx{ttACCOUNT_SET, [](STObject&) {}},
5804+
{tecINVARIANT_FAILED, tefINVARIANT_FAILED},
5805+
[](Account const& a1, Account const& a2, Env& env) {
5806+
// a2 sponsors a1's fees with a pre-funded XRP(100)
5807+
env(sponsor::set_fee(a2, 0, XRP(100)), sponsor::SponseeAcc(a1));
5808+
env.close();
5809+
return env.le(keylet::sponsorship(a2.id(), a1.id())) != nullptr;
5810+
});
5811+
}
5812+
5813+
{
5814+
// Deleting a sponsored object without adjusting the accounts'
5815+
// Sponsored/SponsoringOwnerCount fields must be caught (the
5816+
// isDelete path of SponsorshipOwnerCountsMatch::visitEntry: the
5817+
// sponsored-object delta is -1 while the account deltas are 0).
5818+
auto const expectMessage =
5819+
"SponsoredObjectOwnerCount does not equal SponsoredOwnerCount delta.";
5820+
uint256 checkID;
5821+
5822+
doInvariantCheck(
5823+
{{expectMessage}},
5824+
[&](Account const&, Account const&, ApplyContext& ac) {
5825+
auto const check = ac.view().peek(keylet::check(checkID));
5826+
if (!check)
5827+
return false;
5828+
ac.view().erase(check);
5829+
return true;
5830+
},
5831+
XRPAmount{},
5832+
STTx{ttACCOUNT_SET, [](STObject&) {}},
5833+
{tecINVARIANT_FAILED, tefINVARIANT_FAILED},
5834+
[&checkID](Account const& a1, Account const& a2, Env& env) {
5835+
// a2 reserve-sponsors a1's check by co-signing its creation
5836+
checkID = keylet::check(a1.id(), env.seq(a1)).key;
5837+
env(check::create(a1, a2, XRP(1)),
5838+
sponsor::As(a2, spfSponsorReserve),
5839+
Sig(sfSponsorSignature, a2),
5840+
Fee(XRP(1)));
5841+
env.close();
5842+
auto const sle = env.le(keylet::check(checkID));
5843+
return sle && sle->isFieldPresent(sfSponsor);
5844+
});
5845+
}
5846+
5847+
{
5848+
// Trust lines use sfLowSponsor/sfHighSponsor instead of sfSponsor
5849+
// and can be reserve-sponsored independently on each side.
5850+
auto const expectMessage =
5851+
"SponsoredObjectOwnerCount does not equal SponsoredOwnerCount delta.";
5852+
5853+
auto const preclose = [](Account const& a1, Account const& a2, Env& env) {
5854+
env(trust(a1, a2["USD"](100)));
5855+
return true;
5856+
};
5857+
5858+
// Marking one side of an existing trust line as sponsored without
5859+
// touching any account counts (object delta 1, account deltas 0).
5860+
doInvariantCheck(
5861+
{{expectMessage}},
5862+
[](Account const& a1, Account const& a2, ApplyContext& ac) {
5863+
auto const line = ac.view().peek(keylet::trustLine(a1, a2, a2["USD"].currency));
5864+
if (!line)
5865+
return false;
5866+
line->setAccountID(sfLowSponsor, a2.id());
5867+
ac.view().update(line);
5868+
return true;
5869+
},
5870+
XRPAmount{},
5871+
STTx{ttACCOUNT_SET, [](STObject&) {}},
5872+
{tecINVARIANT_FAILED, tefINVARIANT_FAILED},
5873+
preclose);
5874+
5875+
// A trust line sponsored on both sides contributes two sponsored
5876+
// owner counts, so bumping the account fields by only one each is
5877+
// caught (object delta 2, account deltas 1).
5878+
doInvariantCheck(
5879+
{{expectMessage}},
5880+
[](Account const& a1, Account const& a2, ApplyContext& ac) {
5881+
auto const line = ac.view().peek(keylet::trustLine(a1, a2, a2["USD"].currency));
5882+
if (!line)
5883+
return false;
5884+
line->setAccountID(sfLowSponsor, a2.id());
5885+
line->setAccountID(sfHighSponsor, a2.id());
5886+
ac.view().update(line);
5887+
5888+
// a1 owns the trust line, so its OwnerCount is already 1.
5889+
auto const sponsee = ac.view().peek(keylet::account(a1.id()));
5890+
if (!sponsee)
5891+
return false;
5892+
sponsee->setFieldU32(sfSponsoredOwnerCount, 1);
5893+
ac.view().update(sponsee);
5894+
5895+
auto const sponsoring = ac.view().peek(keylet::account(a2.id()));
5896+
if (!sponsoring)
5897+
return false;
5898+
sponsoring->setFieldU32(sfSponsoringOwnerCount, 1);
5899+
ac.view().update(sponsoring);
5900+
return true;
5901+
},
5902+
XRPAmount{},
5903+
STTx{ttACCOUNT_SET, [](STObject&) {}},
5904+
{tecINVARIANT_FAILED, tefINVARIANT_FAILED},
5905+
preclose);
5906+
}
57725907
}
57735908

57745909
void

0 commit comments

Comments
 (0)