Compare commits

...
Author SHA1 Message Date
Mayukha Vadari 696b28598a Merge remote-tracking branch 'upstream/develop' into mvadari/rearch/offer-entry 2026-10-13 11:35:43 -04:00
Mayukha Vadari 4be0d01136 Merge remote-tracking branch 'upstream/develop' into mvadari/rearch/offer-entry
# Conflicts:
#	include/xrpl/tx/paths/detail/StrandFlow.h
#	src/libxrpl/ledger/helpers/OfferHelpers.cpp
#	src/libxrpl/tx/transactors/dex/OfferCancel.cpp
#	src/libxrpl/tx/transactors/dex/OfferCreate.cpp
#	src/test/app/AMMExtendedMPT_test.cpp
#	src/test/app/AMMExtended_test.cpp
#	src/test/app/FlowMPT_test.cpp
#	src/test/app/Flow_test.cpp
2026-10-12 12:55:46 -04:00
Mayukha Vadari 06305cd239 Use UInt256 instead of uint256 2026-10-05 16:00:04 +01:00
Mayukha Vadari b735ba80d4 Include Keylet.h in the SLEBase test
(cherry picked from commit 3cca9d3266)
2026-10-05 14:40:49 +01:00
Mayukha Vadari bcf85e514a 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 14:40:49 +01:00
Mayukha Vadari 89d5cbfc94 Drop unused include from StrandFlow.h 2026-10-05 13:50:05 +01:00
Mayukha Vadari ca8d23a507 refactor: Use OfferEntry everywhere
Migrate all Offer SLE pointers in transaction processing and payment
path code to OfferEntryR/OfferEntryW, and move the free offerDelete()
helper onto OfferEntry<ViewT> as removeFromLedger().

TOffer, OfferStream, and BookDirs keep raw SLE::pointer/const_pointer:
they cache the offer across a public accessor that many callers rely
on, so retyping it is not a mechanical swap. BookTip keeps its raw
SLE::pointer member for the same reason, but its offerDelete() call
site is updated to build an OfferEntryW from the already-peeked SLE's
key. permissioned_dex::offerInDomain is left as a future cross-type
pass, and the RPC-only NetworkOPs::getBookPage lookup is left alone.

Also declares (rather than defines) the per-entry explicit
instantiations in the SLEBase gtest for entries whose member bodies
live in their own .cpp: OfferEntry now has out-of-line members, and an
explicit instantiation definition of a class whose out-of-line members
aren't visible in the test TU is a Windows/MSVC error (C4661).
2026-10-05 13:50:05 +01:00
15 changed files with 130 additions and 131 deletions

No files matched your search

+13
View File
@@ -9,6 +9,7 @@
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
#include <xrpl/protocol/TER.h>
namespace xrpl {
@@ -38,6 +39,18 @@ public:
: Base(keylet::offer(offerID), view, j)
{
}
/**
* Delete this offer from the ledger.
*
* Requirements:
* The caller must have already checked permissions.
*
* @return tesSUCCESS on success, otherwise an error code.
*/
TER
removeFromLedger()
requires Base::kIsWritable;
};
using OfferEntryR = OfferEntry<ReadView>;
@@ -1,27 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/TER.h>
namespace xrpl {
/**
* Delete an offer.
*
* Requirements:
* The offer must exist.
* The caller must have already checked permissions.
*
* @param view The ApplyView to modify.
* @param sle The offer to delete.
* @param j Journal for logging.
*
* @return tesSUCCESS on success, otherwise an error code.
*/
// [[nodiscard]] // nodiscard commented out so Flow, BookTip and others compile.
TER
offerDelete(ApplyView& view, SLE::Ref sle, beast::Journal j);
} // namespace xrpl
+3 -4
View File
@@ -6,12 +6,11 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/entries/OfferEntry.h>
#include <xrpl/ledger/helpers/AMMHelpers.h>
#include <xrpl/ledger/helpers/OfferHelpers.h>
#include <xrpl/protocol/Concepts.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/IOUAmount.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/MPTAmount.h>
#include <xrpl/protocol/Quality.h>
#include <xrpl/protocol/QualityFunction.h>
@@ -794,8 +793,8 @@ flow(
setUnion(ofrsToRmOnFail, ofrsToRm);
for (auto const& o : ofrsToRm)
{
if (auto const ok = sb.peek(keylet::offer(o)))
offerDelete(sb, ok, j);
if (OfferEntryW ok(o, sb, j); ok)
ok.removeFromLedger();
}
}
@@ -5,6 +5,7 @@
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/OfferEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Keylet.h>
@@ -108,7 +109,7 @@ private:
TER
applyHybrid(
Sandbox& sb,
STLedgerEntry::pointer sleOffer,
OfferEntryW& sleOffer,
Keylet const& offerIndex,
STAmount const& saTakerPays,
STAmount const& saTakerGets,
+74
View File
@@ -0,0 +1,74 @@
#include <xrpl/ledger/entries/OfferEntry.h>
#include <xrpl/basics/base_uint.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/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STArray.h> // IWYU pragma: keep
#include <xrpl/protocol/TER.h>
namespace xrpl {
template <typename ViewT>
TER
OfferEntry<ViewT>::removeFromLedger()
requires Base::kIsWritable
{
if (!this->exists())
return tesSUCCESS;
auto const offerIndex = this->key();
auto const owner = (*this)->getAccountID(sfAccount);
// Detect legacy directories.
UInt256 const uDirectory = (*this)->getFieldH256(sfBookDirectory);
ApplyView& view = this->applyView();
if (!view.dirRemove(
keylet::ownerDir(owner), (*this)->getFieldU64(sfOwnerNode), offerIndex, false))
{
return tefBAD_LEDGER; // LCOV_EXCL_LINE
}
if (!view.dirRemove(
keylet::page(uDirectory), (*this)->getFieldU64(sfBookNode), offerIndex, false))
{
return tefBAD_LEDGER; // LCOV_EXCL_LINE
}
if ((*this)->isFieldPresent(sfAdditionalBooks))
{
XRPL_ASSERT(
(*this)->isFlag(lsfHybrid) && (*this)->isFieldPresent(sfDomainID),
"xrpl::OfferEntry::removeFromLedger : should be a hybrid domain offer");
auto const& additionalBookDirs = (*this)->getFieldArray(sfAdditionalBooks);
for (auto const& bookDir : additionalBookDirs)
{
auto const& dirIndex = bookDir.getFieldH256(sfBookDirectory);
auto const& dirNode = bookDir.getFieldU64(sfBookNode);
if (!view.dirRemove(keylet::page(dirIndex), dirNode, offerIndex, false))
{
return tefBAD_LEDGER; // LCOV_EXCL_LINE
}
}
}
decreaseOwnerCountForObject(view, owner, this->mutableRawSle(), 1, this->journal());
this->erase();
return tesSUCCESS;
}
template class OfferEntry<ReadView>;
template class OfferEntry<ApplyView>;
} // namespace xrpl
@@ -1,65 +0,0 @@
#include <xrpl/ledger/helpers/OfferHelpers.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h> // IWYU pragma: keep
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STArray.h> // IWYU pragma: keep
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/TER.h>
namespace xrpl {
TER
offerDelete(ApplyView& view, SLE::Ref sle, beast::Journal j)
{
if (!sle)
return tesSUCCESS;
auto const offerIndex = sle->key();
auto const owner = sle->getAccountID(sfAccount);
// Detect legacy directories.
UInt256 const uDirectory = sle->getFieldH256(sfBookDirectory);
if (!view.dirRemove(keylet::ownerDir(owner), sle->getFieldU64(sfOwnerNode), offerIndex, false))
{
return tefBAD_LEDGER; // LCOV_EXCL_LINE
}
if (!view.dirRemove(keylet::page(uDirectory), sle->getFieldU64(sfBookNode), offerIndex, false))
{
return tefBAD_LEDGER; // LCOV_EXCL_LINE
}
if (sle->isFieldPresent(sfAdditionalBooks))
{
XRPL_ASSERT(
sle->isFlag(lsfHybrid) && sle->isFieldPresent(sfDomainID),
"xrpl::offerDelete : should be a hybrid domain offer");
auto const& additionalBookDirs = sle->getFieldArray(sfAdditionalBooks);
for (auto const& bookDir : additionalBookDirs)
{
auto const& dirIndex = bookDir.getFieldH256(sfBookDirectory);
auto const& dirNode = bookDir.getFieldU64(sfBookNode);
if (!view.dirRemove(keylet::page(dirIndex), dirNode, offerIndex, false))
{
return tefBAD_LEDGER; // LCOV_EXCL_LINE
}
}
}
decreaseOwnerCountForObject(view, owner, sle, 1, j);
view.erase(sle);
return tesSUCCESS;
}
} // namespace xrpl
+3 -3
View File
@@ -11,11 +11,11 @@
#include <xrpl/json/to_string.h> // IWYU pragma: keep
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/OfferEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DelegateHelpers.h>
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
#include <xrpl/ledger/helpers/OfferHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/ledger/helpers/SponsorHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -1216,10 +1216,10 @@ removeUnfundedOffers(ApplyView& view, std::vector<UInt256> const& offers, beast:
for (auto const& index : offers)
{
if (auto const sleOffer = view.peek(keylet::offer(index)))
if (OfferEntryW sleOffer(index, view, viewJ); sleOffer)
{
// offer is unfunded
offerDelete(view, sleOffer, viewJ);
sleOffer.removeFromLedger();
if (++removed == kUnfundedOfferRemoveLimit)
return;
}
+4 -2
View File
@@ -2,10 +2,12 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/entries/OfferEntry.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/OfferHelpers.h>
#include <xrpl/protocol/Book.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/STLedgerEntry.h>
namespace xrpl {
@@ -22,7 +24,7 @@ BookTip::step(beast::Journal j)
{
if (entry_)
{
offerDelete(view_, entry_, j);
OfferEntryW(Keylet(ltOFFER, entry_->key()), view_, j).removeFromLedger();
entry_ = nullptr;
}
}
@@ -10,10 +10,10 @@
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/DepositPreauthEntry.h>
#include <xrpl/ledger/entries/OfferEntry.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
#include <xrpl/ledger/helpers/OfferHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -79,12 +79,12 @@ TER
offerDelete(
ServiceRegistry&,
ApplyView& view,
AccountID const& account,
AccountID const&,
UInt256 const& delIndex,
SLE::Ref sleDel,
SLE::Ref,
beast::Journal j)
{
return offerDelete(view, sleDel, j);
return OfferEntryW(Keylet(ltOFFER, delIndex), view, j).removeFromLedger();
}
TER
@@ -1,7 +1,7 @@
#include <xrpl/tx/transactors/dex/OfferCancel.h>
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/helpers/OfferHelpers.h>
#include <xrpl/ledger/entries/OfferEntry.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h>
@@ -59,10 +59,11 @@ OfferCancel::doApply()
return tefINTERNAL; // LCOV_EXCL_LINE
auto const seqProxy = SeqProxy::rawSequence(offerSequence);
if (auto const sleOffer = view().peek(keylet::offer(accountID_, seqProxy)))
if (OfferEntryW sleOffer(accountID_, seqProxy, view(), ctx_.registry.get().getJournal("View"));
sleOffer)
{
JLOG(j_.debug()) << "Trying to cancel offer #" << offerSequence;
return offerDelete(view(), sleOffer, ctx_.registry.get().getJournal("View"));
return sleOffer.removeFromLedger();
}
JLOG(j_.debug()) << "Offer #" << offerSequence << " can't be found.";
+11 -10
View File
@@ -9,11 +9,11 @@
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/OfferEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/OfferHelpers.h>
#include <xrpl/ledger/helpers/PermissionedDEXHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -495,10 +495,10 @@ OfferCreate::flowCross(
// If stale offers were found remove them.
for (auto const& toRemove : result.removableOffers)
{
if (auto const otr = psb.peek(keylet::offer(toRemove)))
offerDelete(psb, otr, j_);
if (auto const otr = psbCancel.peek(keylet::offer(toRemove)))
offerDelete(psbCancel, otr, j_);
if (OfferEntryW otr(toRemove, psb, j_); otr)
otr.removeFromLedger();
if (OfferEntryW otr(toRemove, psbCancel, j_); otr)
otr.removeFromLedger();
}
// Determine the size of the final offer after crossing.
@@ -595,7 +595,7 @@ OfferCreate::formatAmount(STAmount const& amount)
TER
OfferCreate::applyHybrid(
Sandbox& sb,
STLedgerEntry::pointer sleOffer,
OfferEntryW& sleOffer,
Keylet const& offerKey,
STAmount const& saTakerPays,
STAmount const& saTakerGets,
@@ -673,7 +673,7 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
if (cancelSequence)
{
auto const seqProxy = SeqProxy::rawSequence(*cancelSequence);
auto const sleCancel = sb.peek(keylet::offer(accountID_, seqProxy));
OfferEntryW sleCancel(accountID_, seqProxy, sb, viewJ);
// It's not an error to not find the offer to cancel: it might have
// been consumed or removed. If it is found, however, it's an error
@@ -681,7 +681,7 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
if (sleCancel)
{
JLOG(j_.debug()) << "Create cancels order " << *cancelSequence;
result = offerDelete(sb, sleCancel, viewJ);
result = sleCancel.removeFromLedger();
}
}
@@ -976,7 +976,8 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
// LCOV_EXCL_STOP
}
auto const sleOffer = std::make_shared<SLE>(offerIndex);
OfferEntryW sleOffer(offerIndex, sb, j_);
sleOffer.newSLE();
sleOffer->setAccountID(sfAccount, accountID_);
sleOffer->setFieldU32(sfSequence, offerSequence.value());
sleOffer->setFieldH256(sfBookDirectory, dir.key);
@@ -1010,7 +1011,7 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
return {res, true}; // LCOV_EXCL_LINE
}
sb.insert(sleOffer);
sleOffer.insert();
if (!bookExisted)
ctx_.addOrderBook(book);
+3 -3
View File
@@ -31,7 +31,7 @@
#include <xrpl/ledger/OpenView.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/helpers/OfferHelpers.h>
#include <xrpl/ledger/entries/OfferEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -1982,9 +1982,9 @@ private:
Sandbox sb(&view, TapNone);
for (auto const& o : flowResult.removableOffers)
{
if (auto const ok = sb.peek(keylet::offer(o)))
if (OfferEntryW ok(o, sb, flowJournal); ok)
{
offerDelete(sb, ok, flowJournal);
ok.removeFromLedger();
}
}
sb.apply(view);
+3 -3
View File
@@ -35,7 +35,7 @@
#include <xrpl/ledger/OpenView.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/helpers/OfferHelpers.h>
#include <xrpl/ledger/entries/OfferEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -2090,8 +2090,8 @@ private:
Sandbox sb(&view, TapNone);
for (auto const& o : flowResult.removableOffers)
{
if (auto const ok = sb.peek(keylet::offer(o)))
offerDelete(sb, ok, flowJournal);
if (OfferEntryW ok(o, sb, flowJournal); ok)
ok.removeFromLedger();
}
sb.apply(view);
return true;
+3 -3
View File
@@ -21,8 +21,8 @@
#include <xrpl/ledger/OpenView.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/entries/OfferEntry.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/OfferHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Feature.h>
@@ -377,8 +377,8 @@ struct FlowMPT_test : public beast::unit_test::Suite
Sandbox sb(&view, TapNone);
for (auto const& o : flowResult.removableOffers)
{
if (auto const ok = sb.peek(keylet::offer(o)))
offerDelete(sb, ok, flowJournal);
if (OfferEntryW ok(o, sb, flowJournal); ok)
ok.removeFromLedger();
}
sb.apply(view);
return true;
+3 -3
View File
@@ -24,8 +24,8 @@
#include <xrpl/ledger/OpenView.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/entries/OfferEntry.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/OfferHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -517,8 +517,8 @@ struct Flow_test : public beast::unit_test::Suite
Sandbox sb(&view, TapNone);
for (auto const& o : flowResult.removableOffers)
{
if (auto const ok = sb.peek(keylet::offer(o)))
offerDelete(sb, ok, flowJournal);
if (OfferEntryW ok(o, sb, flowJournal); ok)
ok.removeFromLedger();
}
sb.apply(view);
return true;