Compare commits

...
Author SHA1 Message Date
Mayukha Vadari e4a7904bd2 Merge remote-tracking branch 'upstream/develop' into mvadari/rearch/permissioneddomain-entry 2026-10-13 11:40:25 -04:00
Mayukha Vadari 13f7154d50 Merge remote-tracking branch 'upstream/develop' into mvadari/rearch/permissioneddomain-entry
# Conflicts:
#	src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp
2026-10-12 13:15:06 -04:00
Mayukha Vadari d4e470a408 Drop unused include from CredentialHelpers.h 2026-10-05 13:40:00 +01:00
Mayukha Vadari dab55a6bd2 refactor: Use PermissionedDomainEntry everywhere
Migrate every raw PermissionedDomain SLE pointer to
PermissionedDomainEntryR/PermissionedDomainEntryW across the
transactors and helpers that read or peek this ledger entry:
PermissionedDomainSet, PermissionedDomainDelete, Payment, OfferCreate,
VaultCreate, VaultSet, MPTokenIssuanceSet, and the Credential/Vault/DEX
helper functions.

credentials::validDomain and verifyValidDomain now take
PermissionedDomainEntryR const& instead of a raw domainID, since every
call site already has (or can cheaply build) the entry; this also
removes a few duplicate re-fetches of the same domain SLE in Payment
and OfferCreate. permissioned_dex::accountInDomain keeps its uint256
domainID parameter: it has a defensive pre-fetch check against a
zero-key domain that cannot be replicated once the caller has already
constructed the entry, so changing its signature risked losing that
safety net for a signature-only refactor.

Pure pointer migration: no helper moved onto the wrapper, and
Credential/Offer/Vault SLE pointers are untouched.
2026-10-05 13:39:59 +01:00
14 changed files with 71 additions and 48 deletions

No files matched your search

@@ -1,11 +1,11 @@
#pragma once
#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/PermissionedDomainEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Rules.h>
#include <xrpl/protocol/STArray.h>
@@ -48,7 +48,7 @@ valid(STTx const& tx, ReadView const& view, AccountID const& src, beast::Journal
// in preclaim and it returns tecEXPIRED, you should call verifyValidDomain in
// doApply. This will ensure that expired credentials are deleted.
TER
validDomain(ReadView const& view, UInt256 domainID, AccountID const& subject);
validDomain(PermissionedDomainEntryR const& domain, AccountID const& subject);
// This function is only called when we are about to return tecNO_PERMISSION
// because all the checks for the DepositPreauth authorization failed.
@@ -69,7 +69,11 @@ checkArray(STArray const& credentials, unsigned maxSize, beast::Journal j);
// Check expired credentials and for credentials matching DomainID of the ledger
// object
TER
verifyValidDomain(ApplyView& view, AccountID const& account, UInt256 domainID, beast::Journal j);
verifyValidDomain(
ApplyView& view,
AccountID const& account,
PermissionedDomainEntryR const& domain,
beast::Journal j);
/**
* @brief Check whether src is authorized to deposit to dst.
@@ -8,6 +8,7 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/DepositPreauthEntry.h>
#include <xrpl/ledger/entries/PermissionedDomainEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
@@ -206,16 +207,16 @@ valid(STTx const& tx, ReadView const& view, AccountID const& src, beast::Journal
}
TER
validDomain(ReadView const& view, UInt256 domainID, AccountID const& subject)
validDomain(PermissionedDomainEntryR const& domain, AccountID const& subject)
{
// Note, permissioned domain objects can be deleted at any time
auto const slePD = view.read(keylet::permissionedDomain(domainID));
if (!slePD)
if (!domain)
return tecOBJECT_NOT_FOUND;
auto const& view = domain.readView();
auto const closeTime = view.header().parentCloseTime;
bool foundExpired = false;
for (auto const& h : slePD->getFieldArray(sfAcceptedCredentials))
for (auto const& h : domain->getFieldArray(sfAcceptedCredentials))
{
auto const issuer = h.getAccountID(sfIssuer);
auto const type = h.getFieldVL(sfCredentialType);
@@ -333,16 +334,19 @@ checkArray(STArray const& credentials, unsigned maxSize, beast::Journal j)
} // namespace credentials
TER
verifyValidDomain(ApplyView& view, AccountID const& account, UInt256 domainID, beast::Journal j)
verifyValidDomain(
ApplyView& view,
AccountID const& account,
PermissionedDomainEntryR const& domain,
beast::Journal j)
{
auto const slePD = view.read(keylet::permissionedDomain(domainID));
if (!slePD)
if (!domain)
return tecOBJECT_NOT_FOUND;
// Collect all matching credentials on a side, so we can remove expired ones
// We may finish the loop with this collection empty, it's fine.
STVector256 credentials;
for (auto const& h : slePD->getFieldArray(sfAcceptedCredentials))
for (auto const& h : domain->getFieldArray(sfAcceptedCredentials))
{
auto const issuer = h.getAccountID(sfIssuer);
auto const type = h.getFieldVL(sfCredentialType);
@@ -7,6 +7,7 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/PermissionedDomainEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -452,7 +453,8 @@ requireAuth(
sleIssuance->isFlag(lsfMPTRequireAuth),
"xrpl::requireAuth : issuance requires authorization");
// ter = tefINTERNAL | tecOBJECT_NOT_FOUND | tecNO_AUTH | tecEXPIRED
auto const ter = credentials::validDomain(view, *maybeDomainID, account);
PermissionedDomainEntryR const domain(*maybeDomainID, view);
auto const ter = credentials::validDomain(domain, account);
if (isTesSuccess(ter))
{
return ter; // Note: sleToken might be null
@@ -505,7 +507,8 @@ enforceMPTokenAuthorization(
if (!maybeDomainID.has_value())
return false; // LCOV_EXCL_LINE
auto const ter = verifyValidDomain(ctx.view, account, *maybeDomainID, j);
PermissionedDomainEntryR const domain(*maybeDomainID, ctx.view);
auto const ter = verifyValidDomain(ctx.view, account, domain, j);
if (isTesSuccess(ter))
return true;
if (ter == tecEXPIRED)
@@ -6,6 +6,7 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/PermissionedDomainEntry.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
@@ -31,15 +32,15 @@ accountInDomain(ReadView const& view, AccountID const& account, Domain const& do
// LCOV_EXCL_STOP
}
auto const sleDomain = view.read(keylet::permissionedDomain(domainID));
if (!sleDomain)
PermissionedDomainEntryR const domain(domainID, view);
if (!domain)
return false;
// domain owner is in the domain
if (sleDomain->getAccountID(sfOwner) == account)
if (domain->getAccountID(sfOwner) == account)
return true;
auto const& credentials = sleDomain->getFieldArray(sfAcceptedCredentials);
auto const& credentials = domain->getFieldArray(sfAcceptedCredentials);
bool const inDomain = std::ranges::any_of(credentials, [&](auto const& credential) {
auto const sleCred = view.read(
+3 -1
View File
@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/PermissionedDomainEntry.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
@@ -320,7 +321,8 @@ checkVaultDomain(
if (!maybeDomainID)
return tecNO_AUTH;
auto const err = credentials::validDomain(view, *maybeDomainID, subject);
PermissionedDomainEntryR const domain(*maybeDomainID, view);
auto const err = credentials::validDomain(domain, subject);
if (err == tecEXPIRED && suppressExpired == SuppressExpired::Yes)
return tesSUCCESS;
@@ -9,6 +9,7 @@
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/PermissionedDomainEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -245,7 +246,7 @@ OfferCreate::preclaim(PreclaimContext const& ctx)
if (ctx.view.rules().enabled(fixCleanup3_4_0))
{
auto const domainID = ctx.tx[sfDomainID];
auto const sleDomain = ctx.view.read(keylet::permissionedDomain(domainID));
PermissionedDomainEntryR const sleDomain(domainID, ctx.view);
if (!sleDomain)
return tecNO_PERMISSION;
@@ -257,7 +258,7 @@ OfferCreate::preclaim(PreclaimContext const& ctx)
{
// validDomain returns tecNO_AUTH when no matching credential is
// found. Map it to tecNO_PERMISSION to preserve existing behavior.
if (auto const err = credentials::validDomain(ctx.view, domainID, id);
if (auto const err = credentials::validDomain(sleDomain, id);
!isTesSuccess(err) && err != tecEXPIRED)
return tecNO_PERMISSION;
}
@@ -1032,13 +1033,13 @@ OfferCreate::doApply()
if (ctx_.tx.isFieldPresent(sfDomainID) && ctx_.view().rules().enabled(fixCleanup3_4_0))
{
auto const domainID = ctx_.tx[sfDomainID];
auto const sleDomain = ctx_.view().read(keylet::permissionedDomain(domainID));
PermissionedDomainEntryR const sleDomain(domainID, ctx_.view());
if (!sleDomain)
return tecINTERNAL; // LCOV_EXCL_LINE
if (sleDomain->getAccountID(sfOwner) != accountID_)
{
if (auto const err = verifyValidDomain(ctx_.view(), accountID_, domainID, j_);
if (auto const err = verifyValidDomain(ctx_.view(), accountID_, sleDomain, j_);
!isTesSuccess(err))
return err;
}
@@ -7,6 +7,7 @@
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/PermissionedDomainEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
@@ -482,7 +483,8 @@ LoanSet::doApply()
JLOG(j_.warn()) << "Private LoanBroker must have a DomainID.";
return tecNO_AUTH;
}
if (auto const ter = verifyValidDomain(view, borrower, *domainID, j_); !isTesSuccess(ter))
PermissionedDomainEntryR const domain(*domainID, view);
if (auto const ter = verifyValidDomain(view, borrower, domain, j_); !isTesSuccess(ter))
{
if (ter == tecNO_PERMISSION)
{
@@ -6,6 +6,7 @@
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/PermissionedDomainEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
@@ -481,7 +482,7 @@ Payment::preclaim(PreclaimContext const& ctx)
if (ctx.view.rules().enabled(fixCleanup3_4_0))
{
auto const domainID = ctx.tx[sfDomainID];
auto const sleDomain = ctx.view.read(keylet::permissionedDomain(domainID));
PermissionedDomainEntryR const sleDomain(domainID, ctx.view);
if (!sleDomain)
return tecNO_PERMISSION;
@@ -493,7 +494,7 @@ Payment::preclaim(PreclaimContext const& ctx)
return tesSUCCESS;
// validDomain returns tecNO_AUTH when no matching credential is
// found. Map it to tecNO_PERMISSION to preserve existing behavior.
if (auto const err = credentials::validDomain(ctx.view, domainID, acct);
if (auto const err = credentials::validDomain(sleDomain, acct);
!isTesSuccess(err) && err != tecEXPIRED)
return tecNO_PERMISSION;
return tesSUCCESS;
@@ -526,14 +527,14 @@ Payment::doApply()
if (ctx_.tx.isFieldPresent(sfDomainID) && ctx_.view().rules().enabled(fixCleanup3_4_0))
{
auto const domainID = ctx_.tx[sfDomainID];
auto const sleDomain = ctx_.view().read(keylet::permissionedDomain(domainID));
PermissionedDomainEntryR const sleDomain(domainID, ctx_.view());
if (!sleDomain)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const cleanupFor = [&](AccountID const& acct) -> TER {
if (sleDomain->getAccountID(sfOwner) == acct)
return tesSUCCESS;
return verifyValidDomain(ctx_.view(), acct, domainID, j_);
return verifyValidDomain(ctx_.view(), acct, sleDomain, j_);
};
auto const destination = ctx_.tx[sfDestination];
@@ -3,6 +3,8 @@
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/PermissionedDomainEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
@@ -28,7 +30,7 @@ TER
PermissionedDomainDelete::preclaim(PreclaimContext const& ctx)
{
auto const domain = ctx.tx.getFieldH256(sfDomainID);
auto const sleDomain = ctx.view.read(keylet::permissionedDomain(domain));
PermissionedDomainEntryR const sleDomain(domain, ctx.view);
if (!sleDomain)
return tecNO_ENTRY;
@@ -52,10 +54,10 @@ PermissionedDomainDelete::doApply()
ctx_.tx.isFieldPresent(sfDomainID),
"xrpl::PermissionedDomainDelete::doApply : required field present");
auto const slePd = view().peek(keylet::permissionedDomain(ctx_.tx.at(sfDomainID)));
PermissionedDomainEntryW slePd(ctx_.tx.at(sfDomainID), view());
auto const page = (*slePd)[sfOwnerNode];
if (!view().dirRemove(keylet::ownerDir(accountID_), page, slePd->key(), true))
if (!view().dirRemove(keylet::ownerDir(accountID_), page, slePd.key(), true))
{
// LCOV_EXCL_START
JLOG(j_.fatal()) << "Unable to delete permissioned domain directory entry.";
@@ -67,8 +69,8 @@ PermissionedDomainDelete::doApply()
XRPL_ASSERT(
ownerSle && ownerSle->getFieldU32(sfOwnerCount) > 0,
"xrpl::PermissionedDomainDelete::doApply : nonzero owner count");
decreaseOwnerCountForObject(view(), ownerSle, slePd, 1, ctx_.journal);
view().erase(slePd);
decreaseOwnerCountForObject(view(), ownerSle, slePd.mutableRawSle(), 1, ctx_.journal);
slePd.erase();
return tesSUCCESS;
}
@@ -2,12 +2,12 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/entries/PermissionedDomainEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h>
@@ -18,7 +18,6 @@
#include <xrpl/protocol/XRPAmount.h>
#include <xrpl/tx/Transactor.h>
#include <memory>
#include <utility>
namespace xrpl {
@@ -63,8 +62,7 @@ PermissionedDomainSet::preclaim(PreclaimContext const& ctx)
if (ctx.tx.isFieldPresent(sfDomainID))
{
auto const sleDomain =
ctx.view.read(keylet::permissionedDomain(ctx.tx.getFieldH256(sfDomainID)));
PermissionedDomainEntryR const sleDomain(ctx.tx.getFieldH256(sfDomainID), ctx.view);
if (!sleDomain)
return tecNO_ENTRY;
if (sleDomain->getAccountID(sfOwner) != account)
@@ -98,12 +96,11 @@ PermissionedDomainSet::doApply()
if (ctx_.tx.isFieldPresent(sfDomainID))
{
// Modify existing permissioned domain.
auto const slePd =
view().peek(keylet::permissionedDomain(ctx_.tx.getFieldH256(sfDomainID)));
PermissionedDomainEntryW slePd(ctx_.tx.getFieldH256(sfDomainID), view());
if (!slePd)
return tefINTERNAL; // LCOV_EXCL_LINE
slePd->peekFieldArray(sfAcceptedCredentials) = std::move(sortedLE);
view().update(slePd);
slePd.update();
}
else
{
@@ -118,21 +115,21 @@ PermissionedDomainSet::doApply()
bool const fixEnabled = view().rules().enabled(fixCleanup3_1_3);
auto const seq = fixEnabled ? ctx_.tx.getSeqProxy()
: SeqProxy::rawSequence(ctx_.tx.getFieldU32(sfSequence));
Keylet const pdKeylet = keylet::permissionedDomain(accountID_, seq);
auto const slePd = std::make_shared<SLE>(pdKeylet);
PermissionedDomainEntryW slePd(accountID_, seq, view());
slePd.newSLE();
slePd->setAccountID(sfOwner, accountID_);
slePd->setFieldU32(sfSequence, seq.value());
slePd->peekFieldArray(sfAcceptedCredentials) = std::move(sortedLE);
auto const page =
view().dirInsert(keylet::ownerDir(accountID_), pdKeylet, describeOwnerDir(accountID_));
auto const page = view().dirInsert(
keylet::ownerDir(accountID_), slePd.keylet(), describeOwnerDir(accountID_));
if (!page)
return tecDIR_FULL; // LCOV_EXCL_LINE
slePd->setFieldU64(sfOwnerNode, *page);
// If we succeeded, the new entry counts against the creator's reserve.
increaseOwnerCount(view(), ownerSle, {}, 1, ctx_.journal);
view().insert(slePd);
slePd.insert();
}
return tesSUCCESS;
@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/PermissionedDomainEntry.h>
#include <xrpl/protocol/ConfidentialTransfer.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -183,7 +184,7 @@ MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx)
if (*domain != beast::kZero)
{
auto const sleDomain = ctx.view.read(keylet::permissionedDomain(*domain));
PermissionedDomainEntryR const sleDomain(*domain, ctx.view);
if (!sleDomain)
return tecOBJECT_NOT_FOUND;
}
@@ -4,7 +4,9 @@
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/PermissionedDomainEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
@@ -154,7 +156,7 @@ VaultCreate::preclaim(PreclaimContext const& ctx)
if (auto const domain = ctx.tx[~sfDomainID])
{
auto const sleDomain = ctx.view.read(keylet::permissionedDomain(*domain));
PermissionedDomainEntryR const sleDomain(*domain, ctx.view);
if (!sleDomain)
return tecOBJECT_NOT_FOUND;
}
@@ -2,6 +2,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/ledger/entries/PermissionedDomainEntry.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
@@ -106,7 +107,7 @@ VaultSet::preclaim(PreclaimContext const& ctx)
if (*domain != beast::kZero)
{
auto const sleDomain = ctx.view.read(keylet::permissionedDomain(*domain));
PermissionedDomainEntryR const sleDomain(*domain, ctx.view);
if (!sleDomain)
return tecOBJECT_NOT_FOUND;
}
+3 -1
View File
@@ -21,6 +21,7 @@
#include <xrpl/json/to_string.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ApplyViewImpl.h>
#include <xrpl/ledger/entries/PermissionedDomainEntry.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
@@ -1146,7 +1147,8 @@ struct Credentials_test : public beast::unit_test::Suite
auto sleCredAfter = av.read(credKeylet);
BEAST_EXPECT(sleCredAfter && sleCredAfter->isFlag(lsfAccepted));
auto const domTer = xrpl::verifyValidDomain(av, subject.id(), domain, j);
xrpl::PermissionedDomainEntryR const domainEntry(domain, av);
auto const domTer = xrpl::verifyValidDomain(av, subject.id(), domainEntry, j);
sleCredAfter = av.read(credKeylet);
BEAST_EXPECT(sleCredAfter && sleCredAfter->isFlag(lsfAccepted));