Compare commits

...
Author SHA1 Message Date
Mayukha Vadari 2978330bf9 Document isIndividualFrozen parameters and return value 2026-10-05 15:45:02 +01:00
Mayukha Vadari d4acfcdb20 refactor: Move isIndividualFrozen onto RippleStateEntry
Add the const member RippleStateEntry::isIndividualFrozen(account,
issuer), which checks lsfHighFreeze or lsfLowFreeze by comparing the
two account IDs, exactly as the free function did. The free function
stays as a shim that handles XRP, the issuer itself, and a missing
line.
2026-10-05 15:44:25 +01:00
Mayukha Vadari 699d9b1656 Document creditLimit and creditBalance parameters and return value 2026-10-05 15:44:19 +01:00
Mayukha Vadari a705d48033 refactor: Move creditLimit and creditBalance onto RippleStateEntry
Add const members RippleStateEntry::creditLimit(account, issuer) and
creditBalance(account, issuer) that hold the field logic. The free
functions stay as shims: they build the entry, call the member when
the line exists, and return zero otherwise, as before.

creditLimit2 reads no fields; it only converts the creditLimit shim
result, so it stays unchanged.
2026-10-05 13:56:56 +01:00
Mayukha Vadari 0c743ea776 refactor: Use RippleStateEntry everywhere
Replace raw RippleState SLE pointers in libxrpl ledger helpers, path
steps, and transactors with RippleStateEntryR / RippleStateEntryW.
Reads become RippleStateEntryR, peeks become RippleStateEntryW, and
insert/update/erase go through the entry.

trustDelete() and deleteAMMTrustLine() now take a RippleStateEntryW&,
and the file-local helpers updateTrustLine(), getLineIfUsable() and
getTrustLineBalance() take or return entries. They stay free
functions. deleteAMMTrustLine() reads the reserve flag before
trustDelete(), because erase() now drops the entry's SLE; the flag is
not changed by trustDelete(), so the result is the same.

Tests: InvariantsMisc_test builds a RippleStateEntryW for the changed
trustDelete() signature. TheoreticalQuality_test no longer declares
its PaymentSandbox const, because read-only entries peek() through an
ApplyView, which is undefined behavior on a const object.

Pure refactor: no amendment, no behavior change.
2026-10-05 13:39:40 +01:00
23 changed files with 182 additions and 113 deletions

No files matched your search

@@ -8,6 +8,8 @@
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/UintTypes.h>
namespace xrpl {
@@ -40,6 +42,53 @@ public:
: Base(keylet::trustLine(id, issue), view, j)
{
}
/**
* Returns the limit that @p account sets on this line for IOUs issued
* by @p issuer. The issuer of the result is @p account.
*
* @param account the account whose limit is returned.
* @param issuer the account on the other side of the line.
* @return the limit @p account sets on this line.
*/
[[nodiscard]] STAmount
creditLimit(AccountID const& account, AccountID const& issuer) const
{
STAmount result = (*this)->getFieldAmount(account < issuer ? sfLowLimit : sfHighLimit);
result.get<Issue>().account = account;
return result;
}
/**
* Returns the amount of IOUs issued by @p issuer that @p account holds
* on this line. The issuer of the result is @p account.
*
* @param account the account whose balance is returned.
* @param issuer the account on the other side of the line.
* @return the balance @p account holds on this line.
*/
[[nodiscard]] STAmount
creditBalance(AccountID const& account, AccountID const& issuer) const
{
STAmount result = (*this)->getFieldAmount(sfBalance);
if (account < issuer)
result.negate();
result.get<Issue>().account = account;
return result;
}
/**
* Returns true if @p issuer froze this line for @p account.
*
* @param account the account whose side of the line is checked.
* @param issuer the account on the other side of the line.
* @return true if @p issuer froze this line for @p account.
*/
[[nodiscard]] bool
isIndividualFrozen(AccountID const& account, AccountID const& issuer) const
{
return (*this)->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze);
}
};
using RippleStateEntryR = RippleStateEntry<ReadView>;
+2 -1
View File
@@ -4,6 +4,7 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
@@ -149,7 +150,7 @@ escrowUnlockApplyHelper<Issue>(
// of the funds
if (!createAsset)
{
auto const sleRippleState = ctx.view.peek(trustLineKey);
RippleStateEntryW const sleRippleState(trustLineKey, ctx.view, journal);
if (!sleRippleState)
return tecINTERNAL; // LCOV_EXCL_LINE
@@ -4,6 +4,7 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/IOUAmount.h>
@@ -165,7 +166,7 @@ trustCreate(
[[nodiscard]] TER
trustDelete(
ApplyView& view,
SLE::Ref sleRippleState,
RippleStateEntryW& sleRippleState,
AccountID const& uLowAccountID,
AccountID const& uHighAccountID,
beast::Journal j);
@@ -270,7 +271,7 @@ removeEmptyHolding(
[[nodiscard]] TER
deleteAMMTrustLine(
ApplyView& view,
SLE::pointer sleState,
RippleStateEntryW& sleState,
std::optional<AccountID> const& ammAccountID,
beast::Journal j);
+4 -3
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/RippleStateEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -33,7 +34,7 @@ checkFreeze(
}
}
if (auto sle = view.read(keylet::trustLine(src, dst, currency)))
if (RippleStateEntryR const sle(src, dst, currency, view); sle)
{
if (sle->isFlag((dst > src) ? lsfHighFreeze : lsfLowFreeze))
{
@@ -77,8 +78,8 @@ checkNoRipple(
beast::Journal j)
{
// fetch the ripple lines into and out of this node
auto sleIn = view.read(keylet::trustLine(prev, cur, currency));
auto sleOut = view.read(keylet::trustLine(cur, next, currency));
RippleStateEntryR const sleIn(prev, cur, currency, view);
RippleStateEntryR const sleOut(cur, next, currency, view);
if (!sleIn || !sleOut)
return terNO_LINE;
+6 -3
View File
@@ -11,6 +11,7 @@
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
@@ -21,6 +22,7 @@
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/MPTIssue.h>
#include <xrpl/protocol/Protocol.h>
@@ -556,7 +558,7 @@ ammLPHolds(
auto const currency = ammLPTCurrency(asset1, asset2);
STAmount amount;
auto const sle = view.read(keylet::trustLine(lpAccount, ammAccount, currency));
RippleStateEntryR const sle(lpAccount, ammAccount, currency, view);
if (!sle)
{
amount.clear(Issue{currency, ammAccount});
@@ -646,7 +648,7 @@ ammAccountHolds(ReadView const& view, AccountID const& ammAccountID, Asset const
}
else if (
auto const sle =
view.read(keylet::trustLine(ammAccountID, issue.account, issue.currency));
RippleStateEntryR(ammAccountID, issue.account, issue.currency, view);
sle && !isFrozen(view, ammAccountID, issue.currency, issue.account))
{
STAmount amount = (*sle)[sfBalance];
@@ -688,7 +690,8 @@ deleteAMMTrustLines(
// LCOV_EXCL_STOP
}
return {deleteAMMTrustLine(sb, sleItem, ammAccountID, j), SkipEntry::No};
RippleStateEntryW line(Keylet(ltRIPPLE_STATE, sleItem->key()), sb, j);
return {deleteAMMTrustLine(sb, line, ammAccountID, j), SkipEntry::No};
}
// LCOV_EXCL_START
JLOG(j.error()) << "deleteAMMObjects: deleting non-trustline or non-MPT " << nodeType;
@@ -7,6 +7,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
@@ -841,7 +842,7 @@ tokenOfferCreatePreclaim(
if (view.rules().enabled(featureNFTokenMintOffer))
{
if (nftIssuer != amount.getIssuer() &&
!view.read(keylet::trustLine(nftIssuer, amount.get<Issue>())))
!RippleStateEntryR(nftIssuer, amount.get<Issue>(), view))
return tecNO_LINE;
}
else if (!view.exists(keylet::trustLine(nftIssuer, amount.get<Issue>())))
@@ -1028,7 +1029,7 @@ checkTrustlineAuthorized(
if (issuerAccount->isFlag(lsfRequireAuth))
{
auto const trustLine = view.read(keylet::trustLine(id, issue.account, issue.currency));
RippleStateEntryR const trustLine(id, issue.account, issue.currency, view);
if (!trustLine)
{
@@ -1078,7 +1079,7 @@ checkTrustlineDeepFrozen(
return tesSUCCESS;
}
auto const trustLine = view.read(keylet::trustLine(id, issue.account, issue.currency));
RippleStateEntryR const trustLine(id, issue.account, issue.currency, view);
if (!trustLine)
{
@@ -7,6 +7,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/SponsorHelpers.h>
@@ -48,13 +49,10 @@ creditLimit(
{
STAmount result(Issue{currency, account});
auto sleRippleState = view.read(keylet::trustLine(account, issuer, currency));
RippleStateEntryR const sleRippleState(account, issuer, currency, view);
if (sleRippleState)
{
result = sleRippleState->getFieldAmount(account < issuer ? sfLowLimit : sfHighLimit);
result.get<Issue>().account = account;
}
result = sleRippleState.creditLimit(account, issuer);
XRPL_ASSERT(result.getIssuer() == account, "xrpl::creditLimit : result issuer match");
XRPL_ASSERT(
@@ -79,15 +77,10 @@ creditBalance(
{
STAmount result(Issue{currency, account});
auto sleRippleState = view.read(keylet::trustLine(account, issuer, currency));
RippleStateEntryR const sleRippleState(account, issuer, currency, view);
if (sleRippleState)
{
result = sleRippleState->getFieldAmount(sfBalance);
if (account < issuer)
result.negate();
result.get<Issue>().account = account;
}
result = sleRippleState.creditBalance(account, issuer);
XRPL_ASSERT(result.getIssuer() == account, "xrpl::creditBalance : result issuer match");
XRPL_ASSERT(
@@ -115,8 +108,8 @@ isIndividualFrozen(
if (issuer != account)
{
// Check if the issuer froze the line
auto const sle = view.read(keylet::trustLine(account, issuer, currency));
if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
RippleStateEntryR const sle(account, issuer, currency, view);
if (sle && sle.isIndividualFrozen(account, issuer))
return true;
}
return false;
@@ -139,8 +132,8 @@ isFrozen(
if (issuer != account)
{
// Check if the issuer froze the line
sle = view.read(keylet::trustLine(account, issuer, currency));
if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
RippleStateEntryR const sleLine(account, issuer, currency, view);
if (sleLine && sleLine->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
return true;
}
return false;
@@ -163,7 +156,7 @@ isDeepFrozen(
return false;
}
auto const sle = view.read(keylet::trustLine(account, issuer, currency));
RippleStateEntryR const sle(account, issuer, currency, view);
if (!sle)
{
return false;
@@ -213,8 +206,9 @@ trustCreate(
// LCOV_EXCL_STOP
}
auto const sleRippleState = std::make_shared<SLE>(ltRIPPLE_STATE, uIndex);
view.insert(sleRippleState);
RippleStateEntryW sleRippleState(Keylet(ltRIPPLE_STATE, uIndex), view, j);
sleRippleState.newSLE();
sleRippleState.insert();
auto lowNode = view.dirInsert(
keylet::ownerDir(uLowAccountID), sleRippleState->key(), describeOwnerDir(uLowAccountID));
@@ -285,7 +279,8 @@ trustCreate(
sleRippleState->setFieldU32(sfFlags, uFlags);
increaseOwnerCount(view, sleAccount, sponsorSle, 1, j);
addSponsorToLedgerEntry(sleRippleState, sponsorSle, bSetHigh ? sfHighSponsor : sfLowSponsor);
addSponsorToLedgerEntry(
sleRippleState.mutableRawSle(), sponsorSle, bSetHigh ? sfHighSponsor : sfLowSponsor);
// ONLY: Create ripple balance.
sleRippleState->setFieldAmount(sfBalance, bSetHigh ? -saBalance : saBalance);
@@ -298,7 +293,7 @@ trustCreate(
TER
trustDelete(
ApplyView& view,
SLE::Ref sleRippleState,
RippleStateEntryW& sleRippleState,
AccountID const& uLowAccountID,
AccountID const& uHighAccountID,
beast::Journal j)
@@ -321,11 +316,11 @@ trustDelete(
return tefBAD_LEDGER; // LCOV_EXCL_LINE
}
removeSponsorFromLedgerEntry(sleRippleState, sfHighSponsor);
removeSponsorFromLedgerEntry(sleRippleState, sfLowSponsor);
removeSponsorFromLedgerEntry(sleRippleState.mutableRawSle(), sfHighSponsor);
removeSponsorFromLedgerEntry(sleRippleState.mutableRawSle(), sfLowSponsor);
JLOG(j.trace()) << "trustDelete: Deleting ripple line: state";
view.erase(sleRippleState);
sleRippleState.erase();
return tesSUCCESS;
}
@@ -339,7 +334,7 @@ trustDelete(
static bool
updateTrustLine(
ApplyView& view,
SLE::pointer state,
RippleStateEntryW& state,
bool bSenderHigh,
AccountID const& sender,
STAmount const& before,
@@ -376,14 +371,15 @@ updateTrustLine(
{
// VFALCO Where is the line being deleted?
// Clear the reserve of the sender, possibly delete the line!
auto const currentSponsor =
getLedgerEntryReserveSponsor(view, state, bSenderHigh ? sfHighSponsor : sfLowSponsor);
auto const currentSponsor = getLedgerEntryReserveSponsor(
view, state.rawSle(), bSenderHigh ? sfHighSponsor : sfLowSponsor);
decreaseOwnerCount(view, sle, currentSponsor, 1, j);
// Clear reserve flag.
state->clearFlag(senderReserveFlag);
removeSponsorFromLedgerEntry(state, !bSenderHigh ? sfLowSponsor : sfHighSponsor);
removeSponsorFromLedgerEntry(
state.mutableRawSle(), !bSenderHigh ? sfLowSponsor : sfHighSponsor);
// Balance is zero, receiver reserve is clear.
if (!after && !state->isFlag(receiverReserveFlag))
@@ -418,7 +414,7 @@ issueIOU(
auto const index = keylet::trustLine(issue.account, account, issue.currency);
if (auto state = view.peek(index))
if (RippleStateEntryW state(index, view, j); state)
{
STAmount finalBalance = state->getFieldAmount(sfBalance);
@@ -451,7 +447,7 @@ issueIOU(
j);
}
view.update(state);
state.update();
return tesSUCCESS;
}
@@ -511,7 +507,7 @@ redeemIOU(
bool const bSenderHigh = account > issue.account;
if (auto state = view.peek(keylet::trustLine(account, issue.account, issue.currency)))
if (RippleStateEntryW state(account, issue.account, issue.currency, view, j); state)
{
STAmount finalBalance = state->getFieldAmount(sfBalance);
@@ -545,7 +541,7 @@ redeemIOU(
j);
}
view.update(state);
state.update();
return tesSUCCESS;
}
@@ -572,7 +568,7 @@ requireAuth(ReadView const& view, Issue const& issue, AccountID const& account,
if (isXRP(issue) || issue.account == account)
return tesSUCCESS;
auto const trustLine = view.read(keylet::trustLine(account, issue.account, issue.currency));
RippleStateEntryR const trustLine(account, issue.account, issue.currency, view);
// If account has no line, and this is a strong check, fail
if (!trustLine && authType == AuthType::StrongAuth)
return tecNO_LINE;
@@ -616,7 +612,7 @@ canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, Acc
auto const isRippleDisabled = [&](AccountID account) -> bool {
// Line might not exist, but some transfers can create it. If this
// is the case, just check the default ripple on the issuer account.
auto const line = view.read(keylet::trustLine(account, issue));
RippleStateEntryR const line(account, issue, view);
if (line)
{
bool const issuerHigh = issuerId > account;
@@ -743,7 +739,7 @@ removeEmptyHolding(
// If the account is the issuer, then no line should exist. Check anyway.
// If a line does exist, it will get deleted. If not, return success.
bool const accountIsIssuer = accountID == issue.account;
auto const line = ctx.view.peek(keylet::trustLine(accountID, issue));
RippleStateEntryW line(accountID, issue, ctx.view, journal);
if (!line)
return accountIsIssuer ? (TER)tesSUCCESS : (TER)tecOBJECT_NOT_FOUND;
if (!accountIsIssuer && line->at(sfBalance)->iou() != beast::kZero)
@@ -757,14 +753,15 @@ removeEmptyHolding(
if (!sleLowAccount)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const currentLowSponsor = getLedgerEntryReserveSponsor(ctx.view, line, sfLowSponsor);
auto const currentLowSponsor =
getLedgerEntryReserveSponsor(ctx.view, line.rawSle(), sfLowSponsor);
decreaseOwnerCount(ctx.view, sleLowAccount, currentLowSponsor, 1, journal);
// It's not really necessary to clear the reserve flag, since the line
// is about to be deleted, but this will make the metadata reflect an
// accurate state at the time of deletion.
line->clearFlag(lsfLowReserve);
removeSponsorFromLedgerEntry(line, sfLowSponsor);
removeSponsorFromLedgerEntry(line.mutableRawSle(), sfLowSponsor);
}
if (line->isFlag(lsfHighReserve))
@@ -774,14 +771,15 @@ removeEmptyHolding(
if (!sleHighAccount)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const currentHighSponsor = getLedgerEntryReserveSponsor(ctx.view, line, sfHighSponsor);
auto const currentHighSponsor =
getLedgerEntryReserveSponsor(ctx.view, line.rawSle(), sfHighSponsor);
decreaseOwnerCount(ctx.view, sleHighAccount, currentHighSponsor, 1, journal);
// It's not really necessary to clear the reserve flag, since the line
// is about to be deleted, but this will make the metadata reflect an
// accurate state at the time of deletion.
line->clearFlag(lsfHighReserve);
removeSponsorFromLedgerEntry(line, sfHighSponsor);
removeSponsorFromLedgerEntry(line.mutableRawSle(), sfHighSponsor);
}
return trustDelete(
@@ -795,7 +793,7 @@ removeEmptyHolding(
TER
deleteAMMTrustLine(
ApplyView& view,
SLE::pointer sleState,
RippleStateEntryW& sleState,
std::optional<AccountID> const& ammAccountID,
beast::Journal j)
{
@@ -825,8 +823,13 @@ deleteAMMTrustLine(
if (ammAccountID && (low != *ammAccountID && high != *ammAccountID))
return terNO_AMM;
auto const sponsorSle =
getLedgerEntryReserveSponsor(view, sleState, !ammLow ? sfLowSponsor : sfHighSponsor);
auto const sponsorSle = getLedgerEntryReserveSponsor(
view, sleState.rawSle(), !ammLow ? sfLowSponsor : sfHighSponsor);
// trustDelete() drops the entry's SLE, so read the reserve flag first.
// trustDelete() does not change the flags.
auto const uFlags = !ammLow ? lsfLowReserve : lsfHighReserve;
bool const hasReserve = sleState->isFlag(uFlags);
if (auto const ter = trustDelete(view, sleState, low, high, j); !isTesSuccess(ter))
{
@@ -834,8 +837,7 @@ deleteAMMTrustLine(
return ter;
}
auto const uFlags = !ammLow ? lsfLowReserve : lsfHighReserve;
if (!sleState->isFlag(uFlags))
if (!hasReserve)
return tecINTERNAL; // LCOV_EXCL_LINE
decreaseOwnerCount(view, !ammLow ? sleLow : sleHigh, sponsorSle, 1, j);
+17 -15
View File
@@ -7,6 +7,7 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
@@ -32,6 +33,7 @@
#include <cstdint>
#include <initializer_list>
#include <limits>
#include <optional>
#include <string>
#include <variant>
@@ -265,7 +267,7 @@ checkDepositFreeze(
//
//------------------------------------------------------------------------------
static SLE::const_pointer
static std::optional<RippleStateEntryR>
getLineIfUsable(
ReadView const& view,
AccountID const& account,
@@ -274,11 +276,11 @@ getLineIfUsable(
FreezeHandling zeroIfFrozen,
beast::Journal j)
{
auto sle = view.read(keylet::trustLine(account, issuer, currency));
RippleStateEntryR sle(account, issuer, currency, view);
if (!sle)
{
return nullptr;
return std::nullopt;
}
if (zeroIfFrozen == FreezeHandling::ZeroIfFrozen)
@@ -286,7 +288,7 @@ getLineIfUsable(
if (isFrozen(view, account, currency, issuer) ||
isDeepFrozen(view, account, currency, issuer))
{
return nullptr;
return std::nullopt;
}
// when fixFrozenLPTokenTransfer is enabled, if currency is lptoken,
@@ -296,7 +298,7 @@ getLineIfUsable(
auto const sleIssuer = view.read(keylet::account(issuer));
if (!sleIssuer)
{
return nullptr; // LCOV_EXCL_LINE
return std::nullopt; // LCOV_EXCL_LINE
}
if (sleIssuer->isFieldPresent(sfAMMID))
{
@@ -305,7 +307,7 @@ getLineIfUsable(
if (!sleAmm ||
isLPTokenFrozen(view, account, (*sleAmm)[sfAsset], (*sleAmm)[sfAsset2]))
{
return nullptr;
return std::nullopt;
}
}
}
@@ -316,7 +318,7 @@ getLineIfUsable(
// gated by featureMPTokensV2.
if (!isTesSuccess(canTransferLPToken(view, account, account, issuer)))
{
return nullptr;
return std::nullopt;
}
}
@@ -326,7 +328,7 @@ getLineIfUsable(
static STAmount
getTrustLineBalance(
ReadView const& view,
SLE::ConstRef sle,
std::optional<RippleStateEntryR> const& sle,
AccountID const& account,
Currency const& currency,
AccountID const& issuer,
@@ -336,7 +338,7 @@ getTrustLineBalance(
STAmount amount;
if (sle)
{
amount = sle->getFieldAmount(sfBalance);
amount = (*sle)->getFieldAmount(sfBalance);
bool const accountHigh = account > issuer;
auto const& oppositeField = accountHigh ? sfLowLimit : sfHighLimit;
if (accountHigh)
@@ -346,7 +348,7 @@ getTrustLineBalance(
}
if (includeOppositeLimit)
{
amount += sle->getFieldAmount(oppositeField);
amount += (*sle)->getFieldAmount(oppositeField);
}
amount.get<Issue>().account = issuer;
}
@@ -386,7 +388,7 @@ accountHolds(
}
// IOU: Return balance on trust line modulo freeze
SLE::const_pointer const sle =
std::optional<RippleStateEntryR> const sle =
getLineIfUsable(view, account, currency, issuer, zeroIfFrozen, j);
return getTrustLineBalance(view, sle, account, currency, issuer, returnSpendable, j);
@@ -713,7 +715,7 @@ directSendNoFeeIOU(
"xrpl::directSendNoFeeIOU : receiver is not XRP");
// If the line exists, modify it accordingly.
if (auto const sleRippleState = view.peek(index))
if (RippleStateEntryW sleRippleState(index, view, j); sleRippleState)
{
STAmount saBalance = sleRippleState->getFieldAmount(sfBalance);
@@ -759,11 +761,11 @@ directSendNoFeeIOU(
{
// Clear the reserve of the sender, possibly delete the line!
auto const currentSponsor = getLedgerEntryReserveSponsor(
view, sleRippleState, !bSenderHigh ? sfLowSponsor : sfHighSponsor);
view, sleRippleState.rawSle(), !bSenderHigh ? sfLowSponsor : sfHighSponsor);
decreaseOwnerCount(view, view.peek(keylet::account(uSenderID)), currentSponsor, 1, j);
removeSponsorFromLedgerEntry(
sleRippleState, !bSenderHigh ? sfLowSponsor : sfHighSponsor);
sleRippleState.mutableRawSle(), !bSenderHigh ? sfLowSponsor : sfHighSponsor);
// Clear reserve flag.
sleRippleState->clearFlag(senderReserveFlag);
@@ -791,7 +793,7 @@ directSendNoFeeIOU(
j);
}
view.update(sleRippleState);
sleRippleState.update();
return tesSUCCESS;
}
+2 -1
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/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DelegateHelpers.h>
@@ -1277,7 +1278,7 @@ removeDeletedTrustLines(
for (auto const& index : trustLines)
{
if (auto const sleState = view.peek({ltRIPPLE_STATE, index});
if (RippleStateEntryW sleState(Keylet(ltRIPPLE_STATE, index), view, viewJ);
!isTesSuccess(deleteAMMTrustLine(view, sleState, std::nullopt, viewJ)))
{
JLOG(viewJ.error()) << "removeDeletedTrustLines: failed to delete AMM trustline";
+2 -1
View File
@@ -7,6 +7,7 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AMMHelpers.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
@@ -1449,7 +1450,7 @@ BookStep<TIn, TOut, TDerived>::check(StrandContext const& ctx) const
auto const err = book_.in.visit(
[&](Issue const& issue) -> std::optional<TER> {
auto sle = view.read(keylet::trustLine(*prev, cur, issue.currency));
RippleStateEntryR const sle(*prev, cur, issue.currency, view);
if (!sle)
return terNO_LINE;
if (sle->isFlag((cur > *prev) ? lsfHighNoRipple : lsfLowNoRipple))
+3 -2
View File
@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
@@ -345,7 +346,7 @@ DirectIPaymentStep::quality(ReadView const& sb, QualityDirection qDir) const
if (src_ == dst_)
return QUALITY_ONE;
auto const sle = sb.read(keylet::trustLine(dst_, src_, currency_));
RippleStateEntryR const sle(dst_, src_, currency_, sb);
if (!sle)
return QUALITY_ONE;
@@ -421,7 +422,7 @@ DirectIPaymentStep::check(StrandContext const& ctx, SLE::ConstRef sleSrc) const
// Since this is a payment a trust line must be present. Perform all
// trust line related checks.
{
auto const sleLine = ctx.view.read(keylet::trustLine(src_, dst_, currency_));
RippleStateEntryR const sleLine(src_, dst_, currency_, ctx.view);
if (!sleLine)
{
JLOG(j_.trace()) << "DirectStepI: No credit line. " << *this;
@@ -7,6 +7,7 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
@@ -198,8 +199,7 @@ CheckCash::preclaim(PreclaimContext const& ctx)
return value.asset().visit(
[&](Issue const& issue) -> TER {
Currency const currency{issue.currency};
auto const sleTrustLine =
ctx.view.read(keylet::trustLine(dstId, issuerId, currency));
RippleStateEntryR const sleTrustLine(dstId, issuerId, currency, ctx.view);
auto const sleIssuer = ctx.view.read(keylet::account(issuerId));
if (!sleIssuer)
@@ -506,7 +506,7 @@ CheckCash::doApply()
// would exceed the limit on their trust line. So we
// tweak the trust line limits before calling flow and
// then restore the trust line limits afterwards.
auto const sleTrustLine = psb.peek(*trustLineKey);
RippleStateEntryW sleTrustLine(*trustLineKey, psb, j_);
if (!sleTrustLine)
return tecNO_LINE;
@@ -552,7 +552,7 @@ CheckCash::doApply()
if (trustLineKey)
{
SF_AMOUNT const& tweakedLimit = destLow ? sfLowLimit : sfHighLimit;
if (auto const sleTrustLine = psb.peek(*trustLineKey))
if (RippleStateEntryW sleTrustLine(*trustLineKey, psb); sleTrustLine)
sleTrustLine->at(tweakedLimit) = savedLimit;
}
});
@@ -4,6 +4,7 @@
#include <xrpl/basics/base_uint.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
@@ -126,8 +127,7 @@ CheckCreate::preclaim(PreclaimContext const& ctx)
if (issuerId != srcId)
{
// Check if the issuer froze the line
auto const sleTrust =
ctx.view.read(keylet::trustLine(srcId, issuerId, issue.currency));
RippleStateEntryR const sleTrust(srcId, issuerId, issue.currency, ctx.view);
if (sleTrust &&
sleTrust->isFlag((issuerId > srcId) ? lsfHighFreeze : lsfLowFreeze))
{
@@ -138,8 +138,7 @@ CheckCreate::preclaim(PreclaimContext const& ctx)
if (issuerId != dstId)
{
// Check if dst froze the line.
auto const sleTrust =
ctx.view.read(keylet::trustLine(issuerId, dstId, issue.currency));
RippleStateEntryR const sleTrust(issuerId, dstId, issue.currency, ctx.view);
if (sleTrust &&
sleTrust->isFlag((dstId > issuerId) ? lsfHighFreeze : lsfLowFreeze))
{
+4 -4
View File
@@ -5,6 +5,7 @@
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AMMHelpers.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
@@ -275,7 +276,7 @@ applyCreate(ApplyContext& ctx, Sandbox& sb, AccountID const& account, beast::Jou
// LP Token already exists. (should not happen)
auto const lptIss = ammLPTIssue(amount.asset(), amount2.asset(), accountId);
if (sb.read(keylet::trustLine(accountId, lptIss)))
if (RippleStateEntryR(accountId, lptIss, sb))
{
JLOG(j.error()) << "AMM Instance: LP Token already exists.";
return {tecDUPLICATE, false};
@@ -358,8 +359,7 @@ applyCreate(ApplyContext& ctx, Sandbox& sb, AccountID const& account, beast::Jou
// Set AMM flag on AMM trustline
if (!isXRP(amount))
{
SLE::pointer const sleRippleState =
sb.peek(keylet::trustLine(accountId, issue));
RippleStateEntryW sleRippleState(accountId, issue, sb, j);
if (!sleRippleState)
{
return tecINTERNAL; // LCOV_EXCL_LINE
@@ -367,7 +367,7 @@ applyCreate(ApplyContext& ctx, Sandbox& sb, AccountID const& account, beast::Jou
auto const flags = sleRippleState->getFlags();
sleRippleState->setFieldU32(sfFlags, flags | lsfAMMNode);
sb.update(sleRippleState);
sleRippleState.update();
}
return tesSUCCESS;
});
@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AMMHelpers.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
@@ -233,8 +234,7 @@ AMMDeposit::preclaim(PreclaimContext const& ctx)
{
auto const lpIssue = (*ammSle)[sfLPTokenBalance].get<Issue>();
// Adjust the reserve if LP doesn't have LPToken trustline
auto const sle =
ctx.view.read(keylet::trustLine(accountID, lpIssue.account, lpIssue.currency));
RippleStateEntryR const sle(accountID, lpIssue.account, lpIssue.currency, ctx.view);
if (xrpLiquid(ctx.view, accountID, !sle, ctx.j) >= deposit)
return TER(tesSUCCESS);
if (sle)
@@ -584,8 +584,7 @@ AMMDeposit::deposit(
{
auto const& lpIssue = lpTokensDeposit.get<Issue>();
// Adjust the reserve if LP doesn't have LPToken trustline
auto const sle =
view.read(keylet::trustLine(accountID_, lpIssue.account, lpIssue.currency));
RippleStateEntryR const sle(accountID_, lpIssue.account, lpIssue.currency, view);
if (xrpLiquid(view, accountID_, !sle, j_) >= depositAmount)
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/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -307,7 +308,7 @@ OfferCreate::checkAcceptAsset(
return asset.visit(
[&](Issue const& issue) -> TER {
auto const& issuer = issue.getIssuer();
auto const trustLine = view.read(keylet::trustLine(id, issuer, issue.currency));
RippleStateEntryR const trustLine(id, issuer, issue.currency, view);
// Check if the issuer has lsfDisallowIncomingTrustline set.
// If so, the account must already have a trustline to receive tokens.
@@ -7,6 +7,7 @@
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
@@ -214,7 +215,7 @@ escrowCreatePreclaimHelper<Issue>(
return tecNO_PERMISSION;
// If the account does not have a trustline to the issuer, return tecNO_LINE
auto const sleRippleState = ctx.view.read(keylet::trustLine(account, issuer, issue.currency));
RippleStateEntryR const sleRippleState(account, issuer, issue.currency, ctx.view);
if (!sleRippleState)
return tecNO_LINE;
@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
@@ -317,7 +318,7 @@ NFTokenAcceptOffer::preclaim(PreclaimContext const& ctx)
if (ctx.view.rules().enabled(fixEnforceNFTokenTrustline) &&
(nft::getFlags(tokenID) & nft::kFlagCreateTrustLines) == 0 &&
nftMinter != amount.getIssuer() &&
!ctx.view.read(keylet::trustLine(nftMinter, amount.get<Issue>())))
!RippleStateEntryR(nftMinter, amount.get<Issue>(), ctx.view))
return tecNO_LINE;
// Check that the issuer is allowed to receive IOUs.
@@ -6,6 +6,7 @@
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
@@ -329,7 +330,7 @@ Payment::checkGranularSemantics(
if (issue.getIssuer() != account && issue.getIssuer() != destination)
return terNO_DELEGATE_PERMISSION;
auto const sle = view.read(keylet::trustLine(account, destination, issue.currency));
RippleStateEntryR const sle(account, destination, issue.currency, view);
if (!sle)
return terNO_DELEGATE_PERMISSION;
@@ -2,6 +2,7 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -108,8 +109,8 @@ preclaimHelper<Issue>(
if (!sleIssuer.isFlag(lsfAllowTrustLineClawback) || sleIssuer.isFlag(lsfNoFreeze))
return tecNO_PERMISSION;
auto const sleRippleState =
ctx.view.read(keylet::trustLine(holder, issuer, clawAmount.get<Issue>().currency));
RippleStateEntryR const sleRippleState(
holder, issuer, clawAmount.get<Issue>().currency, ctx.view);
if (!sleRippleState)
return tecNO_LINE;
+13 -14
View File
@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/ledger/helpers/SponsorHelpers.h>
@@ -129,9 +130,8 @@ TrustSet::checkGranularSemantics(
std::unordered_set<GranularPermissionType> const& heldGranularPermissions)
{
auto const saLimitAmount = tx.getFieldAmount(sfLimitAmount);
auto const sleRippleState = view.read(
keylet::trustLine(
tx[sfAccount], saLimitAmount.getIssuer(), saLimitAmount.get<Issue>().currency));
RippleStateEntryR const sleRippleState(
tx[sfAccount], saLimitAmount.getIssuer(), saLimitAmount.get<Issue>().currency, view);
// granular permissions are not allowed to create a trustline
if (!sleRippleState)
@@ -258,7 +258,7 @@ TrustSet::preclaim(PreclaimContext const& ctx)
bool const bHigh = id > uDstAccountID;
// Fetching current state of trust line
auto const sleRippleState = ctx.view.read(keylet::trustLine(id, uDstAccountID, currency));
RippleStateEntryR const sleRippleState(id, uDstAccountID, currency, ctx.view);
std::uint32_t uFlags = sleRippleState ? sleRippleState->getFieldU32(sfFlags) : 0u;
// Computing expected trust line state
uFlags = computeFreezeFlags(
@@ -361,8 +361,7 @@ TrustSet::doApply()
STAmount saLimitAllow = saLimitAmount;
saLimitAllow.get<Issue>().account = accountID_;
SLE::pointer const sleRippleState =
view().peek(keylet::trustLine(accountID_, uDstAccountID, currency));
RippleStateEntryW sleRippleState(accountID_, uDstAccountID, currency, view(), j_);
if (sleRippleState)
{
@@ -519,9 +518,9 @@ TrustSet::doApply()
bool bReserveIncrease = false;
auto const currentHighSponsor =
getLedgerEntryReserveSponsor(view(), sleRippleState, sfHighSponsor);
getLedgerEntryReserveSponsor(view(), sleRippleState.rawSle(), sfHighSponsor);
auto const currentLowSponsor =
getLedgerEntryReserveSponsor(view(), sleRippleState, sfLowSponsor);
getLedgerEntryReserveSponsor(view(), sleRippleState.rawSle(), sfLowSponsor);
if (bSetAuth)
{
@@ -552,7 +551,7 @@ TrustSet::doApply()
increaseOwnerCount(view(), sleLowAccount, lowSponsor, 1, viewJ);
uFlagsOut |= lsfLowReserve;
addSponsorToLedgerEntry(sleRippleState, lowSponsor, sfLowSponsor);
addSponsorToLedgerEntry(sleRippleState.mutableRawSle(), lowSponsor, sfLowSponsor);
if (!bHigh)
bReserveIncrease = true;
@@ -564,7 +563,7 @@ TrustSet::doApply()
decreaseOwnerCount(view(), sleLowAccount, currentLowSponsor, 1, viewJ);
uFlagsOut &= ~lsfLowReserve;
removeSponsorFromLedgerEntry(sleRippleState, sfLowSponsor);
removeSponsorFromLedgerEntry(sleRippleState.mutableRawSle(), sfLowSponsor);
}
if (bHighReserveSet && !bHighReserved)
@@ -594,7 +593,7 @@ TrustSet::doApply()
increaseOwnerCount(view(), sleHighAccount, highSponsor, 1, viewJ);
uFlagsOut |= lsfHighReserve;
addSponsorToLedgerEntry(sleRippleState, highSponsor, sfHighSponsor);
addSponsorToLedgerEntry(sleRippleState.mutableRawSle(), highSponsor, sfHighSponsor);
if (bHigh)
bReserveIncrease = true;
@@ -606,7 +605,7 @@ TrustSet::doApply()
decreaseOwnerCount(view(), sleHighAccount, currentHighSponsor, 1, viewJ);
uFlagsOut &= ~lsfHighReserve;
removeSponsorFromLedgerEntry(sleRippleState, sfHighSponsor);
removeSponsorFromLedgerEntry(sleRippleState.mutableRawSle(), sfHighSponsor);
}
if (uFlagsIn != uFlagsOut)
@@ -642,7 +641,7 @@ TrustSet::doApply()
}
else
{
view().update(sleRippleState);
sleRippleState.update();
JLOG(j_.trace()) << "Modify ripple line";
}
@@ -668,7 +667,7 @@ TrustSet::doApply()
}
else
{
view().update(sleRippleState);
sleRippleState.update();
JLOG(j_.trace()) << "Modify ripple line";
}
+4 -1
View File
@@ -252,7 +252,10 @@ class TheoreticalQuality_test : public beast::unit_test::Suite
std::shared_ptr<ReadView const> closed,
std::optional<Quality> const& expectedQ = {})
{
PaymentSandbox const sb(closed.get(), TapNone);
// Not const: read-only ledger entries peek() through an ApplyView, which
// is undefined behavior on a const object (see SLEBase.h).
// NOLINTNEXTLINE(misc-const-correctness)
PaymentSandbox sb(closed.get(), TapNone);
AMMContext ammContext(rcp.srcAccount, false);
auto const sendMaxIssue = [&rcp]() -> std::optional<Asset> {
@@ -19,6 +19,7 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/OpenView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -380,7 +381,7 @@ class InvariantsMisc_test : public InvariantsBase
for (auto const& trustKeylet :
{keylet::trustLine(ammAcctID, a1["USD"]), keylet::trustLine(a1, ammIssue)})
{
auto const line = ac.view().peek(trustKeylet);
RippleStateEntryW line(trustKeylet, ac.view());
if (!line)
{
return false;