Files
rippled/src/libxrpl/tx/transactors/check/CheckCancel.cpp

119 lines
3.4 KiB
C++

#include <xrpl/tx/transactors/check/CheckCancel.h>
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/STTx.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/XRPAmount.h>
#include <xrpl/tx/Transactor.h>
#include <cstdint>
#include <memory>
namespace xrpl {
NotTEC
CheckCancel::preflight(PreflightContext const& ctx)
{
return tesSUCCESS;
}
TER
CheckCancel::preclaim(PreclaimContext const& ctx)
{
auto const sleCheck = ctx.view.read(keylet::check(ctx.tx[sfCheckID]));
if (!sleCheck)
{
JLOG(ctx.j.warn()) << "Check does not exist.";
return tecNO_ENTRY;
}
// Expiration is defined in terms of the close time of the parent
// ledger, because we definitively know the time that it closed but
// we do not know the closing time of the ledger that is under
// construction.
if (!hasExpired(ctx.view, (*sleCheck)[~sfExpiration]))
{
// If the check is not yet expired, then only the creator or the
// destination may cancel the check.
AccountID const acctId{ctx.tx[sfAccount]};
if (acctId != (*sleCheck)[sfAccount] && acctId != (*sleCheck)[sfDestination])
{
JLOG(ctx.j.warn()) << "Check is not expired and canceler is "
"neither check source nor destination.";
return tecNO_PERMISSION;
}
}
return tesSUCCESS;
}
TER
CheckCancel::doApply()
{
auto const sleCheck = view().peek(keylet::check(ctx_.tx[sfCheckID]));
if (!sleCheck)
{
// Error should have been caught in preclaim.
JLOG(j_.warn()) << "Check does not exist.";
return tecNO_ENTRY;
}
AccountID const srcId{sleCheck->getAccountID(sfAccount)};
AccountID const dstId{sleCheck->getAccountID(sfDestination)};
auto viewJ = ctx_.registry.get().getJournal("View");
// If the check is not written to self (and it shouldn't be), remove the
// check from the destination account root.
if (srcId != dstId)
{
std::uint64_t const page{(*sleCheck)[sfDestinationNode]};
if (!view().dirRemove(keylet::ownerDir(dstId), page, sleCheck->key(), true))
{
// LCOV_EXCL_START
JLOG(j_.fatal()) << "Unable to delete check from destination.";
return tefBAD_LEDGER;
// LCOV_EXCL_STOP
}
}
{
std::uint64_t const page{(*sleCheck)[sfOwnerNode]};
if (!view().dirRemove(keylet::ownerDir(srcId), page, sleCheck->key(), true))
{
// LCOV_EXCL_START
JLOG(j_.fatal()) << "Unable to delete check from owner.";
return tefBAD_LEDGER;
// LCOV_EXCL_STOP
}
}
// If we succeeded, update the check owner's reserve.
auto const sleSrc = view().peek(keylet::account(srcId));
adjustOwnerCount(view(), sleSrc, -1, viewJ);
// Remove check from ledger.
view().erase(sleCheck);
return tesSUCCESS;
}
void
CheckCancel::visitInvariantEntry(
bool,
std::shared_ptr<SLE const> const&,
std::shared_ptr<SLE const> const&)
{
}
bool
CheckCancel::finalizeInvariants(STTx const&, TER, XRPAmount, ReadView const&, beast::Journal const&)
{
return true;
}
} // namespace xrpl