Skip to content

Commit

Permalink
Invariants and error code
Browse files Browse the repository at this point in the history
  • Loading branch information
shawnxie999 committed Jan 17, 2024
1 parent 9e43eb2 commit 791a008
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 103 deletions.
199 changes: 104 additions & 95 deletions src/ripple/app/tx/impl/InvariantCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,9 @@ ValidMPTIssuance::visitEntry(
mptIssuancesDeleted_++;
else if (!before)
mptIssuancesCreated_++;

if ((*after)[sfOutstandingAmount] > (*after)[~sfMaximumAmount].value_or(maxMPTokenAmount))
amountExceededMax_ = true;
}

if (after && after->getType() == ltMPTOKEN)
Expand All @@ -834,116 +837,118 @@ ValidMPTIssuance::finalize(
ReadView const& _view,
beast::Journal const& j)
{
if (tx.getTxnType() == ttMPTOKEN_ISSUANCE_CREATE && result == tesSUCCESS)
{
if (mptIssuancesCreated_ == 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance creation "
"succeeded without creating a MPT issuance";
}
else if (mptIssuancesDeleted_ != 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance creation "
"succeeded while removing MPT issuances";
}
else if (mptIssuancesCreated_ > 1)
if (result == tesSUCCESS){
if (tx.getTxnType() == ttMPTOKEN_ISSUANCE_CREATE)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance creation "
"succeeded but created multiple issuances";
}

return mptIssuancesCreated_ == 1 && mptIssuancesDeleted_ == 0;
}
if (mptIssuancesCreated_ == 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance creation "
"succeeded without creating a MPT issuance";
}
else if (mptIssuancesDeleted_ != 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance creation "
"succeeded while removing MPT issuances";
}
else if (mptIssuancesCreated_ > 1)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance creation "
"succeeded but created multiple issuances";
}

if (tx.getTxnType() == ttMPTOKEN_ISSUANCE_DESTROY && result == tesSUCCESS)
{
if (mptIssuancesDeleted_ == 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance deletion "
"succeeded without removing a MPT issuance";
}
else if (mptIssuancesCreated_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance deletion "
"succeeded while creating MPT issuances";
}
else if (mptIssuancesDeleted_ > 1)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance deletion "
"succeeded but deleted multiple issuances";
return mptIssuancesCreated_ == 1 && mptIssuancesDeleted_ == 0;
}

return mptIssuancesCreated_ == 0 && mptIssuancesDeleted_ == 1;
}

if (tx.getTxnType() == ttMPTOKEN_AUTHORIZE && result == tesSUCCESS)
{
bool const submittedByIssuer = tx.isFieldPresent(sfMPTokenHolder);

if (mptIssuancesCreated_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT authorize "
"succeeded but created MPT issuances";
return false;
}
else if (mptIssuancesDeleted_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT authorize "
"succeeded but deleted issuances";
return false;
}
else if (
submittedByIssuer && (mptokensCreated_ > 0 || mptokensDeleted_ > 0))
if (tx.getTxnType() == ttMPTOKEN_ISSUANCE_DESTROY)
{
JLOG(j.fatal())
<< "Invariant failed: MPT authorize submitted by issuer "
"succeeded but created/deleted mptokens";
return false;
if (mptIssuancesDeleted_ == 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance deletion "
"succeeded without removing a MPT issuance";
}
else if (mptIssuancesCreated_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance deletion "
"succeeded while creating MPT issuances";
}
else if (mptIssuancesDeleted_ > 1)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance deletion "
"succeeded but deleted multiple issuances";
}

return mptIssuancesCreated_ == 0 && mptIssuancesDeleted_ == 1;
}
else if (
!submittedByIssuer && (mptokensCreated_ + mptokensDeleted_ != 1))

if (tx.getTxnType() == ttMPTOKEN_AUTHORIZE)
{
// if the holder submitted this tx, then a mptoken must be either
// created or deleted.
JLOG(j.fatal())
<< "Invariant failed: MPT authorize submitted by holder "
"succeeded but created/deleted bad number of mptokens";
return false;
}
bool const submittedByIssuer = tx.isFieldPresent(sfMPTokenHolder);

return true;
}
if (mptIssuancesCreated_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT authorize "
"succeeded but created MPT issuances";
return false;
}
else if (mptIssuancesDeleted_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT authorize "
"succeeded but deleted issuances";
return false;
}
else if (
submittedByIssuer && (mptokensCreated_ > 0 || mptokensDeleted_ > 0))
{
JLOG(j.fatal())
<< "Invariant failed: MPT authorize submitted by issuer "
"succeeded but created/deleted mptokens";
return false;
}
else if (
!submittedByIssuer && (mptokensCreated_ + mptokensDeleted_ != 1))
{
// if the holder submitted this tx, then a mptoken must be either
// created or deleted.
JLOG(j.fatal())
<< "Invariant failed: MPT authorize submitted by holder "
"succeeded but created/deleted bad number of mptokens";
return false;
}

if (tx.getTxnType() == ttMPTOKEN_ISSUANCE_SET && result == tesSUCCESS)
{
if (mptIssuancesDeleted_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance set "
"succeeded while removing MPT issuances";
}
else if (mptIssuancesCreated_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance set "
"succeeded while creating MPT issuances";
}
else if (mptokensDeleted_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance set "
"succeeded while removing MPTokens";
return true;
}
else if (mptokensCreated_ > 0)

if (tx.getTxnType() == ttMPTOKEN_ISSUANCE_SET )
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance set "
"succeeded while creating MPTokens";
}
if (mptIssuancesDeleted_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance set "
"succeeded while removing MPT issuances";
}
else if (mptIssuancesCreated_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance set "
"succeeded while creating MPT issuances";
}
else if (mptokensDeleted_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance set "
"succeeded while removing MPTokens";
}
else if (mptokensCreated_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: MPT issuance set "
"succeeded while creating MPTokens";
}

return mptIssuancesCreated_ == 0 && mptIssuancesDeleted_ == 0 &&
mptokensCreated_ == 0 && mptokensDeleted_ == 0;
return mptIssuancesCreated_ == 0 && mptIssuancesDeleted_ == 0 &&
mptokensCreated_ == 0 && mptokensDeleted_ == 0;
}
}

if (mptIssuancesCreated_ != 0)
{
JLOG(j.fatal()) << "Invariant failed: a MPT issuance was created";
JLOG(j.fatal()) << "Invariant failed: a MPT issuance was created";
}
else if (mptIssuancesDeleted_ != 0)
{
Expand All @@ -957,9 +962,13 @@ ValidMPTIssuance::finalize(
{
JLOG(j.fatal()) << "Invariant failed: a MPToken was deleted";
}
else if (amountExceededMax_)
{
JLOG(j.fatal()) << "Invariant failed: OutstandingAmount exceeded MaximumAmount";
}

return mptIssuancesCreated_ == 0 && mptIssuancesDeleted_ == 0 &&
mptokensCreated_ == 0 && mptokensDeleted_ == 0;
mptokensCreated_ == 0 && mptokensDeleted_ == 0 && !amountExceededMax_;
}

} // namespace ripple
2 changes: 2 additions & 0 deletions src/ripple/app/tx/impl/InvariantCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,8 @@ class ValidMPTIssuance
std::uint32_t mptokensCreated_ = 0;
std::uint32_t mptokensDeleted_ = 0;

bool amountExceededMax_ = false;

public:
void
visitEntry(
Expand Down
2 changes: 1 addition & 1 deletion src/ripple/app/tx/impl/Payment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ Payment::doApply()
if (account_ != issuer && uDstAccountID != issuer &&
(isFrozen(view(), account_, issue) ||
isFrozen(view(), uDstAccountID, issue)))
return tecFROZEN;
return tecMPT_LOCKED;

PaymentSandbox pv(&view());
auto const res =
Expand Down
2 changes: 1 addition & 1 deletion src/ripple/ledger/impl/View.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1738,7 +1738,7 @@ rippleMPTCredit(

// TODO: Replace maxAmt const with a variable
if (sle->getFieldU64(sfOutstandingAmount) >
(*sle)[~sfMaximumAmount].value_or(0x7FFFFFFFFFFFFFFFull))
(*sle)[~sfMaximumAmount].value_or(maxMPTokenAmount))
return tecMPT_MAX_AMOUNT_EXCEEDED;

view.update(sle);
Expand Down
3 changes: 3 additions & 0 deletions src/ripple/protocol/Protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ std::size_t constexpr maxDomainLength = 256;
/** The maximum length of MPTokenMetadata */
std::size_t constexpr maxMPTokenMetadataLength = 1024;

/** The maximum amount of MPTokenIssuance */
std::uint64_t constexpr maxMPTokenAmount = 0x7FFFFFFFFFFFFFFFull;

/** A ledger index. */
using LedgerIndex = std::uint32_t;

Expand Down
3 changes: 2 additions & 1 deletion src/ripple/protocol/TER.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,8 @@ enum TECcodes : TERUnderlyingType {
tecXCHAIN_CREATE_ACCOUNT_DISABLED = 186,
tecEMPTY_DID = 187,
tecMPTOKEN_EXISTS = 188,
tecMPT_MAX_AMOUNT_EXCEEDED = 189
tecMPT_MAX_AMOUNT_EXCEEDED = 189,
tecMPT_LOCKED = 190

};

Expand Down
1 change: 1 addition & 0 deletions src/ripple/protocol/impl/TER.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ transResults()
MAKE_ERROR(tecEMPTY_DID, "The DID object did not have a URI or DIDDocument field."),
MAKE_ERROR(tecMPTOKEN_EXISTS, "The account already owns the MPToken object."),
MAKE_ERROR(tecMPT_MAX_AMOUNT_EXCEEDED, "The MPT's maximum amount is exceeded."),
MAKE_ERROR(tecMPT_LOCKED, "MPT is locked by the issuer."),

MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
Expand Down
10 changes: 5 additions & 5 deletions src/test/app/MPToken_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -739,8 +739,8 @@ class MPToken_test : public beast::unit_test::suite
// Global lock
mptAlice.set({.account = &alice, .flags = tfMPTLock});
// Can't send between holders
mptAlice.pay(bob, carol, 1, tecFROZEN);
mptAlice.pay(carol, bob, 2, tecFROZEN);
mptAlice.pay(bob, carol, 1, tecMPT_LOCKED);
mptAlice.pay(carol, bob, 2, tecMPT_LOCKED);
// Issuer can send
mptAlice.pay(alice, bob, 3);
// Holder can send back to issuer
Expand All @@ -752,8 +752,8 @@ class MPToken_test : public beast::unit_test::suite
mptAlice.set(
{.account = &alice, .holder = &bob, .flags = tfMPTLock});
// Can't send between holders
mptAlice.pay(bob, carol, 5, tecFROZEN);
mptAlice.pay(carol, bob, 6, tecFROZEN);
mptAlice.pay(bob, carol, 5, tecMPT_LOCKED);
mptAlice.pay(carol, bob, 6, tecMPT_LOCKED);
// Issuer can send
mptAlice.pay(alice, bob, 7);
// Holder can send back to issuer
Expand Down Expand Up @@ -791,7 +791,7 @@ class MPToken_test : public beast::unit_test::suite
mptAlice.authorize({.account = &bob});

// issuer sends holder the default max amount allowed
mptAlice.pay(alice, bob, 0x7FFFFFFFFFFFFFFFull);
mptAlice.pay(alice, bob, maxMPTokenAmount);

// issuer tries to exceed max amount
mptAlice.pay(alice, bob, 1, tecMPT_MAX_AMOUNT_EXCEEDED);
Expand Down

0 comments on commit 791a008

Please sign in to comment.