mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-04 01:06:48 +00:00
116 lines
3.5 KiB
C++
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
|