Compare commits

...
Author SHA1 Message Date
Mayukha Vadari e67d1d4012 Document removeIfEmpty parameters 2026-10-05 15:49:07 +01:00
Mayukha Vadari 5b720dbbea refactor: Move removeEmptyHolding line logic onto RippleStateEntry
Add the writable member RippleStateEntry::removeIfEmpty(account,
issuer). It holds the part of removeEmptyHolding() that works on an
existing line: the balance check, the reserve and sponsor cleanup of
each side, and removeFromLedger(). The checks and their order do not
change.

removeEmptyHolding() stays free: the XRP path reads only the
AccountRoot, and the missing-line case has no line.
2026-10-05 15:48:29 +01:00
Mayukha Vadari 5c28ad60c7 Document create parameters and return value 2026-10-05 15:48:22 +01:00
Mayukha Vadari 40e9512020 refactor: Move trustCreate onto RippleStateEntry
Replace the free trustCreate() with the static factory
RippleStateEntry<ApplyView>::create(). The parameters, the body and the
order of reads and writes do not change. The body moves to
RippleStateEntry.cpp. Update the callers in RippleStateHelpers,
TokenHelpers, EscrowHelpers.h, CheckCash and TrustSet, and drop the
RippleStateHelpers.h includes that are no longer used.
2026-10-05 15:47:39 +01:00
Mayukha Vadari 1f824cfcf2 Document removeFromLedger parameters 2026-10-05 15:47:28 +01:00
Mayukha Vadari a90a2cd5fe Include Keylet.h in the SLEBase test
(cherry picked from commit 3cca9d3266)
2026-10-05 15:46:48 +01:00
Mayukha Vadari f406600031 test: Drop extern template declarations from SLEBase test
An explicit instantiation declaration stops clang from emitting the
inline constructors of the header-only entries at -O0, so the debug
builds fail to link xrpl_tests (undefined AccountRootEntry constructors).
Naming each class in a static_assert already instantiates its definition,
which is all the exhaustiveness check needs.

(cherry picked from commit 611415e1f9)
2026-10-05 15:46:47 +01:00
Mayukha Vadari 5b9562556c refactor: Move trustDelete onto RippleStateEntry
Replace the free trustDelete() with the writable member
RippleStateEntry::removeFromLedger(lowAccount, highAccount). The body
is unchanged and lives in the new RippleStateEntry.cpp. It uses the
entry's view and journal.

The two account parameters stay: callers compute them by comparing
account IDs, not from the line's sfLowLimit/sfHighLimit issuers, so
dropping them would change which directories a malformed line is
removed from.

TrustSet passed its "View" journal to trustDelete(), so it now builds
its entry with that journal, and the log output does not change.
2026-10-05 15:46:47 +01:00
Mayukha Vadari c7aa4ea5ef test: Declare, not define, entry instantiations in SLEBase test
The exhaustive per-entry-type check in the SLEBase gtest used explicit
instantiation definitions. Once an entry class gets out-of-line member
bodies in its own .cpp (with the explicit instantiation definition
there), the test would instantiate the class a second time, and MSVC
rejects it with C4661 because those member bodies are not visible in
the test translation unit. Explicit instantiation declarations still
instantiate the class definition, which is all the check needs.

(cherry picked from commit 8b07abc3cd)
2026-10-05 15:46:47 +01:00
Mayukha Vadari 510bd2305a Document isAuthorized parameters and return value 2026-10-05 15:46:40 +01:00
Mayukha Vadari 6298cd8235 refactor: Move requireAuth line check onto RippleStateEntry
Add the const member RippleStateEntry::isAuthorized(account, issuer),
which checks lsfLowAuth or lsfHighAuth by comparing the two account
IDs, exactly as requireAuth did. The rest of requireAuth stays free:
the lsfRequireAuth check reads the issuer AccountRoot, the
pseudo-account check reads the holder AccountRoot, and the missing-line
cases need no line.
2026-10-05 15:46:03 +01:00
Mayukha Vadari dd8da37dac Document isDeepFrozen return value 2026-10-05 15:45:55 +01:00
Mayukha Vadari 617f490c58 refactor: Move isDeepFrozen onto RippleStateEntry
Add the const member RippleStateEntry::isDeepFrozen(), which checks
lsfHighDeepFreeze or lsfLowDeepFreeze. The free function stays as a
shim that handles XRP, the issuer itself, and a missing line.

checkDeepFrozen reads no fields; it only maps the isDeepFrozen shim
result to a TER, so it stays unchanged.
2026-10-05 15:45:13 +01:00
Mayukha Vadari 4ea944e037 refactor: Use RippleStateEntry freeze check in isFrozen
The trust line part of isFrozen is the same check as
RippleStateEntry::isIndividualFrozen, so call the member instead of
adding a duplicate isFrozen member. The global-freeze check reads the
issuer AccountRoot, not the line, so it stays in the free function.
2026-10-05 15:45:09 +01:00
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
25 changed files with 555 additions and 389 deletions

No files matched your search

@@ -1,5 +1,6 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
@@ -8,8 +9,14 @@
#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/STLedgerEntry.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/UintTypes.h>
#include <cstdint>
namespace xrpl {
template <typename ViewT>
@@ -40,6 +47,165 @@ 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);
}
/**
* Returns true if either side deep-froze this line.
*
* @return true if either side deep-froze this line.
*/
[[nodiscard]] bool
isDeepFrozen() const
{
return (*this)->isFlag(lsfHighDeepFreeze) || (*this)->isFlag(lsfLowDeepFreeze);
}
/**
* Returns true if @p issuer authorized @p account on this line.
*
* @note This checks only the line's auth flag. Whether the issuer
* requires authorization (lsfRequireAuth) is on the issuer AccountRoot;
* see requireAuth().
*
* @param account the account whose authorization is checked.
* @param issuer the account on the other side of the line.
* @return true if @p issuer authorized @p account on this line.
*/
[[nodiscard]] bool
isAuthorized(AccountID const& account, AccountID const& issuer) const
{
return (*this)->isFlag((account > issuer) ? lsfLowAuth : lsfHighAuth);
}
/**
* Removes this line from the owner directories of @p lowAccount and
* @p highAccount, clears both sponsors, and erases it.
*
* @param lowAccount the account on the low side of the line.
* @param highAccount the account on the high side of the line.
* @return tesSUCCESS, or tefBAD_LEDGER if a directory removal fails
*/
[[nodiscard]] TER
removeFromLedger(AccountID const& lowAccount, AccountID const& highAccount)
requires Base::kIsWritable;
/**
* Create a trust line
*
* This can set an initial balance.
*
* @param view the view to apply the trust line creation to.
* @param bSrcHigh true if the source account is the high side of the
* line.
* @param uSrcAccountID the account the balance and limit are set from.
* @param uDstAccountID the other account on the line.
* @param uIndex the ledger index of the new ripple state entry.
* @param sleAccount the account being set (the high or low side,
* depending on bSrcHigh and the limit's issuer).
* @param bAuth whether to authorize the account.
* @param bNoRipple whether to disable rippling through the account being
* set.
* @param bFreeze whether the account being set cannot have funds leave.
* @param bDeepFreeze whether the account being set can neither send nor
* receive funds.
* @param saBalance the balance of the account being set; the issuer
* should be noAccount().
* @param saLimit the limit for the account being set; the issuer should
* be the account being set.
* @param uQualityIn the inbound quality for the account being set, or 0
* to leave it unset.
* @param uQualityOut the outbound quality for the account being set, or
* 0 to leave it unset.
* @param sponsorSle the sponsor to charge the new line's reserve to, if
* any.
* @param j the journal to log to.
* @return tesSUCCESS, tecDIR_FULL if either owner directory is full,
* tefINTERNAL if @p sleAccount is null, tecNO_TARGET if the peer account
* does not exist, or tecINTERNAL if the line would be to self and the
* lending protocol is enabled
*/
[[nodiscard]] static TER
create(
ApplyView& view,
bool const bSrcHigh,
AccountID const& uSrcAccountID,
AccountID const& uDstAccountID,
UInt256 const& uIndex, // --> ripple state entry
SLE::Ref sleAccount, // --> the account being set.
bool const bAuth, // --> authorize account.
bool const bNoRipple, // --> others cannot ripple through
bool const bFreeze, // --> funds cannot leave
bool bDeepFreeze, // --> can neither receive nor send funds
STAmount const& saBalance, // --> balance of account being set.
// Issuer should be noAccount()
STAmount const& saLimit, // --> limit for account being set.
// Issuer should be the account being set.
std::uint32_t uQualityIn,
std::uint32_t uQualityOut,
SLE::Ref sponsorSle,
beast::Journal j)
requires Base::kIsWritable;
/**
* Removes this line if @p account holds no balance on it. Clears the
* reserve flag and sponsor of each side that has a reserve, decreases
* that side's owner count, and then calls removeFromLedger(). The
* balance check is skipped when @p account is @p issuer.
*
* @param account the account whose balance is checked.
* @param issuer the account on the other side of the line.
* @return tesSUCCESS, tecHAS_OBLIGATIONS if the balance is not zero, or
* tecINTERNAL / tefBAD_LEDGER on failure
*/
[[nodiscard]] TER
removeIfEmpty(AccountID const& account, AccountID const& issuer)
requires Base::kIsWritable;
};
using RippleStateEntryR = RippleStateEntry<ReadView>;
+3 -3
View File
@@ -4,9 +4,9 @@
#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>
#include <xrpl/ledger/helpers/SponsorHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -93,7 +93,7 @@ escrowUnlockApplyHelper<Issue>(
STAmount initialBalance(issue);
initialBalance.get<Issue>().account = noAccount();
if (TER const ter = trustCreate(
if (TER const ter = RippleStateEntryW::create(
ctx.view, // payment sandbox
recvLow, // is dest low?
issuer, // source
@@ -149,7 +149,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
@@ -1,9 +1,9 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#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>
@@ -130,46 +130,6 @@ checkDeepFrozen(ReadView const& view, AccountID const& account, Issue const& iss
return isDeepFrozen(view, account, issue) ? (TER)tecFROZEN : (TER)tesSUCCESS;
}
//------------------------------------------------------------------------------
//
// Trust line operations
//
//------------------------------------------------------------------------------
/**
* Create a trust line
*
* This can set an initial balance.
*/
[[nodiscard]] TER
trustCreate(
ApplyView& view,
bool const bSrcHigh,
AccountID const& uSrcAccountID,
AccountID const& uDstAccountID,
UInt256 const& uIndex, // --> ripple state entry
SLE::Ref sleAccount, // --> the account being set.
bool const bAuth, // --> authorize account.
bool const bNoRipple, // --> others cannot ripple through
bool const bFreeze, // --> funds cannot leave
bool bDeepFreeze, // --> can neither receive nor send funds
STAmount const& saBalance, // --> balance of account being set.
// Issuer should be noAccount()
STAmount const& saLimit, // --> limit for account being set.
// Issuer should be the account being set.
std::uint32_t uQualityIn,
std::uint32_t uQualityOut,
SLE::Ref sponsorSle,
beast::Journal j);
[[nodiscard]] TER
trustDelete(
ApplyView& view,
SLE::Ref sleRippleState,
AccountID const& uLowAccountID,
AccountID const& uHighAccountID,
beast::Journal j);
//------------------------------------------------------------------------------
//
// IOU issuance/redemption
@@ -270,7 +230,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;
@@ -0,0 +1,238 @@
#include <xrpl/ledger/entries/RippleStateEntry.h>
#include <xrpl/basics/Log.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/SponsorHelpers.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/STAmount.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/TER.h>
#include <cstdint>
namespace xrpl {
template <typename ViewT>
TER
RippleStateEntry<ViewT>::removeFromLedger(AccountID const& lowAccount, AccountID const& highAccount)
requires Base::kIsWritable
{
auto& view = this->applyView();
auto const j = this->journal();
// Detect legacy dirs.
std::uint64_t const uLowNode = (*this)->getFieldU64(sfLowNode);
std::uint64_t const uHighNode = (*this)->getFieldU64(sfHighNode);
JLOG(j.trace()) << "trustDelete: Deleting ripple line: low";
if (!view.dirRemove(keylet::ownerDir(lowAccount), uLowNode, (*this)->key(), false))
{
return tefBAD_LEDGER; // LCOV_EXCL_LINE
}
JLOG(j.trace()) << "trustDelete: Deleting ripple line: high";
if (!view.dirRemove(keylet::ownerDir(highAccount), uHighNode, (*this)->key(), false))
{
return tefBAD_LEDGER; // LCOV_EXCL_LINE
}
removeSponsorFromLedgerEntry(this->mutableRawSle(), sfHighSponsor);
removeSponsorFromLedgerEntry(this->mutableRawSle(), sfLowSponsor);
JLOG(j.trace()) << "trustDelete: Deleting ripple line: state";
this->erase();
return tesSUCCESS;
}
template <typename ViewT>
TER
RippleStateEntry<ViewT>::create(
ApplyView& view,
bool const bSrcHigh,
AccountID const& uSrcAccountID,
AccountID const& uDstAccountID,
UInt256 const& uIndex, // ripple state entry
SLE::Ref sleAccount, // the account being set.
bool const bAuth, // authorize account.
bool const bNoRipple, // others cannot ripple through
bool const bFreeze, // funds cannot leave
bool bDeepFreeze, // can neither receive nor send funds
STAmount const& saBalance, // balance of account being set.
// Issuer should be noAccount()
STAmount const& saLimit, // limit for account being set.
// Issuer should be the account being set.
std::uint32_t uQualityIn,
std::uint32_t uQualityOut,
SLE::Ref sponsorSle,
beast::Journal j)
requires Base::kIsWritable
{
JLOG(j.trace()) << "trustCreate: " << to_string(uSrcAccountID) << ", "
<< to_string(uDstAccountID) << ", " << saBalance.getFullText();
auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID;
auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID;
if (uLowAccountID == uHighAccountID)
{
// LCOV_EXCL_START
UNREACHABLE("xrpl::trustCreate : trust line to self");
if (view.rules().enabled(featureLendingProtocol))
return tecINTERNAL;
// LCOV_EXCL_STOP
}
RippleStateEntry sleRippleState(Keylet(ltRIPPLE_STATE, uIndex), view, j);
sleRippleState.newSLE();
sleRippleState.insert();
auto lowNode = view.dirInsert(
keylet::ownerDir(uLowAccountID), sleRippleState->key(), describeOwnerDir(uLowAccountID));
if (!lowNode)
return tecDIR_FULL; // LCOV_EXCL_LINE
auto highNode = view.dirInsert(
keylet::ownerDir(uHighAccountID), sleRippleState->key(), describeOwnerDir(uHighAccountID));
if (!highNode)
return tecDIR_FULL; // LCOV_EXCL_LINE
bool const bSetDst = saLimit.getIssuer() == uDstAccountID;
bool const bSetHigh = bSrcHigh ^ bSetDst;
XRPL_ASSERT(sleAccount, "xrpl::trustCreate : non-null SLE");
if (!sleAccount)
return tefINTERNAL; // LCOV_EXCL_LINE
XRPL_ASSERT(
sleAccount->getAccountID(sfAccount) == (bSetHigh ? uHighAccountID : uLowAccountID),
"xrpl::trustCreate : matching account ID");
auto const slePeer = view.peek(keylet::account(bSetHigh ? uLowAccountID : uHighAccountID));
if (!slePeer)
return tecNO_TARGET;
// Remember deletion hints.
sleRippleState->setFieldU64(sfLowNode, *lowNode);
sleRippleState->setFieldU64(sfHighNode, *highNode);
sleRippleState->setFieldAmount(bSetHigh ? sfHighLimit : sfLowLimit, saLimit);
sleRippleState->setFieldAmount(
bSetHigh ? sfLowLimit : sfHighLimit,
STAmount(Issue{saBalance.get<Issue>().currency, bSetDst ? uSrcAccountID : uDstAccountID}));
if (uQualityIn != 0u)
sleRippleState->setFieldU32(bSetHigh ? sfHighQualityIn : sfLowQualityIn, uQualityIn);
if (uQualityOut != 0u)
sleRippleState->setFieldU32(bSetHigh ? sfHighQualityOut : sfLowQualityOut, uQualityOut);
std::uint32_t uFlags = bSetHigh ? lsfHighReserve : lsfLowReserve;
if (bAuth)
{
uFlags |= (bSetHigh ? lsfHighAuth : lsfLowAuth);
}
if (bNoRipple)
{
uFlags |= (bSetHigh ? lsfHighNoRipple : lsfLowNoRipple);
}
if (bFreeze)
{
uFlags |= (bSetHigh ? lsfHighFreeze : lsfLowFreeze);
}
if (bDeepFreeze)
{
uFlags |= (bSetHigh ? lsfHighDeepFreeze : lsfLowDeepFreeze);
}
if (!slePeer->isFlag(lsfDefaultRipple))
{
// The other side's default is no rippling
uFlags |= (bSetHigh ? lsfLowNoRipple : lsfHighNoRipple);
}
sleRippleState->setFieldU32(sfFlags, uFlags);
increaseOwnerCount(view, sleAccount, sponsorSle, 1, j);
addSponsorToLedgerEntry(
sleRippleState.mutableRawSle(), sponsorSle, bSetHigh ? sfHighSponsor : sfLowSponsor);
// ONLY: Create ripple balance.
sleRippleState->setFieldAmount(sfBalance, bSetHigh ? -saBalance : saBalance);
view.creditHookIOU(uSrcAccountID, uDstAccountID, saBalance, saBalance.zeroed());
return tesSUCCESS;
}
template <typename ViewT>
TER
RippleStateEntry<ViewT>::removeIfEmpty(AccountID const& account, AccountID const& issuer)
requires Base::kIsWritable
{
auto& view = this->applyView();
auto const j = this->journal();
bool const accountIsIssuer = account == issuer;
if (!accountIsIssuer && (*this)->at(sfBalance)->iou() != beast::kZero)
return tecHAS_OBLIGATIONS;
// Adjust the owner count(s)
if ((*this)->isFlag(lsfLowReserve))
{
// Clear reserve for low account.
auto sleLowAccount = view.peek(keylet::account((*this)->at(sfLowLimit)->getIssuer()));
if (!sleLowAccount)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const currentLowSponsor =
getLedgerEntryReserveSponsor(view, this->rawSle(), sfLowSponsor);
decreaseOwnerCount(view, sleLowAccount, currentLowSponsor, 1, j);
// 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.
(*this)->clearFlag(lsfLowReserve);
removeSponsorFromLedgerEntry(this->mutableRawSle(), sfLowSponsor);
}
if ((*this)->isFlag(lsfHighReserve))
{
// Clear reserve for high account.
auto sleHighAccount = view.peek(keylet::account((*this)->at(sfHighLimit)->getIssuer()));
if (!sleHighAccount)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const currentHighSponsor =
getLedgerEntryReserveSponsor(view, this->rawSle(), sfHighSponsor);
decreaseOwnerCount(view, sleHighAccount, currentHighSponsor, 1, j);
// 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.
(*this)->clearFlag(lsfHighReserve);
removeSponsorFromLedgerEntry(this->mutableRawSle(), sfHighSponsor);
}
return this->removeFromLedger(
(*this)->at(sfLowLimit)->getIssuer(), (*this)->at(sfHighLimit)->getIssuer());
}
template class RippleStateEntry<ReadView>;
template class RippleStateEntry<ApplyView>;
} // namespace xrpl
+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)
{
+41 -254
View File
@@ -7,8 +7,8 @@
#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>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -27,7 +27,6 @@
#include <xrpl/protocol/XRPAmount.h>
#include <algorithm>
#include <cstdint>
#include <memory>
#include <optional>
@@ -48,13 +47,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 +75,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 +106,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 +130,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.isIndividualFrozen(account, issuer))
return true;
}
return false;
@@ -163,171 +154,13 @@ isDeepFrozen(
return false;
}
auto const sle = view.read(keylet::trustLine(account, issuer, currency));
RippleStateEntryR const sle(account, issuer, currency, view);
if (!sle)
{
return false;
}
return sle->isFlag(lsfHighDeepFreeze) || sle->isFlag(lsfLowDeepFreeze);
}
//------------------------------------------------------------------------------
//
// Trust line operations
//
//------------------------------------------------------------------------------
TER
trustCreate(
ApplyView& view,
bool const bSrcHigh,
AccountID const& uSrcAccountID,
AccountID const& uDstAccountID,
UInt256 const& uIndex, // ripple state entry
SLE::Ref sleAccount, // the account being set.
bool const bAuth, // authorize account.
bool const bNoRipple, // others cannot ripple through
bool const bFreeze, // funds cannot leave
bool bDeepFreeze, // can neither receive nor send funds
STAmount const& saBalance, // balance of account being set.
// Issuer should be noAccount()
STAmount const& saLimit, // limit for account being set.
// Issuer should be the account being set.
std::uint32_t uQualityIn,
std::uint32_t uQualityOut,
SLE::Ref sponsorSle,
beast::Journal j)
{
JLOG(j.trace()) << "trustCreate: " << to_string(uSrcAccountID) << ", "
<< to_string(uDstAccountID) << ", " << saBalance.getFullText();
auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID;
auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID;
if (uLowAccountID == uHighAccountID)
{
// LCOV_EXCL_START
UNREACHABLE("xrpl::trustCreate : trust line to self");
if (view.rules().enabled(featureLendingProtocol))
return tecINTERNAL;
// LCOV_EXCL_STOP
}
auto const sleRippleState = std::make_shared<SLE>(ltRIPPLE_STATE, uIndex);
view.insert(sleRippleState);
auto lowNode = view.dirInsert(
keylet::ownerDir(uLowAccountID), sleRippleState->key(), describeOwnerDir(uLowAccountID));
if (!lowNode)
return tecDIR_FULL; // LCOV_EXCL_LINE
auto highNode = view.dirInsert(
keylet::ownerDir(uHighAccountID), sleRippleState->key(), describeOwnerDir(uHighAccountID));
if (!highNode)
return tecDIR_FULL; // LCOV_EXCL_LINE
bool const bSetDst = saLimit.getIssuer() == uDstAccountID;
bool const bSetHigh = bSrcHigh ^ bSetDst;
XRPL_ASSERT(sleAccount, "xrpl::trustCreate : non-null SLE");
if (!sleAccount)
return tefINTERNAL; // LCOV_EXCL_LINE
XRPL_ASSERT(
sleAccount->getAccountID(sfAccount) == (bSetHigh ? uHighAccountID : uLowAccountID),
"xrpl::trustCreate : matching account ID");
auto const slePeer = view.peek(keylet::account(bSetHigh ? uLowAccountID : uHighAccountID));
if (!slePeer)
return tecNO_TARGET;
// Remember deletion hints.
sleRippleState->setFieldU64(sfLowNode, *lowNode);
sleRippleState->setFieldU64(sfHighNode, *highNode);
sleRippleState->setFieldAmount(bSetHigh ? sfHighLimit : sfLowLimit, saLimit);
sleRippleState->setFieldAmount(
bSetHigh ? sfLowLimit : sfHighLimit,
STAmount(Issue{saBalance.get<Issue>().currency, bSetDst ? uSrcAccountID : uDstAccountID}));
if (uQualityIn != 0u)
sleRippleState->setFieldU32(bSetHigh ? sfHighQualityIn : sfLowQualityIn, uQualityIn);
if (uQualityOut != 0u)
sleRippleState->setFieldU32(bSetHigh ? sfHighQualityOut : sfLowQualityOut, uQualityOut);
std::uint32_t uFlags = bSetHigh ? lsfHighReserve : lsfLowReserve;
if (bAuth)
{
uFlags |= (bSetHigh ? lsfHighAuth : lsfLowAuth);
}
if (bNoRipple)
{
uFlags |= (bSetHigh ? lsfHighNoRipple : lsfLowNoRipple);
}
if (bFreeze)
{
uFlags |= (bSetHigh ? lsfHighFreeze : lsfLowFreeze);
}
if (bDeepFreeze)
{
uFlags |= (bSetHigh ? lsfHighDeepFreeze : lsfLowDeepFreeze);
}
if (!slePeer->isFlag(lsfDefaultRipple))
{
// The other side's default is no rippling
uFlags |= (bSetHigh ? lsfLowNoRipple : lsfHighNoRipple);
}
sleRippleState->setFieldU32(sfFlags, uFlags);
increaseOwnerCount(view, sleAccount, sponsorSle, 1, j);
addSponsorToLedgerEntry(sleRippleState, sponsorSle, bSetHigh ? sfHighSponsor : sfLowSponsor);
// ONLY: Create ripple balance.
sleRippleState->setFieldAmount(sfBalance, bSetHigh ? -saBalance : saBalance);
view.creditHookIOU(uSrcAccountID, uDstAccountID, saBalance, saBalance.zeroed());
return tesSUCCESS;
}
TER
trustDelete(
ApplyView& view,
SLE::Ref sleRippleState,
AccountID const& uLowAccountID,
AccountID const& uHighAccountID,
beast::Journal j)
{
// Detect legacy dirs.
std::uint64_t const uLowNode = sleRippleState->getFieldU64(sfLowNode);
std::uint64_t const uHighNode = sleRippleState->getFieldU64(sfHighNode);
JLOG(j.trace()) << "trustDelete: Deleting ripple line: low";
if (!view.dirRemove(keylet::ownerDir(uLowAccountID), uLowNode, sleRippleState->key(), false))
{
return tefBAD_LEDGER; // LCOV_EXCL_LINE
}
JLOG(j.trace()) << "trustDelete: Deleting ripple line: high";
if (!view.dirRemove(keylet::ownerDir(uHighAccountID), uHighNode, sleRippleState->key(), false))
{
return tefBAD_LEDGER; // LCOV_EXCL_LINE
}
removeSponsorFromLedgerEntry(sleRippleState, sfHighSponsor);
removeSponsorFromLedgerEntry(sleRippleState, sfLowSponsor);
JLOG(j.trace()) << "trustDelete: Deleting ripple line: state";
view.erase(sleRippleState);
return tesSUCCESS;
return sle.isDeepFrozen();
}
//------------------------------------------------------------------------------
@@ -339,7 +172,7 @@ trustDelete(
static bool
updateTrustLine(
ApplyView& view,
SLE::pointer state,
RippleStateEntryW& state,
bool bSenderHigh,
AccountID const& sender,
STAmount const& before,
@@ -376,14 +209,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 +252,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);
@@ -443,15 +277,11 @@ issueIOU(
state->setFieldAmount(sfBalance, finalBalance);
if (mustDelete)
{
return trustDelete(
view,
state,
bSenderHigh ? account : issue.account,
bSenderHigh ? issue.account : account,
j);
return state.removeFromLedger(
bSenderHigh ? account : issue.account, bSenderHigh ? issue.account : account);
}
view.update(state);
state.update();
return tesSUCCESS;
}
@@ -470,7 +300,7 @@ issueIOU(
bool const noRipple = !receiverAccount->isFlag(lsfDefaultRipple);
return trustCreate(
return RippleStateEntryW::create(
view,
bSenderHigh,
issue.account,
@@ -511,7 +341,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);
@@ -537,15 +367,11 @@ redeemIOU(
if (mustDelete)
{
return trustDelete(
view,
state,
bSenderHigh ? issue.account : account,
bSenderHigh ? account : issue.account,
j);
return state.removeFromLedger(
bSenderHigh ? issue.account : account, bSenderHigh ? account : issue.account);
}
view.update(state);
state.update();
return tesSUCCESS;
}
@@ -572,7 +398,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;
@@ -584,7 +410,7 @@ requireAuth(ReadView const& view, Issue const& issue, AccountID const& account,
{
if (trustLine)
{
if (trustLine->isFlag((account > issue.account) ? lsfLowAuth : lsfHighAuth))
if (trustLine.isAuthorized(account, issue.account))
return tesSUCCESS;
// A pseudo-account cannot submit transactions and only stores assets for the object
@@ -616,7 +442,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;
@@ -700,7 +526,7 @@ addEmptyHolding(
return ret;
}
return trustCreate(
return RippleStateEntryW::create(
ctx.view,
high,
srcId,
@@ -743,59 +569,16 @@ 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)
return tecHAS_OBLIGATIONS;
// Adjust the owner count(s)
if (line->isFlag(lsfLowReserve))
{
// Clear reserve for low account.
auto sleLowAccount = ctx.view.peek(keylet::account(line->at(sfLowLimit)->getIssuer()));
if (!sleLowAccount)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const currentLowSponsor = getLedgerEntryReserveSponsor(ctx.view, line, 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);
}
if (line->isFlag(lsfHighReserve))
{
// Clear reserve for high account.
auto sleHighAccount = ctx.view.peek(keylet::account(line->at(sfHighLimit)->getIssuer()));
if (!sleHighAccount)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const currentHighSponsor = getLedgerEntryReserveSponsor(ctx.view, line, 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);
}
return trustDelete(
ctx.view,
line,
line->at(sfLowLimit)->getIssuer(),
line->at(sfHighLimit)->getIssuer(),
journal);
return line.removeIfEmpty(accountID, issue.account);
}
TER
deleteAMMTrustLine(
ApplyView& view,
SLE::pointer sleState,
RippleStateEntryW& sleState,
std::optional<AccountID> const& ammAccountID,
beast::Journal j)
{
@@ -825,17 +608,21 @@ 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);
if (auto const ter = trustDelete(view, sleState, low, high, j); !isTesSuccess(ter))
// removeFromLedger() drops the entry's SLE, so read the reserve flag
// first. removeFromLedger() does not change the flags.
auto const uFlags = !ammLow ? lsfLowReserve : lsfHighReserve;
bool const hasReserve = sleState->isFlag(uFlags);
if (auto const ter = sleState.removeFromLedger(low, high); !isTesSuccess(ter))
{
JLOG(j.error()) << "deleteAMMTrustLine: failed to delete the trustline.";
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);
+20 -22
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);
@@ -783,15 +785,11 @@ directSendNoFeeIOU(
if (bDelete)
{
return trustDelete(
view,
sleRippleState,
bSenderHigh ? uReceiverID : uSenderID,
bSenderHigh ? uSenderID : uReceiverID,
j);
return sleRippleState.removeFromLedger(
bSenderHigh ? uReceiverID : uSenderID, bSenderHigh ? uSenderID : uReceiverID);
}
view.update(sleRippleState);
sleRippleState.update();
return tesSUCCESS;
}
@@ -811,7 +809,7 @@ directSendNoFeeIOU(
bool const noRipple = !sleAccount->isFlag(lsfDefaultRipple);
return trustCreate(
return RippleStateEntryW::create(
view,
bSenderHigh,
uSenderID,
+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)
@@ -471,7 +471,7 @@ CheckCash::doApply()
STAmount initialBalance(flowDeliver.asset());
initialBalance.get<Issue>().account = noAccount();
if (TER const ter = trustCreate(
if (TER const ter = RippleStateEntryW::create(
psb, // payment sandbox
destLow, // is dest low?
deliverIssuer, // source
@@ -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;
+16 -20
View File
@@ -5,8 +5,8 @@
#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>
#include <xrpl/protocol/AMMCore.h>
#include <xrpl/protocol/AccountID.h>
@@ -129,9 +129,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 +257,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 +360,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(), viewJ);
if (sleRippleState)
{
@@ -519,9 +517,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 +550,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 +562,7 @@ TrustSet::doApply()
decreaseOwnerCount(view(), sleLowAccount, currentLowSponsor, 1, viewJ);
uFlagsOut &= ~lsfLowReserve;
removeSponsorFromLedgerEntry(sleRippleState, sfLowSponsor);
removeSponsorFromLedgerEntry(sleRippleState.mutableRawSle(), sfLowSponsor);
}
if (bHighReserveSet && !bHighReserved)
@@ -594,7 +592,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 +604,7 @@ TrustSet::doApply()
decreaseOwnerCount(view(), sleHighAccount, currentHighSponsor, 1, viewJ);
uFlagsOut &= ~lsfHighReserve;
removeSponsorFromLedgerEntry(sleRippleState, sfHighSponsor);
removeSponsorFromLedgerEntry(sleRippleState.mutableRawSle(), sfHighSponsor);
}
if (uFlagsIn != uFlagsOut)
@@ -618,8 +616,7 @@ TrustSet::doApply()
{
// Delete.
terResult =
trustDelete(view(), sleRippleState, uLowAccountID, uHighAccountID, viewJ);
terResult = sleRippleState.removeFromLedger(uLowAccountID, uHighAccountID);
}
// Reserve is not scaled by load
else if (
@@ -642,7 +639,7 @@ TrustSet::doApply()
}
else
{
view().update(sleRippleState);
sleRippleState.update();
JLOG(j_.trace()) << "Modify ripple line";
}
@@ -653,8 +650,7 @@ TrustSet::doApply()
{
// Delete.
terResult =
trustDelete(view(), sleRippleState, uLowAccountID, uHighAccountID, viewJ);
terResult = sleRippleState.removeFromLedger(uLowAccountID, uHighAccountID);
}
// Reserve is not scaled by load.
else if (bReserveIncrease && preFeeBalance_ < reserveCreate)
@@ -668,7 +664,7 @@ TrustSet::doApply()
}
else
{
view().update(sleRippleState);
sleRippleState.update();
JLOG(j_.trace()) << "Modify ripple line";
}
@@ -725,7 +721,7 @@ TrustSet::doApply()
JLOG(j_.trace()) << "doTrustSet: Creating ripple line: " << to_string(k.key);
// Create a new ripple line.
terResult = trustCreate(
terResult = RippleStateEntryW::create(
view(),
bHigh,
accountID_,
+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,8 +19,8 @@
#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>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -380,7 +380,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(), ac.journal);
if (!line)
{
return false;
@@ -389,12 +389,8 @@ class InvariantsMisc_test : public InvariantsBase
STAmount const lowLimit = line->at(sfLowLimit);
STAmount const highLimit = line->at(sfHighLimit);
BEAST_EXPECT(
trustDelete(
ac.view(),
line,
lowLimit.getIssuer(),
highLimit.getIssuer(),
ac.journal) == tesSUCCESS);
line.removeFromLedger(lowLimit.getIssuer(), highLimit.getIssuer()) ==
tesSUCCESS);
}
auto const ammSle = ac.view().peek(keylet::amm(ammKey));
+14 -3
View File
@@ -38,6 +38,7 @@
#include <xrpl/ledger/entries/XChainOwnedClaimIDEntry.h> // IWYU pragma: keep
#include <xrpl/ledger/entries/XChainOwnedCreateAccountClaimIDEntry.h> // IWYU pragma: keep
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h>
@@ -76,12 +77,22 @@ template class SLEBase<ApplyView>;
#pragma push_macro("LEDGER_ENTRY")
#undef LEDGER_ENTRY
// No explicit instantiation here, neither a definition nor a declaration.
// A definition would instantiate an entry a second time once its member
// bodies live in its own .cpp (MSVC rejects that with C4661 under /WX), and a
// declaration (`extern template`) stops clang from emitting the inline
// constructors of the header-only entries at -O0, which leaves them undefined
// at link time in the debug builds. Naming the class in a static_assert is
// enough to instantiate its definition, which is all this exhaustiveness
// check needs; the per-type suites exercise the members.
#define LEDGER_ENTRY(tag, value, name, ...) \
template class name##Entry<ReadView>; \
template class name##Entry<ApplyView>; \
static_assert( \
name##Entry<ReadView>::kEntryType == tag && name##Entry<ApplyView>::kEntryType == tag, \
#name "Entry must be bound to " #tag);
#name "Entry must be bound to " #tag); \
static_assert( \
std::is_constructible_v<name##Entry<ReadView>, Keylet const&, ReadView const&> && \
std::is_constructible_v<name##Entry<ApplyView>, Keylet const&, ApplyView&>, \
#name "Entry must be constructible from a Keylet and a view");
#include <xrpl/protocol/detail/ledger_entries.macro>