diff --git a/cmake/RippledSanity.cmake b/cmake/RippledSanity.cmake index 3dd5fb782f..28ce854135 100644 --- a/cmake/RippledSanity.cmake +++ b/cmake/RippledSanity.cmake @@ -2,16 +2,6 @@ convenience variables and sanity checks #]===================================================================] -include(ProcessorCount) - -if (NOT ep_procs) - ProcessorCount(ep_procs) - if (ep_procs GREATER 1) - # never use more than half of cores for EP builds - math (EXPR ep_procs "${ep_procs} / 2") - message (STATUS "Using ${ep_procs} cores for ExternalProject builds.") - endif () -endif () get_property(is_multiconfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) set (CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) diff --git a/src/libxrpl/protocol/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp index 1f061cebdc..b9b583046e 100644 --- a/src/libxrpl/protocol/BuildInfo.cpp +++ b/src/libxrpl/protocol/BuildInfo.cpp @@ -36,7 +36,7 @@ namespace BuildInfo { // and follow the format described at http://semver.org/ //------------------------------------------------------------------------------ // clang-format off -char const* const versionString = "2.5.0-b1" +char const* const versionString = "2.5.0-rc1" // clang-format on #if defined(DEBUG) || defined(SANITIZER) diff --git a/src/libxrpl/protocol/STAmount.cpp b/src/libxrpl/protocol/STAmount.cpp index 845ad6481a..0c72244885 100644 --- a/src/libxrpl/protocol/STAmount.cpp +++ b/src/libxrpl/protocol/STAmount.cpp @@ -581,7 +581,10 @@ canAdd(STAmount const& a, STAmount const& b) return true; } + // LCOV_EXCL_START + UNREACHABLE("STAmount::canAdd : unexpected STAmount type"); return false; + // LCOV_EXCL_STOP } /** @@ -653,8 +656,10 @@ canSubtract(STAmount const& a, STAmount const& b) return false; return true; } - + // LCOV_EXCL_START + UNREACHABLE("STAmount::canSubtract : unexpected STAmount type"); return false; + // LCOV_EXCL_STOP } void diff --git a/src/test/app/EscrowToken_test.cpp b/src/test/app/EscrowToken_test.cpp index da9610f0c3..6ba8c48c93 100644 --- a/src/test/app/EscrowToken_test.cpp +++ b/src/test/app/EscrowToken_test.cpp @@ -21,9 +21,11 @@ #include #include +#include #include #include +#include #include #include @@ -56,27 +58,39 @@ struct EscrowToken_test : public beast::unit_test::suite return 0; } - void - issuerIOUEscrowed( + jtx::PrettyAmount + issuerBalance( jtx::Env& env, jtx::Account const& account, - Currency const& currency, - int const& outstanding, - int const& locked) + Issue const& issue) { Json::Value params; params[jss::account] = account.human(); auto jrr = env.rpc("json", "gateway_balances", to_string(params)); auto const result = jrr[jss::result]; - auto const actualOutstanding = - result[jss::obligations][to_string(currency)]; - BEAST_EXPECT(actualOutstanding == to_string(outstanding)); - if (locked != 0) - { - auto const actualEscrowed = - result[jss::locked][to_string(currency)]; - BEAST_EXPECT(actualEscrowed == to_string(locked)); - } + auto const obligations = + result[jss::obligations][to_string(issue.currency)]; + if (obligations.isNull()) + return {STAmount(issue, 0), account.name()}; + STAmount const amount = amountFromString(issue, obligations.asString()); + return {amount, account.name()}; + } + + jtx::PrettyAmount + issuerEscrowed( + jtx::Env& env, + jtx::Account const& account, + Issue const& issue) + { + Json::Value params; + params[jss::account] = account.human(); + auto jrr = env.rpc("json", "gateway_balances", to_string(params)); + auto const result = jrr[jss::result]; + auto const locked = result[jss::locked][to_string(issue.currency)]; + if (locked.isNull()) + return {STAmount(issue, 0), account.name()}; + STAmount const amount = amountFromString(issue, locked.asString()); + return {amount, account.name()}; } void @@ -136,6 +150,37 @@ struct EscrowToken_test : public beast::unit_test::suite env(escrow::cancel(bob, alice, seq2), finishResult); env.close(); } + + for (bool const withTokenEscrow : {false, true}) + { + auto const amend = + withTokenEscrow ? features : features - featureTokenEscrow; + Env env{*this, amend}; + auto const baseFee = env.current()->fees().base; + auto const alice = Account("alice"); + auto const bob = Account("bob"); + auto const gw = Account{"gateway"}; + auto const USD = gw["USD"]; + env.fund(XRP(5000), alice, bob, gw); + env(fset(gw, asfAllowTrustLineLocking)); + env.close(); + env.trust(USD(10'000), alice, bob); + env.close(); + env(pay(gw, alice, USD(5000))); + env(pay(gw, bob, USD(5000))); + env.close(); + + auto const seq1 = env.seq(alice); + env(escrow::finish(bob, alice, seq1), + escrow::condition(escrow::cb1), + escrow::fulfillment(escrow::fb1), + fee(baseFee * 150), + ter(tecNO_TARGET)); + env.close(); + + env(escrow::cancel(bob, alice, seq1), ter(tecNO_TARGET)); + env.close(); + } } void @@ -865,34 +910,76 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); env.trust(USD(10'000), alice, bob); env.close(); - env(pay(gw, alice, USD(5000))); - env(pay(gw, bob, USD(5000))); + env(pay(gw, alice, USD(5'000))); + env(pay(gw, bob, USD(5'000))); env.close(); + auto const outstandingUSD = USD(10'000); + + // Create & Finish Escrow auto const seq1 = env.seq(alice); - env(escrow::create(alice, bob, USD(1'000)), - escrow::condition(escrow::cb1), - escrow::finish_time(env.now() + 1s), - fee(baseFee * 150), - ter(tesSUCCESS)); - env.close(); - env(escrow::finish(bob, alice, seq1), - escrow::condition(escrow::cb1), - escrow::fulfillment(escrow::fb1), - fee(baseFee * 150), - ter(tesSUCCESS)); - env.close(); + { + auto const preAliceUSD = env.balance(alice, USD); + auto const preBobUSD = env.balance(bob, USD); + env(escrow::create(alice, bob, USD(1'000)), + escrow::condition(escrow::cb1), + escrow::finish_time(env.now() + 1s), + fee(baseFee * 150), + ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT(env.balance(alice, USD) == preAliceUSD - USD(1'000)); + BEAST_EXPECT(env.balance(bob, USD) == preBobUSD); + BEAST_EXPECT( + issuerBalance(env, gw, USD) == outstandingUSD - USD(1'000)); + BEAST_EXPECT(issuerEscrowed(env, gw, USD) == USD(1'000)); + } + { + auto const preAliceUSD = env.balance(alice, USD); + auto const preBobUSD = env.balance(bob, USD); + env(escrow::finish(bob, alice, seq1), + escrow::condition(escrow::cb1), + escrow::fulfillment(escrow::fb1), + fee(baseFee * 150), + ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT(env.balance(alice, USD) == preAliceUSD); + BEAST_EXPECT(env.balance(bob, USD) == preBobUSD + USD(1'000)); + BEAST_EXPECT(issuerBalance(env, gw, USD) == outstandingUSD); + BEAST_EXPECT(issuerEscrowed(env, gw, USD) == USD(0)); + } + + // Create & Cancel Escrow auto const seq2 = env.seq(alice); - env(escrow::create(alice, bob, USD(1'000)), - escrow::condition(escrow::cb2), - escrow::finish_time(env.now() + 1s), - escrow::cancel_time(env.now() + 2s), - fee(baseFee * 150), - ter(tesSUCCESS)); - env.close(); - env(escrow::cancel(bob, alice, seq2), ter(tesSUCCESS)); - env.close(); + { + auto const preAliceUSD = env.balance(alice, USD); + auto const preBobUSD = env.balance(bob, USD); + env(escrow::create(alice, bob, USD(1'000)), + escrow::condition(escrow::cb2), + escrow::finish_time(env.now() + 1s), + escrow::cancel_time(env.now() + 2s), + fee(baseFee * 150), + ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT(env.balance(alice, USD) == preAliceUSD - USD(1'000)); + BEAST_EXPECT(env.balance(bob, USD) == preBobUSD); + BEAST_EXPECT( + issuerBalance(env, gw, USD) == outstandingUSD - USD(1'000)); + BEAST_EXPECT(issuerEscrowed(env, gw, USD) == USD(1'000)); + } + { + auto const preAliceUSD = env.balance(alice, USD); + auto const preBobUSD = env.balance(bob, USD); + env(escrow::cancel(bob, alice, seq2), ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT(env.balance(alice, USD) == preAliceUSD + USD(1'000)); + BEAST_EXPECT(env.balance(bob, USD) == preBobUSD); + BEAST_EXPECT(issuerBalance(env, gw, USD) == outstandingUSD); + BEAST_EXPECT(issuerEscrowed(env, gw, USD) == USD(0)); + } } void @@ -2430,7 +2517,6 @@ struct EscrowToken_test : public beast::unit_test::suite mptGw.authorize({.account = alice}); mptGw.authorize({.account = bob}); auto const MPT = mptGw["MPT"]; - env(pay(gw, alice, MPT(10))); env(pay(gw, bob, MPT(10))); env.close(); @@ -2521,6 +2607,39 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); } + // tecOBJECT_NOT_FOUND: MPT issuance does not exist + { + Env env{*this, features}; + auto const baseFee = env.current()->fees().base; + auto const alice = Account("alice"); + auto const bob = Account("bob"); + env.fund(XRP(10'000), alice, bob); + env.close(); + + auto const seq1 = env.seq(alice); + env.app().openLedger().modify( + [&](OpenView& view, beast::Journal j) { + Sandbox sb(&view, tapNONE); + auto sleNew = + std::make_shared(keylet::escrow(alice, seq1)); + MPTIssue const mpt{ + MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + STAmount amt(mpt, 10); + sleNew->setAccountID(sfDestination, bob); + sleNew->setFieldAmount(sfAmount, amt); + sb.insert(sleNew); + sb.apply(view); + return true; + }); + + env(escrow::finish(bob, alice, seq1), + escrow::condition(escrow::cb1), + escrow::fulfillment(escrow::fb1), + fee(baseFee * 150), + ter(tecOBJECT_NOT_FOUND)); + env.close(); + } + // tecLOCKED: issuer has locked the dest { Env env{*this, features}; @@ -2726,6 +2845,36 @@ struct EscrowToken_test : public beast::unit_test::suite env(escrow::cancel(bob, alice, seq1), ter(tecNO_AUTH)); env.close(); } + + // tecOBJECT_NOT_FOUND: MPT issuance does not exist + { + Env env{*this, features}; + auto const baseFee = env.current()->fees().base; + auto const alice = Account("alice"); + auto const bob = Account("bob"); + env.fund(XRP(10'000), alice, bob); + + auto const seq1 = env.seq(alice); + env.app().openLedger().modify( + [&](OpenView& view, beast::Journal j) { + Sandbox sb(&view, tapNONE); + auto sleNew = + std::make_shared(keylet::escrow(alice, seq1)); + MPTIssue const mpt{ + MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + STAmount amt(mpt, 10); + sleNew->setAccountID(sfDestination, bob); + sleNew->setFieldAmount(sfAmount, amt); + sb.insert(sleNew); + sb.apply(view); + return true; + }); + + env(escrow::cancel(bob, alice, seq1), + fee(baseFee), + ter(tecOBJECT_NOT_FOUND)); + env.close(); + } } void @@ -3603,12 +3752,14 @@ struct EscrowToken_test : public beast::unit_test::suite fee(baseFee * 150)); env.close(); + env(pay(alice, gw, MPT(10'000)), ter(tecPATH_PARTIAL)); env(pay(alice, gw, MPT(9'990))); env(pay(bob, gw, MPT(10'000))); BEAST_EXPECT(env.balance(alice, MPT) == MPT(0)); BEAST_EXPECT(mptEscrowed(env, alice, MPT) == 10); BEAST_EXPECT(env.balance(bob, MPT) == MPT(0)); BEAST_EXPECT(mptEscrowed(env, bob, MPT) == 0); + BEAST_EXPECT(env.balance(gw, MPT) == MPT(10)); mptGw.authorize({.account = bob, .flags = tfMPTUnauthorize}); mptGw.destroy( {.id = mptGw.issuanceID(), diff --git a/src/test/app/Escrow_test.cpp b/src/test/app/Escrow_test.cpp index 37f388d9e7..489997ea0f 100644 --- a/src/test/app/Escrow_test.cpp +++ b/src/test/app/Escrow_test.cpp @@ -372,6 +372,12 @@ struct Escrow_test : public beast::unit_test::suite env.fund(XRP(5000), "alice", "bob", "gw"); env.close(); + // temINVALID_FLAG + env(escrow::create("alice", "bob", XRP(1000)), + escrow::finish_time(env.now() + 5s), + txflags(tfPassive), + ter(temINVALID_FLAG)); + // Finish time is in the past env(escrow::create("alice", "bob", XRP(1000)), escrow::finish_time(env.now() - 5s), diff --git a/src/test/ledger/Invariants_test.cpp b/src/test/ledger/Invariants_test.cpp index ebd2235cc9..6178b413d5 100644 --- a/src/test/ledger/Invariants_test.cpp +++ b/src/test/ledger/Invariants_test.cpp @@ -762,6 +762,153 @@ class Invariants_test : public beast::unit_test::suite ac.view().insert(sleNew); return true; }); + + // IOU < 0 + doInvariantCheck( + {{"escrow specifies invalid amount"}}, + [](Account const& A1, Account const&, ApplyContext& ac) { + // escrow with too-little iou + auto const sle = ac.view().peek(keylet::account(A1.id())); + if (!sle) + return false; + auto sleNew = std::make_shared( + keylet::escrow(A1, (*sle)[sfSequence] + 2)); + + Issue const usd{ + Currency(0x5553440000000000), AccountID(0x4985601)}; + STAmount amt(usd, -1); + sleNew->setFieldAmount(sfAmount, amt); + ac.view().insert(sleNew); + return true; + }); + + // IOU bad currency + doInvariantCheck( + {{"escrow specifies invalid amount"}}, + [](Account const& A1, Account const&, ApplyContext& ac) { + // escrow with bad iou currency + auto const sle = ac.view().peek(keylet::account(A1.id())); + if (!sle) + return false; + auto sleNew = std::make_shared( + keylet::escrow(A1, (*sle)[sfSequence] + 2)); + + Issue const bad{badCurrency(), AccountID(0x4985601)}; + STAmount amt(bad, 1); + sleNew->setFieldAmount(sfAmount, amt); + ac.view().insert(sleNew); + return true; + }); + + // MPT < 0 + doInvariantCheck( + {{"escrow specifies invalid amount"}}, + [](Account const& A1, Account const&, ApplyContext& ac) { + // escrow with too-little mpt + auto const sle = ac.view().peek(keylet::account(A1.id())); + if (!sle) + return false; + auto sleNew = std::make_shared( + keylet::escrow(A1, (*sle)[sfSequence] + 2)); + + MPTIssue const mpt{ + MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + STAmount amt(mpt, -1); + sleNew->setFieldAmount(sfAmount, amt); + ac.view().insert(sleNew); + return true; + }); + + // MPT OutstandingAmount < 0 + doInvariantCheck( + {{"escrow specifies invalid amount"}}, + [](Account const& A1, Account const&, ApplyContext& ac) { + // mpissuance outstanding is negative + auto const sle = ac.view().peek(keylet::account(A1.id())); + if (!sle) + return false; + + MPTIssue const mpt{ + MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + auto sleNew = + std::make_shared(keylet::mptIssuance(mpt.getMptID())); + sleNew->setFieldU64(sfOutstandingAmount, -1); + ac.view().insert(sleNew); + return true; + }); + + // MPT LockedAmount < 0 + doInvariantCheck( + {{"escrow specifies invalid amount"}}, + [](Account const& A1, Account const&, ApplyContext& ac) { + // mpissuance locked is less than locked + auto const sle = ac.view().peek(keylet::account(A1.id())); + if (!sle) + return false; + + MPTIssue const mpt{ + MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + auto sleNew = + std::make_shared(keylet::mptIssuance(mpt.getMptID())); + sleNew->setFieldU64(sfLockedAmount, -1); + ac.view().insert(sleNew); + return true; + }); + + // MPT OutstandingAmount < LockedAmount + doInvariantCheck( + {{"escrow specifies invalid amount"}}, + [](Account const& A1, Account const&, ApplyContext& ac) { + // mpissuance outstanding is less than locked + auto const sle = ac.view().peek(keylet::account(A1.id())); + if (!sle) + return false; + + MPTIssue const mpt{ + MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + auto sleNew = + std::make_shared(keylet::mptIssuance(mpt.getMptID())); + sleNew->setFieldU64(sfOutstandingAmount, 1); + sleNew->setFieldU64(sfLockedAmount, 10); + ac.view().insert(sleNew); + return true; + }); + + // MPT MPTAmount < 0 + doInvariantCheck( + {{"escrow specifies invalid amount"}}, + [](Account const& A1, Account const&, ApplyContext& ac) { + // mptoken amount is negative + auto const sle = ac.view().peek(keylet::account(A1.id())); + if (!sle) + return false; + + MPTIssue const mpt{ + MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + auto sleNew = + std::make_shared(keylet::mptoken(mpt.getMptID(), A1)); + sleNew->setFieldU64(sfMPTAmount, -1); + ac.view().insert(sleNew); + return true; + }); + + // MPT LockedAmount < 0 + doInvariantCheck( + {{"escrow specifies invalid amount"}}, + [](Account const& A1, Account const&, ApplyContext& ac) { + // mptoken locked amount is negative + auto const sle = ac.view().peek(keylet::account(A1.id())); + if (!sle) + return false; + + MPTIssue const mpt{ + MPTIssue{makeMptID(1, AccountID(0x4985601))}}; + auto sleNew = + std::make_shared(keylet::mptoken(mpt.getMptID(), A1)); + sleNew->setFieldU64(sfLockedAmount, -1); + ac.view().insert(sleNew); + return true; + }); } void diff --git a/src/xrpld/app/tx/detail/Escrow.cpp b/src/xrpld/app/tx/detail/Escrow.cpp index a324b317ff..6f52d1a4f2 100644 --- a/src/xrpld/app/tx/detail/Escrow.cpp +++ b/src/xrpld/app/tx/detail/Escrow.cpp @@ -642,7 +642,7 @@ EscrowCreate::doApply() }, amount.asset().value()); !isTesSuccess(ret)) - return ret; + return ret; // LCOV_EXCL_LINE } // increment owner count @@ -878,9 +878,6 @@ EscrowFinish::preclaim(PreclaimContext const& ctx) if (!isXRP(amount)) { - if (!ctx.view.rules().enabled(featureTokenEscrow)) - return temDISABLED; // LCOV_EXCL_LINE - if (auto const ret = std::visit( [&](T const&) { return escrowFinishPreclaimHelper( @@ -1120,15 +1117,13 @@ EscrowFinish::doApply() auto const k = keylet::escrow(ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]); auto const slep = ctx_.view().peek(k); if (!slep) - return ctx_.view().rules().enabled(featureSmartEscrow) ? tecINTERNAL - : tecNO_TARGET; + { + if (ctx_.view().rules().enabled(featureTokenEscrow) || + ctx_.view().rules().enabled(featureSmartEscrow)) + return tecINTERNAL; // LCOV_EXCL_LINE - // Order of processing the release conditions (in order of performance): - // FinishAfter/CancelAfter - // Destination validity (after SmartEscrow is enabled) - // Condition/Fulfillment - // Destination validity (before SmartEscrow is enabled) - // FinishFunction + return tecNO_TARGET; + } // If a cancel time is present, a finish operation should only succeed prior // to that time. fix1571 corrects a logic error in the check that would make @@ -1432,7 +1427,7 @@ escrowCancelPreclaimHelper( keylet::mptIssuance(amount.get().getMptID()); auto const sleIssuance = ctx.view.read(issuanceKey); if (!sleIssuance) - return tecOBJECT_NOT_FOUND; // LCOV_EXCL_LINE + return tecOBJECT_NOT_FOUND; // If the issuer has requireAuth set, check if the account is // authorized @@ -1448,26 +1443,27 @@ escrowCancelPreclaimHelper( TER EscrowCancel::preclaim(PreclaimContext const& ctx) { - auto const k = keylet::escrow(ctx.tx[sfOwner], ctx.tx[sfOfferSequence]); - auto const slep = ctx.view.read(k); - if (!slep) - return tecNO_TARGET; - - AccountID const account = (*slep)[sfAccount]; - STAmount const amount = (*slep)[sfAmount]; - - if (!isXRP(amount)) + if (ctx.view.rules().enabled(featureTokenEscrow)) { - if (!ctx.view.rules().enabled(featureTokenEscrow)) - return temDISABLED; // LCOV_EXCL_LINE + auto const k = keylet::escrow(ctx.tx[sfOwner], ctx.tx[sfOfferSequence]); + auto const slep = ctx.view.read(k); + if (!slep) + return tecNO_TARGET; - if (auto const ret = std::visit( - [&](T const&) { - return escrowCancelPreclaimHelper(ctx, account, amount); - }, - amount.asset().value()); - !isTesSuccess(ret)) - return ret; + AccountID const account = (*slep)[sfAccount]; + STAmount const amount = (*slep)[sfAmount]; + + if (!isXRP(amount)) + { + if (auto const ret = std::visit( + [&](T const&) { + return escrowCancelPreclaimHelper( + ctx, account, amount); + }, + amount.asset().value()); + !isTesSuccess(ret)) + return ret; + } } return tesSUCCESS; } @@ -1478,7 +1474,12 @@ EscrowCancel::doApply() auto const k = keylet::escrow(ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]); auto const slep = ctx_.view().peek(k); if (!slep) + { + if (ctx_.view().rules().enabled(featureTokenEscrow)) + return tecINTERNAL; // LCOV_EXCL_LINE + return tecNO_TARGET; + } if (ctx_.view().rules().enabled(fix1571)) { diff --git a/src/xrpld/app/tx/detail/InvariantCheck.cpp b/src/xrpld/app/tx/detail/InvariantCheck.cpp index 31b8fe3cc1..d93378d3cd 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.cpp +++ b/src/xrpld/app/tx/detail/InvariantCheck.cpp @@ -271,26 +271,6 @@ NoZeroEscrow::visitEntry( std::shared_ptr const& after) { auto isBad = [](STAmount const& amount) { - // IOU case - if (amount.holds()) - { - if (amount <= beast::zero) - return true; - - if (badCurrency() == amount.getCurrency()) - return true; - } - - // MPT case - if (amount.holds()) - { - if (amount <= beast::zero) - return true; - - if (amount.mpt() > MPTAmount{maxMPTokenAmount}) - return true; - } - // XRP case if (amount.native()) { @@ -300,7 +280,28 @@ NoZeroEscrow::visitEntry( if (amount.xrp() >= INITIAL_XRP) return true; } + else + { + // IOU case + if (amount.holds()) + { + if (amount <= beast::zero) + return true; + if (badCurrency() == amount.getCurrency()) + return true; + } + + // MPT case + if (amount.holds()) + { + if (amount <= beast::zero) + return true; + + if (amount.mpt() > MPTAmount{maxMPTokenAmount}) + return true; // LCOV_EXCL_LINE + } + } return false; }; diff --git a/src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.cpp b/src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.cpp index a2e1f33b94..e2b87dbd79 100644 --- a/src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.cpp +++ b/src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.cpp @@ -59,7 +59,7 @@ MPTokenIssuanceDestroy::preclaim(PreclaimContext const& ctx) return tecHAS_OBLIGATIONS; if ((*sleMPT)[~sfLockedAmount].value_or(0) != 0) - return tecHAS_OBLIGATIONS; + return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE return tesSUCCESS; } diff --git a/src/xrpld/ledger/detail/View.cpp b/src/xrpld/ledger/detail/View.cpp index 2949b6e51f..f0c4d335cd 100644 --- a/src/xrpld/ledger/detail/View.cpp +++ b/src/xrpld/ledger/detail/View.cpp @@ -2745,18 +2745,18 @@ rippleLockEscrowMPT( auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); auto sleIssuance = view.peek(mptID); if (!sleIssuance) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleLockEscrowMPT: MPT issuance not found for " << mptIssue.getMptID(); - return tecOBJECT_NOT_FOUND; // LCOV_EXCL_LINE - } + return tecOBJECT_NOT_FOUND; + } // LCOV_EXCL_STOP if (amount.getIssuer() == sender) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleLockEscrowMPT: sender is the issuer, cannot lock MPTs."; - return tecINTERNAL; // LCOV_EXCL_LINE - } + return tecINTERNAL; + } // LCOV_EXCL_STOP // 1. Decrease the MPT Holder MPTAmount // 2. Increase the MPT Holder EscrowedAmount @@ -2764,23 +2764,23 @@ rippleLockEscrowMPT( auto const mptokenID = keylet::mptoken(mptID.key, sender); auto sle = view.peek(mptokenID); if (!sle) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleLockEscrowMPT: MPToken not found for " << sender; - return tecOBJECT_NOT_FOUND; // LCOV_EXCL_LINE - } + return tecOBJECT_NOT_FOUND; + } // LCOV_EXCL_STOP auto const amt = sle->getFieldU64(sfMPTAmount); auto const pay = amount.mpt().value(); // Underflow check for subtraction if (!canSubtract(STAmount(mptIssue, amt), STAmount(mptIssue, pay))) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleLockEscrowMPT: insufficient MPTAmount for " << to_string(sender) << ": " << amt << " < " << pay; - return tecINTERNAL; // LCOV_EXCL_LINE - } + return tecINTERNAL; + } // LCOV_EXCL_STOP (*sle)[sfMPTAmount] = amt - pay; @@ -2788,12 +2788,12 @@ rippleLockEscrowMPT( uint64_t const locked = (*sle)[~sfLockedAmount].value_or(0); if (!canAdd(STAmount(mptIssue, locked), STAmount(mptIssue, pay))) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleLockEscrowMPT: overflow on locked amount for " << to_string(sender) << ": " << locked << " + " << pay; - return tecINTERNAL; // LCOV_EXCL_LINE - } + return tecINTERNAL; + } // LCOV_EXCL_STOP if (sle->isFieldPresent(sfLockedAmount)) (*sle)[sfLockedAmount] += pay; @@ -2813,13 +2813,13 @@ rippleLockEscrowMPT( // Overflow check for addition if (!canAdd( STAmount(mptIssue, issuanceEscrowed), STAmount(mptIssue, pay))) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleLockEscrowMPT: overflow on issuance " "locked amount for " << mptIssue.getMptID() << ": " << issuanceEscrowed << " + " << pay; - return tecINTERNAL; // LCOV_EXCL_LINE - } + return tecINTERNAL; + } // LCOV_EXCL_STOP if (sleIssuance->isFieldPresent(sfLockedAmount)) (*sleIssuance)[sfLockedAmount] += pay; @@ -2844,21 +2844,21 @@ rippleUnlockEscrowMPT( auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); auto sleIssuance = view.peek(mptID); if (!sleIssuance) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleUnlockEscrowMPT: MPT issuance not found for " << mptIssue.getMptID(); - return tecOBJECT_NOT_FOUND; // LCOV_EXCL_LINE - } + return tecOBJECT_NOT_FOUND; + } // LCOV_EXCL_STOP // Decrease the Issuance EscrowedAmount { if (!sleIssuance->isFieldPresent(sfLockedAmount)) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleUnlockEscrowMPT: no locked amount in issuance for " << mptIssue.getMptID(); - return tecINTERNAL; // LCOV_EXCL_LINE - } + return tecINTERNAL; + } // LCOV_EXCL_STOP auto const locked = sleIssuance->getFieldU64(sfLockedAmount); auto const redeem = amount.mpt().value(); @@ -2866,12 +2866,12 @@ rippleUnlockEscrowMPT( // Underflow check for subtraction if (!canSubtract( STAmount(mptIssue, locked), STAmount(mptIssue, redeem))) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleUnlockEscrowMPT: insufficient locked amount for " << mptIssue.getMptID() << ": " << locked << " < " << redeem; - return tecINTERNAL; // LCOV_EXCL_LINE - } + return tecINTERNAL; + } // LCOV_EXCL_STOP auto const newLocked = locked - redeem; if (newLocked == 0) @@ -2887,23 +2887,23 @@ rippleUnlockEscrowMPT( auto const mptokenID = keylet::mptoken(mptID.key, receiver); auto sle = view.peek(mptokenID); if (!sle) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleUnlockEscrowMPT: MPToken not found for " << receiver; return tecOBJECT_NOT_FOUND; // LCOV_EXCL_LINE - } + } // LCOV_EXCL_STOP auto current = sle->getFieldU64(sfMPTAmount); auto delta = amount.mpt().value(); // Overflow check for addition if (!canAdd(STAmount(mptIssue, current), STAmount(mptIssue, delta))) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleUnlockEscrowMPT: overflow on MPTAmount for " << to_string(receiver) << ": " << current << " + " << delta; - return tecINTERNAL; // LCOV_EXCL_LINE - } + return tecINTERNAL; + } // LCOV_EXCL_STOP (*sle)[sfMPTAmount] += delta; view.update(sle); @@ -2917,55 +2917,56 @@ rippleUnlockEscrowMPT( // Underflow check for subtraction if (!canSubtract( STAmount(mptIssue, outstanding), STAmount(mptIssue, redeem))) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleUnlockEscrowMPT: insufficient outstanding amount for " << mptIssue.getMptID() << ": " << outstanding << " < " << redeem; - return tecINTERNAL; // LCOV_EXCL_LINE - } + return tecINTERNAL; + } // LCOV_EXCL_STOP sleIssuance->setFieldU64(sfOutstandingAmount, outstanding - redeem); view.update(sleIssuance); } if (issuer == sender) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleUnlockEscrowMPT: sender is the issuer, " "cannot unlock MPTs."; - return tecINTERNAL; // LCOV_EXCL_LINE - } + return tecINTERNAL; + } // LCOV_EXCL_STOP else { // Decrease the MPT Holder EscrowedAmount auto const mptokenID = keylet::mptoken(mptID.key, sender); auto sle = view.peek(mptokenID); if (!sle) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleUnlockEscrowMPT: MPToken not found for " << sender; - return tecOBJECT_NOT_FOUND; // LCOV_EXCL_LINE - } + return tecOBJECT_NOT_FOUND; + } // LCOV_EXCL_STOP if (!sle->isFieldPresent(sfLockedAmount)) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleUnlockEscrowMPT: no locked amount in MPToken for " << to_string(sender); - return tecINTERNAL; // LCOV_EXCL_LINE - } + return tecINTERNAL; + } // LCOV_EXCL_STOP auto const locked = sle->getFieldU64(sfLockedAmount); auto const delta = amount.mpt().value(); // Underflow check for subtraction + // LCOV_EXCL_START if (!canSubtract(STAmount(mptIssue, locked), STAmount(mptIssue, delta))) - { + { // LCOV_EXCL_START JLOG(j.error()) << "rippleUnlockEscrowMPT: insufficient locked amount for " << to_string(sender) << ": " << locked << " < " << delta; - return tecINTERNAL; // LCOV_EXCL_LINE - } + return tecINTERNAL; + } // LCOV_EXCL_STOP auto const newLocked = locked - delta; if (newLocked == 0)