Skip to content

Commit

Permalink
Add check unit-tests plush some fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
gregtatcam committed Sep 30, 2024
1 parent 2806acb commit 0f40092
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 4 deletions.
114 changes: 114 additions & 0 deletions src/test/app/MPToken_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <test/jtx/AMM.h>
#include <test/jtx/AMMTest.h>
#include <test/jtx/TestHelpers.h>
#include <test/jtx/check.h>
#include <test/jtx/trust.h>
#include <test/jtx/xchain_bridge.h>
#include <xrpl/protocol/Feature.h>
Expand Down Expand Up @@ -2266,6 +2267,116 @@ class MPToken_test : public beast::unit_test::suite
}
}

void
testCheck(FeatureBitset features)
{
testcase("Check Create/Cash");

using namespace test::jtx;
Account const gw{"gw"};
Account const alice{"alice"};

// MPTokensV2 is disabled
{
Env env{*this, features - featureMPTokensV2};

MPTTester mpt(env, gw, {.holders = {&alice}});
mpt.create(
{.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer});
auto const MPT = mpt["MPT"];
mpt.authorize({.account = &alice});

uint256 const checkId{keylet::check(gw, env.seq(gw)).key};

env(check::create(gw, alice, MPT(100)), ter(temDISABLED));
env.close();

env(check::cash(alice, checkId, MPT(100)), ter(temDISABLED));
env.close();
}

// Insufficient funds
{
Env env{*this, features};
Account const carol{"carol"};

MPTTester mpt(env, gw, {.holders = {&alice, &carol}});
mpt.create(
{.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer});
auto const MPT = mpt["MPT"];
mpt.authorize({.account = &alice});
mpt.pay(gw, alice, 50);

uint256 const checkId{keylet::check(alice, env.seq(alice)).key};

// can create
env(check::create(alice, carol, MPT(100)));
env.close();

// can't cash since alice only has 50 of MPT
env(check::cash(carol, checkId, MPT(100)), ter(tecPATH_PARTIAL));
env.close();

// can cash if DeliverMin is set
// carol is not authorized, MPToken is authorized by CheckCash
env(check::cash(carol, checkId, check::DeliverMin(MPT(50))));
env.close();
BEAST_EXPECT(mpt.checkMPTokenAmount(carol, 50));
BEAST_EXPECT(mpt.checkMPTokenOutstandingAmount(50));
}

// Exceed max amount
{
Env env{*this, features};

MPTTester mpt(env, gw, {.holders = {&alice}});
mpt.create(
{.maxAmt = "100",
.ownerCount = 1,
.holderCount = 0,
.flags = tfMPTCanTransfer});
auto const MPT = mpt["MPT"];

uint256 const checkId{keylet::check(gw, env.seq(gw)).key};

// can create
env(check::create(gw, alice, MPT(200)));
env.close();

// can't cash since the outstanding amount exceeds max amount
env(check::cash(alice, checkId, MPT(200)), ter(tecPATH_PARTIAL));
env.close();

// can cash if DeliverMin is set
env(check::cash(alice, checkId, check::DeliverMin(MPT(100))));
env.close();
BEAST_EXPECT(mpt.checkMPTokenAmount(alice, 100));
BEAST_EXPECT(mpt.checkMPTokenOutstandingAmount(100));
}

// Normal create/cash
{
Env env{*this, features};

MPTTester mpt(env, gw, {.holders = {&alice}});
mpt.create(
{.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer});
auto const MPT = mpt["MPT"];
mpt.authorize({.account = &alice});

uint256 const checkId{keylet::check(gw, env.seq(gw)).key};

env(check::create(gw, alice, MPT(100)));
env.close();

env(check::cash(alice, checkId, MPT(100)));
env.close();

BEAST_EXPECT(mpt.checkMPTokenAmount(alice, 100));
BEAST_EXPECT(mpt.checkMPTokenOutstandingAmount(100));
}
}

public:
void
run() override
Expand Down Expand Up @@ -2310,6 +2421,9 @@ class MPToken_test : public beast::unit_test::suite

// Test path finding
testPath(all);

// Test checks
testCheck(all);
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/xrpld/app/tx/detail/CashCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,9 @@ CashCheck::preclaim(PreclaimContext const& ctx)
// An issuer can always accept their own currency.
if (!value.native() && (value.getIssuer() != dstId))
{
Currency const currency{value.get<Issue>().currency};
if (value.holds<Issue>())
{
Currency const currency{value.get<Issue>().currency};
auto const sleTrustLine =
ctx.view.read(keylet::line(dstId, issuerId, currency));

Expand Down
10 changes: 7 additions & 3 deletions src/xrpld/app/tx/detail/InvariantCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1111,7 +1111,7 @@ ValidMPTIssuance::finalize(
mptokensCreated_ == 0 && mptokensDeleted_ == 0;
}

if (tx.getTxnType() == ttAMM_CREATE)
if (tx.getTxnType() == ttAMM_CREATE || tx.getTxnType() == ttCHECK_CASH)
{
if (mptIssuancesDeleted_ > 0)
{
Expand All @@ -1129,14 +1129,18 @@ ValidMPTIssuance::finalize(
"succeeded while removing MPTokens";
}
// AMM can be created with IOU/MPT or MPT/MPT
else if (mptokensCreated_ > 2)
else if (
(tx.getTxnType() == ttAMM_CREATE && mptokensCreated_ > 2) ||
(tx.getTxnType() == ttCHECK_CASH && mptokensCreated_ > 1))
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance set "
"succeeded while creating MPTokens";
}

return mptIssuancesCreated_ == 0 && mptIssuancesDeleted_ == 0 &&
mptokensCreated_ <= 2 && mptokensDeleted_ == 0;
((tx.getTxnType() == ttAMM_CREATE && mptokensCreated_ <= 2) ||
(tx.getTxnType() == ttCHECK_CASH && mptokensCreated_ <= 1)) &&
mptokensDeleted_ == 0;
}

if (tx.getTxnType() == ttAMM_DELETE ||
Expand Down

0 comments on commit 0f40092

Please sign in to comment.