Compare commits

...

2 Commits

Author SHA1 Message Date
Mayukha Vadari
000596c262 refactor: Move checkExpired onto CredentialEntry
Move the credentials::checkExpired free function onto CredentialEntry
as a const member isExpired(), part of the Wrapped SLEs migration.
Updates all call sites (CredentialHelpers, DepositAuthorized RPC
handler, PermissionedDEXHelpers, CredentialDelete/Accept transactors,
and the Credentials_test gtest) to call the member instead.
2026-10-05 13:45:03 +01:00
Mayukha Vadari
b1a1dde2a6 refactor: Use CredentialEntry everywhere
Replace raw Credential SLE pointers with CredentialEntryR and
CredentialEntryW in the ledger helpers and transactors.
credentials::checkExpired now takes CredentialEntryR const& and
credentials::deleteSLE takes CredentialEntryW&; both stay free
functions. The RPC handler and Credentials_test get the minimal edits
that the new signatures force.

Pure refactor: no amendment and no behavior change.
2026-10-05 13:39:52 +01:00
11 changed files with 65 additions and 54 deletions

View File

@@ -2,6 +2,7 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
@@ -9,6 +10,10 @@
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <cstdint>
#include <limits>
namespace xrpl {
@@ -39,6 +44,17 @@ public:
: Base(keylet::credential(credentialID), view, j)
{
}
// Check if the credential's sfExpiration field has passed the given
// ledger close time.
[[nodiscard]] bool
isExpired(NetClock::time_point const& closed) const
{
std::uint32_t const exp =
Base::operator*()[~sfExpiration].value_or(std::numeric_limits<std::uint32_t>::max());
std::uint32_t const now = closed.time_since_epoch().count();
return now > exp;
}
};
using CredentialEntryR = CredentialEntry<ReadView>;

View File

@@ -2,10 +2,10 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/CredentialEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Rules.h>
#include <xrpl/protocol/STArray.h>
@@ -25,13 +25,9 @@ namespace credentials {
// (and any future pre-authorization modes) as part of authorization (all the
// transfer funds transactions)
// Check if credential sfExpiration field has passed ledger's parentCloseTime
bool
checkExpired(SLE const& sleCredential, NetClock::time_point const& closed);
// Actually remove a credentials object from the ledger
[[nodiscard]] TER
deleteSLE(ApplyView& view, SLE::Ref sleCredential, beast::Journal j);
deleteSLE(ApplyView& view, CredentialEntryW& sleCredential, beast::Journal j);
// Amendment and parameters checks for sfCredentialIDs field
NotTEC

View File

@@ -3,10 +3,10 @@
#include <xrpl/basics/Log.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/CredentialEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
@@ -25,7 +25,6 @@
#include <algorithm>
#include <cstdint>
#include <expected>
#include <limits>
#include <set>
#include <unordered_set>
#include <utility>
@@ -34,15 +33,6 @@
namespace xrpl {
namespace credentials {
bool
checkExpired(SLE const& sleCredential, NetClock::time_point const& closed)
{
std::uint32_t const exp =
sleCredential[~sfExpiration].value_or(std::numeric_limits<std::uint32_t>::max());
std::uint32_t const now = closed.time_since_epoch().count();
return now > exp;
}
[[nodiscard]]
static std::expected<bool, TER>
removeExpired(ApplyView& view, STVector256 const& arr, beast::Journal const j)
@@ -56,10 +46,9 @@ removeExpired(ApplyView& view, STVector256 const& arr, beast::Journal const j)
if (view.rules().enabled(fixCleanup3_4_0) && h.isZero())
return std::unexpected(tecINTERNAL); // LCOV_EXCL_LINE
auto const k = keylet::credential(h);
auto const sleCred = view.peek(k);
CredentialEntryW sleCred(h, view, j);
if (sleCred && checkExpired(*sleCred, closeTime))
if (sleCred && sleCred.isExpired(closeTime))
{
JLOG(j.trace()) << "Credentials are expired. Cred: " << sleCred->getText();
// delete expired credentials even if the transaction failed
@@ -74,7 +63,7 @@ removeExpired(ApplyView& view, STVector256 const& arr, beast::Journal const j)
}
TER
deleteSLE(ApplyView& view, SLE::Ref sleCredential, beast::Journal j)
deleteSLE(ApplyView& view, CredentialEntryW& sleCredential, beast::Journal j)
{
if (!sleCredential)
return tecNO_ENTRY;
@@ -101,7 +90,7 @@ deleteSLE(ApplyView& view, SLE::Ref sleCredential, beast::Journal j)
}
if (isOwner)
decreaseOwnerCountForObject(view, sleAccount, sleCredential, 1, j);
decreaseOwnerCountForObject(view, sleAccount, sleCredential.mutableRawSle(), 1, j);
return tesSUCCESS;
};
@@ -122,7 +111,7 @@ deleteSLE(ApplyView& view, SLE::Ref sleCredential, beast::Journal j)
}
// Remove object from ledger
view.erase(sleCredential);
sleCredential.erase();
return tesSUCCESS;
}
@@ -179,7 +168,7 @@ valid(STTx const& tx, ReadView const& view, AccountID const& src, beast::Journal
// LCOV_EXCL_STOP
}
auto const sleCred = view.read(keylet::credential(h));
CredentialEntryR const sleCred(h, view);
if (!sleCred)
{
JLOG(j.trace()) << "Credential doesn't exist. Cred: " << h;
@@ -218,8 +207,7 @@ validDomain(ReadView const& view, UInt256 domainID, AccountID const& subject)
{
auto const issuer = h.getAccountID(sfIssuer);
auto const type = h.getFieldVL(sfCredentialType);
auto const keyletCredential = keylet::credential(subject, issuer, makeSlice(type));
auto const sleCredential = view.read(keyletCredential);
CredentialEntryR const sleCredential(subject, issuer, makeSlice(type), view);
// We cannot delete expired credentials, that would require ApplyView&
// However we can check if credentials are expired. Expected transaction
@@ -228,7 +216,7 @@ validDomain(ReadView const& view, UInt256 domainID, AccountID const& subject)
// allows expired credentials to be deleted by any transaction.
if (sleCredential)
{
if (checkExpired(*sleCredential, closeTime))
if (sleCredential.isExpired(closeTime))
{
foundExpired = true;
continue;
@@ -249,14 +237,14 @@ TER
authorizedDepositPreauth(ReadView const& view, STVector256 const& credIDs, AccountID const& dst)
{
std::set<std::pair<AccountID, Slice>> sorted;
std::vector<SLE::const_pointer> lifeExtender;
std::vector<CredentialEntryR> lifeExtender;
lifeExtender.reserve(credIDs.size());
for (auto const& h : credIDs)
{
if (view.rules().enabled(fixCleanup3_4_0) && h.isZero())
return tefINTERNAL; // LCOV_EXCL_LINE
auto sleCred = view.read(keylet::credential(h));
CredentialEntryR sleCred(h, view);
if (!sleCred) // already checked in preclaim
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -356,7 +344,7 @@ verifyValidDomain(ApplyView& view, AccountID const& account, UInt256 domainID, b
for (auto const& h : credentials)
{
auto sleCredential = view.read(keylet::credential(h));
CredentialEntryR const sleCredential(h, view);
if (!sleCredential)
continue; // expired, i.e. deleted in credentials::removeExpired

View File

@@ -6,12 +6,13 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/entries/CredentialEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STArray.h>
#include <xrpl/protocol/UintTypes.h>
#include <algorithm>
@@ -42,12 +43,12 @@ accountInDomain(ReadView const& view, AccountID const& account, Domain const& do
auto const& credentials = sleDomain->getFieldArray(sfAcceptedCredentials);
bool const inDomain = std::ranges::any_of(credentials, [&](auto const& credential) {
auto const sleCred = view.read(
keylet::credential(account, credential[sfIssuer], credential[sfCredentialType]));
CredentialEntryR const sleCred(
account, credential[sfIssuer], credential[sfCredentialType], view);
if (!sleCred || !sleCred->isFlag(lsfAccepted))
return false;
return !credentials::checkExpired(*sleCred, view.header().parentCloseTime);
return !sleCred.isExpired(view.header().parentCloseTime);
});
return inDomain;

View File

@@ -11,6 +11,7 @@
#include <xrpl/json/to_string.h> // IWYU pragma: keep
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/CredentialEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DelegateHelpers.h>
@@ -1250,7 +1251,7 @@ removeExpiredCredentials(ApplyView& view, std::vector<UInt256> const& creds, bea
{
for (auto const& index : creds)
{
if (auto const sle = view.peek(keylet::credential(index)))
if (auto sle = CredentialEntryW(index, view, viewJ))
{
if (auto const ter = credentials::deleteSLE(view, sle, viewJ); !isTesSuccess(ter))
{

View File

@@ -9,6 +9,7 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/CredentialEntry.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
@@ -166,10 +167,11 @@ removeCredentialFromLedger(
ServiceRegistry&,
ApplyView& view,
AccountID const&,
UInt256 const&,
SLE::Ref sleDel,
UInt256 const& delIndex,
SLE::Ref,
beast::Journal j)
{
CredentialEntryW sleDel(delIndex, view, j);
return credentials::deleteSLE(view, sleDel, j);
}

View File

@@ -2,6 +2,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/entries/CredentialEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/SponsorHelpers.h>
@@ -63,7 +64,7 @@ CredentialAccept::preclaim(PreclaimContext const& ctx)
return tecNO_ISSUER;
}
auto const sleCred = ctx.view.read(keylet::credential(subject, issuer, credType));
CredentialEntryR const sleCred(subject, issuer, credType, ctx.view);
if (!sleCred)
{
JLOG(ctx.j.warn()) << "No credential: " << to_string(subject) << ", " << to_string(issuer)
@@ -108,12 +109,11 @@ CredentialAccept::doApply()
return ret;
auto const credType(ctx_.tx[sfCredentialType]);
Keylet const credentialKey = keylet::credential(accountID_, issuer, credType);
auto const sleCred = view().peek(credentialKey); // Checked in preclaim()
CredentialEntryW sleCred(accountID_, issuer, credType, view(), j_); // Checked in preclaim()
if (!sleCred)
return tefINTERNAL; // LCOV_EXCL_LINE
if (checkExpired(*sleCred, view().header().parentCloseTime))
if (sleCred.isExpired(view().header().parentCloseTime))
{
JLOG(j_.trace()) << "Credential is expired: " << sleCred->getText();
// delete expired credentials even if the transaction failed
@@ -126,12 +126,12 @@ CredentialAccept::doApply()
// Release the original creation sponsor from the credential (it covered
// the issuer's reserve), then assign the accept tx's sponsor (if any) so
// the credential reflects whoever is now covering the subject's reserve.
decreaseOwnerCountForObject(view(), sleIssuer, sleCred, 1, j_);
removeSponsorFromLedgerEntry(sleCred);
decreaseOwnerCountForObject(view(), sleIssuer, sleCred.mutableRawSle(), 1, j_);
removeSponsorFromLedgerEntry(sleCred.mutableRawSle());
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCred);
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCred.mutableRawSle());
increaseOwnerCount(ctx_.getApplyViewContext(), sleSubject, 1, j_);
view().update(sleCred);
sleCred.update();
return tesSUCCESS;
}

View File

@@ -4,6 +4,7 @@
#include <xrpl/basics/base_uint.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/entries/CredentialEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h> // IWYU pragma: keep
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -114,7 +115,8 @@ CredentialCreate::doApply()
auto const credType(ctx_.tx[sfCredentialType]);
Keylet const credentialKey = keylet::credential(subject, accountID_, credType);
auto const sleCred = std::make_shared<SLE>(credentialKey);
CredentialEntryW sleCred(credentialKey, view(), j_);
sleCred.newSLE();
if (!sleCred)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -160,7 +162,7 @@ CredentialCreate::doApply()
sleCred->setFieldU64(sfIssuerNode, *page);
increaseOwnerCount(ctx_.getApplyViewContext(), sleIssuer, 1, j_);
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCred);
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCred.mutableRawSle());
}
if (subject == accountID_)
@@ -180,7 +182,7 @@ CredentialCreate::doApply()
sleCred->setFieldU64(sfSubjectNode, *page);
}
view().insert(sleCred);
sleCred.insert();
return tesSUCCESS;
}

View File

@@ -2,6 +2,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/entries/CredentialEntry.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
@@ -80,12 +81,12 @@ CredentialDelete::doApply()
auto const issuer = ctx_.tx[~sfIssuer].value_or(accountID_);
auto const credType(ctx_.tx[sfCredentialType]);
auto const sleCred = view().peek(keylet::credential(subject, issuer, credType));
CredentialEntryW sleCred(subject, issuer, credType, view(), j_);
if (!sleCred)
return tefINTERNAL; // LCOV_EXCL_LINE
if ((subject != accountID_) && (issuer != accountID_) &&
!checkExpired(*sleCred, ctx_.view().header().parentCloseTime))
!sleCred.isExpired(ctx_.view().header().parentCloseTime))
{
JLOG(j_.trace()) << "Can't delete non-expired credential.";
return tecNO_PERMISSION;

View File

@@ -16,11 +16,13 @@
#include <test/jtx/txflags.h>
#include <test/jtx/vault.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/strHex.h>
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/json/to_string.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ApplyViewImpl.h>
#include <xrpl/ledger/entries/CredentialEntry.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
@@ -903,7 +905,8 @@ struct Credentials_test : public beast::unit_test::Suite
testcase("deleteSLE fail, bad SLE.");
auto view =
std::make_shared<ApplyViewImpl>(env.current().get(), ApplyFlags::TapNone);
auto ter = xrpl::credentials::deleteSLE(*view, {}, env.journal);
CredentialEntryW sleCred(UInt256{}, *view);
auto ter = xrpl::credentials::deleteSLE(*view, sleCred, env.journal);
BEAST_EXPECT(ter == tecNO_ENTRY);
}
}
@@ -1119,7 +1122,8 @@ struct Credentials_test : public beast::unit_test::Suite
auto const sleCred = env.current()->read(credKeylet);
BEAST_EXPECT(
sleCred &&
xrpl::credentials::checkExpired(*sleCred, env.current()->header().parentCloseTime));
CredentialEntryR(sleCred, *env.current())
.isExpired(env.current()->header().parentCloseTime));
}
// Create an ApplyViewImpl on top of the current closed ledger

View File

@@ -6,7 +6,7 @@
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/json/json_value.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/entries/CredentialEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Indexes.h>
@@ -141,7 +141,7 @@ doDepositAuthorized(rpc::JsonContext& context)
return result;
}
if (credentials::checkExpired(*sleCred, ledger->header().parentCloseTime))
if (CredentialEntryR(sleCred, *ledger).isExpired(ledger->header().parentCloseTime))
{
rpc::injectError(RpcBadCredentials, "credentials are expired", result);
return result;