Files
rippled/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp

116 lines
3.5 KiB
C++

#include <xrpl/basics/Log.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/CredentialHelpers.h>
#include <xrpl/ledger/View.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/TxFlags.h>
#include <xrpl/tx/transactors/credentials/CredentialAccept.h>
#include <chrono>
namespace xrpl {
using namespace credentials;
std::uint32_t
CredentialAccept::getFlagsMask(PreflightContext const& ctx)
{
// 0 means "Allow any flags"
return ctx.rules.enabled(fixInvalidTxFlags) ? tfUniversalMask : 0;
}
NotTEC
CredentialAccept::preflight(PreflightContext const& ctx)
{
if (!ctx.tx[sfIssuer])
{
JLOG(ctx.j.trace()) << "Malformed transaction: Issuer field zeroed.";
return temINVALID_ACCOUNT_ID;
}
auto const credType = ctx.tx[sfCredentialType];
if (credType.empty() || (credType.size() > maxCredentialTypeLength))
{
JLOG(ctx.j.trace()) << "Malformed transaction: invalid size of CredentialType.";
return temMALFORMED;
}
return tesSUCCESS;
}
TER
CredentialAccept::preclaim(PreclaimContext const& ctx)
{
AccountID const subject = ctx.tx[sfAccount];
AccountID const issuer = ctx.tx[sfIssuer];
auto const credType(ctx.tx[sfCredentialType]);
if (!ctx.view.exists(keylet::account(issuer)))
{
JLOG(ctx.j.warn()) << "No issuer: " << to_string(issuer);
return tecNO_ISSUER;
}
auto const sleCred = ctx.view.read(keylet::credential(subject, issuer, credType));
if (!sleCred)
{
JLOG(ctx.j.warn()) << "No credential: " << to_string(subject) << ", " << to_string(issuer)
<< ", " << credType;
return tecNO_ENTRY;
}
if (sleCred->getFieldU32(sfFlags) & lsfAccepted)
{
JLOG(ctx.j.warn()) << "Credential already accepted: " << to_string(subject) << ", "
<< to_string(issuer) << ", " << credType;
return tecDUPLICATE;
}
return tesSUCCESS;
}
TER
CredentialAccept::doApply()
{
AccountID const issuer{ctx_.tx[sfIssuer]};
// Both exist as credential object exist itself (checked in preclaim)
auto const sleSubject = view().peek(keylet::account(account_));
auto const sleIssuer = view().peek(keylet::account(issuer));
if (!sleSubject || !sleIssuer)
return tefINTERNAL; // LCOV_EXCL_LINE
auto const newSponsor = getTxReserveSponsor(view(), ctx_.tx);
if (auto const ret =
checkInsufficientReserve(view(), ctx_.tx, sleSubject, mPriorBalance, newSponsor, 1);
!isTesSuccess(ret))
return ret;
auto const credType(ctx_.tx[sfCredentialType]);
Keylet const credentialKey = keylet::credential(account_, issuer, credType);
auto const sleCred = view().peek(credentialKey); // Checked in preclaim()
auto const currentSponsor = getLedgerEntryReserveSponsor(view(), sleCred);
if (checkExpired(sleCred, view().header().parentCloseTime))
{
JLOG(j_.trace()) << "Credential is expired: " << sleCred->getText();
// delete expired credentials even if the transaction failed
auto const err = credentials::deleteSLE(view(), sleCred, j_);
return isTesSuccess(err) ? tecEXPIRED : err;
}
sleCred->setFieldU32(sfFlags, lsfAccepted);
view().update(sleCred);
adjustOwnerCount(view(), sleIssuer, currentSponsor, -1, j_);
removeSponsorFromLedgerEntry(sleCred);
adjustOwnerCount(view(), sleSubject, newSponsor, 1, j_);
addSponsorToLedgerEntry(sleCred, newSponsor);
return tesSUCCESS;
}
} // namespace xrpl