Compare commits

...

6 Commits

Author SHA1 Message Date
Mayukha Vadari
909331db6d Keep Ticket deletion in Transactor::ticketDelete
Move the deletion logic back from TicketEntry::removeFromLedger into
Transactor::ticketDelete and drop the new member, so this PR only
migrates the Ticket SLE pointers to TicketEntry.
2026-10-07 20:46:40 +01:00
Mayukha Vadari
03d84784a9 Document removeFromLedger parameters and return value 2026-10-05 15:47:00 +01:00
Mayukha Vadari
8c405396b8 Include Keylet.h in the SLEBase test
(cherry picked from commit 3cca9d3266)
2026-10-05 14:37:00 +01:00
Mayukha Vadari
8972740b77 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:37:00 +01:00
Mayukha Vadari
f19a964272 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 13:33:24 +01:00
Mayukha Vadari
a224f998ea refactor: Use TicketEntry everywhere
Replace raw Ticket SLE pointers with TicketEntryW in TicketCreate and
Transactor::ticketDelete, and move the ticket deletion logic (directory
removal, TicketCount decrement, owner count decrement, erase) onto the
wrapper as TicketEntry::removeFromLedger(). The member body lives in
src/libxrpl/ledger/entries/TicketEntry.cpp with explicit instantiation.
No behavior change.
2026-10-05 13:33:24 +01:00
3 changed files with 29 additions and 18 deletions

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/TicketEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DelegateHelpers.h>
@@ -815,8 +816,8 @@ Transactor::ticketDelete(
{
// Delete the Ticket, adjust the account root ticket count, and
// reduce the owner count.
SLE::pointer const sleTicket = view.peek(keylet::ticket(ticketIndex));
if (!sleTicket)
TicketEntryW ticket(ticketIndex, view, j);
if (!ticket)
{
// LCOV_EXCL_START
JLOG(j.fatal()) << "Ticket disappeared from ledger.";
@@ -824,7 +825,7 @@ Transactor::ticketDelete(
// LCOV_EXCL_STOP
}
std::uint64_t const page{(*sleTicket)[sfOwnerNode]};
std::uint64_t const page{(*ticket)[sfOwnerNode]};
if (!view.dirRemove(keylet::ownerDir(account), page, ticketIndex, true))
{
// LCOV_EXCL_START
@@ -864,10 +865,10 @@ Transactor::ticketDelete(
}
// Update the Ticket owner's reserve.
decreaseOwnerCountForObject(view, sleAccount, sleTicket, 1, j);
decreaseOwnerCountForObject(view, sleAccount, ticket.mutableRawSle(), 1, j);
// Remove Ticket from ledger.
view.erase(sleTicket);
ticket.erase();
return tesSUCCESS;
}

View File

@@ -4,10 +4,10 @@
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/entries/TicketEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/STTx.h>
@@ -17,7 +17,6 @@
#include <xrpl/tx/applySteps.h>
#include <cstdint>
#include <memory>
namespace xrpl {
@@ -99,24 +98,24 @@ TicketCreate::doApply()
for (std::uint32_t i = 0; i < ticketCount; ++i)
{
std::uint32_t const curTicketSeq = firstTicketSeq + i;
Keylet const ticketKeylet = keylet::ticket(accountID_, SeqProxy::rawTicket(curTicketSeq));
SLE::pointer const sleTicket = std::make_shared<SLE>(ticketKeylet);
TicketEntryW ticket(accountID_, SeqProxy::rawTicket(curTicketSeq), view());
ticket.newSLE();
sleTicket->setAccountID(sfAccount, accountID_);
sleTicket->setFieldU32(sfTicketSequence, curTicketSeq);
ticket->setAccountID(sfAccount, accountID_);
ticket->setFieldU32(sfTicketSequence, curTicketSeq);
view().insert(sleTicket);
ticket.insert();
auto const page = view().dirInsert(
keylet::ownerDir(accountID_), ticketKeylet, describeOwnerDir(accountID_));
keylet::ownerDir(accountID_), ticket.keylet(), describeOwnerDir(accountID_));
JLOG(j_.trace()) << "Creating ticket " << to_string(ticketKeylet.key) << ": "
JLOG(j_.trace()) << "Creating ticket " << to_string(ticket.key()) << ": "
<< (page ? "success" : "failure");
if (!page)
return tecDIR_FULL; // LCOV_EXCL_LINE
sleTicket->setFieldU64(sfOwnerNode, *page);
ticket->setFieldU64(sfOwnerNode, *page);
}
// Update the record of the number of Tickets this account owns.

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>