Compare commits

...

10 Commits

Author SHA1 Message Date
Mayukha Vadari
a7b0bd7036 Keep DepositPreauth::removeFromLedger in the transactor
Move DepositPreauth::removeFromLedger back to the DepositPreauth
transactor with its develop signature and body, reading the owner from
the object. Only the DepositPreauth SLE inside it uses
DepositPreauthEntryW now. AccountDelete and doApply call it as on
develop, and the unreachable tefINTERNAL check in the credentials
branch is back.

Delete DepositPreauthEntry.cpp and restore DepositPreauthEntry.h and
DepositPreauth.h to develop. The PR is now a pointer-only migration.
2026-10-07 21:01:45 +01:00
Mayukha Vadari
3fcb586a08 Merge remote-tracking branch 'upstream/develop' into mvadari/rearch/depositpreauth-entry
# Conflicts:
#	src/libxrpl/ledger/View.cpp
2026-10-07 14:23:54 +01:00
Ayaz Salikhov
b4564d5301 chore: Update pre-commit hooks and image (#8528) 2026-10-07 10:59:37 +00:00
Mayukha Vadari
5fe5550150 Merge remote-tracking branch 'upstream/develop' into mvadari/rearch/depositpreauth-entry
# Conflicts:
#	src/libxrpl/ledger/View.cpp
2026-10-06 10:35:41 +01:00
Mayukha Vadari
14e27d1a98 Document removeFromLedger parameters and return value 2026-10-05 15:46:46 +01:00
Mayukha Vadari
f7da22e410 Include Keylet.h in the SLEBase test
(cherry picked from commit 3cca9d3266)
2026-10-05 14:37:28 +01:00
Mayukha Vadari
d3728b53c8 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:28 +01:00
Mayukha Vadari
a5e06bc027 Drop unused includes from DepositPreauth.h 2026-10-05 13:34:05 +01:00
Mayukha Vadari
efa5aa1c7d refactor: Use DepositPreauthEntry everywhere
Migrate every DepositPreauth pointer (view.read/peek/exists over
keylet::depositPreauth) in libxrpl to DepositPreauthEntryR/W, and move
the ledger-removal logic (dir removal, owner count, erase) off
DepositPreauth::removeFromLedger and AccountDelete's
removeDepositPreauthFromLedger onto a single writable
DepositPreauthEntry<ViewT>::removeFromLedger(AccountID const& owner)
member.
2026-10-05 13:34:04 +01:00
Mayukha Vadari
779448bee4 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:34:04 +01:00
9 changed files with 124 additions and 47 deletions

View File

@@ -108,3 +108,75 @@ endfunction()
function(patch_nix_binary target)
endfunction()
function(rpcspec_generate_instantiations)
set(options)
set(oneValueArgs OUT_VAR VALUE_TYPE VIEW_HEADER INCLUDE_DIR)
set(multiValueArgs HANDLERS)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()
function(corrosion_import_crate)
set(options
ALL_FEATURES
NO_DEFAULT_FEATURES
NO_STD
NO_LINKER_OVERRIDE
NO_USES_TERMINAL
LOCKED
FROZEN
)
set(oneValueArgs MANIFEST_PATH PROFILE IMPORTED_CRATES)
set(multiValueArgs
CRATE_TYPES
CRATES
FEATURES
FLAGS
OVERRIDE_CRATE_TYPE
)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()
function(corrosion_set_env_vars target_name env_var)
endfunction()
function(corrosion_add_cxxbridge cxx_target)
set(options)
set(oneValueArgs CRATE)
set(multiValueArgs FILES)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()
function(_unlink_libgcc_s crate)
endfunction()
function(add_xrpl_crate name)
set(options)
set(oneValueArgs CRATE)
set(multiValueArgs FILES)
cmake_parse_arguments(
THIS_FUNCTION_PREFIX
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
endfunction()

View File

@@ -17,4 +17,4 @@ jobs:
uses: XRPLF/actions/.github/workflows/pre-commit.yml@279ec358f4a1be4088be3e024b07916fa97c75b6
with:
runs_on: ubuntu-latest
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-3a2d19f" }'
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-70b8fd3" }'

View File

@@ -60,7 +60,7 @@ repos:
types_or: [c++, c]
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: e2b496dc2bd8340c2524cb9a2d2a943cde1bb6df # frozen: v23.1.1
rev: a9a8a861f30ed207ead7d5a3b7e8032283ba5da7 # frozen: v23.1.2
hooks:
- id: clang-format
args: [--style=file]
@@ -82,9 +82,10 @@ repos:
files: ^crates/.*\.rs$
- repo: https://github.com/BlankSpruce/gersemi-pre-commit
rev: f1c4833f8cf23c6d952673abc73525411a5719e8 # frozen: 0.29.1
rev: 28010ddd6016e1a0f7bd232acb6536ef996ae897 # frozen: 0.29.2
hooks:
- id: gersemi
args: [-i, --warnings-as-errors]
- repo: https://github.com/rbubley/mirrors-prettier
rev: ef4a397f916211b4a39ccf9d3d9cbb6562157251 # frozen: v3.9.9
@@ -95,19 +96,19 @@ repos:
# Scoped to package/: the rest of the repo's Python has pre-existing findings,
# so widening these is its own change.
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: a56c0b927e6465d37cae3e97d35d4d18ab2b96cd # frozen: v0.16.9
rev: f12be1ebaa5351c1fc76472de98db2c3446c8253 # frozen: v0.16.10
hooks:
- id: ruff-check
args: [--fix]
files: ^package/.*\.py$
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 4160603246a6b365d4a2af661c6d71b0a0f50478 # frozen: 26.5.1
rev: 96ae3e5802f3fe2d551e703e18f0a367d1a81ac2 # frozen: 26.10.0
hooks:
- id: black
- repo: https://github.com/pre-commit/mirrors-mypy
rev: 7ff8d35ae36a7d2b968f2f90b4c723e292e594ee # frozen: v2.3.1
rev: 2834ec6639549dd6796205c8f011dedcd587288b # frozen: v2.4.0
hooks:
- id: mypy
args: [--strict]

View File

@@ -80,13 +80,12 @@ function(add_xrpl_crate name)
# `cc` picks its runtime flag from `crt-static` alone, so it compiles a
# crate's C++ with `-MT`; Debug needs `-MTd` (to match cmake/XrplCompiler.cmake).
if(is_msvc)
corrosion_set_env_vars(
${ARG_CRATE}
"$<$<CONFIG:Debug>:CXXFLAGS=-MTd>"
)
corrosion_set_env_vars(${ARG_CRATE} "$<$<CONFIG:Debug>:CXXFLAGS=-MTd>")
endif()
corrosion_add_cxxbridge(${name}_cxxbridge CRATE ${ARG_CRATE} FILES
${ARG_FILES}
corrosion_add_cxxbridge(
${name}_cxxbridge
CRATE ${ARG_CRATE}
FILES ${ARG_FILES}
)
# Generated cxxbridge headers don't exist at configure time; CMake 3.28+
# validates INTERFACE_SOURCES on consuming targets. Clear it to skip the

View File

@@ -10,6 +10,7 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AmendmentsEntry.h>
#include <xrpl/ledger/entries/DepositPreauthEntry.h>
#include <xrpl/ledger/entries/LedgerHashesEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
@@ -451,7 +452,7 @@ canWithdraw(
if (toSle->isFlag(lsfDepositAuth))
{
if (!view.exists(keylet::depositPreauth(to, from)))
if (!DepositPreauthEntryR(to, from, view))
{
if (credentialIDs.has_value())
{

View File

@@ -7,6 +7,7 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/DepositPreauthEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
@@ -266,7 +267,7 @@ authorizedDepositPreauth(ReadView const& view, STVector256 const& credIDs, Accou
lifeExtender.push_back(std::move(sleCred));
}
if (!view.exists(keylet::depositPreauth(dst, sorted)))
if (!DepositPreauthEntryR(dst, sorted, view))
return tecNO_PERMISSION;
return tesSUCCESS;
@@ -386,7 +387,7 @@ checkDepositPreauth(
{
if (src != dst)
{
if (!view.exists(keylet::depositPreauth(dst, src)))
if (!DepositPreauthEntryR(dst, src, view))
{
return !tx.isFieldPresent(sfCredentialIDs)
? tecNO_PERMISSION

View File

@@ -9,6 +9,7 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/DepositPreauthEntry.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
@@ -245,7 +246,7 @@ AccountDelete::preclaim(PreclaimContext const& ctx)
// lsfDepositAuth flag set by default
if (sleDst->isFlag(lsfDepositAuth))
{
if (!ctx.view.exists(keylet::depositPreauth(dst, account)))
if (!DepositPreauthEntryR(dst, account, ctx.view))
return tecNO_PERMISSION;
}
}

View File

@@ -10,6 +10,7 @@
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/RawView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/DepositPreauthEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -418,7 +419,7 @@ transferHelper(
dst == claimOwner && depositAuthPolicy == DepositAuthPolicy::DstCanBypass;
if (!canBypassDepositAuth && sleDst->isFlag(lsfDepositAuth) &&
!psb.exists(keylet::depositPreauth(dst, src)))
!DepositPreauthEntryR(dst, src, psb))
{
return tecNO_PERMISSION;
}

View File

@@ -4,6 +4,7 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/entries/DepositPreauthEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -115,13 +116,13 @@ DepositPreauth::preclaim(PreclaimContext const& ctx)
// Verify that the Preauth entry they asked to add is not already
// in the ledger.
if (ctx.view.exists(keylet::depositPreauth(account, auth)))
if (DepositPreauthEntryR(account, auth, ctx.view))
return tecDUPLICATE;
}
else if (ctx.tx.isFieldPresent(sfUnauthorize))
{
// Verify that the Preauth entry they asked to remove is in the ledger.
if (!ctx.view.exists(keylet::depositPreauth(account, ctx.tx[sfUnauthorize])))
if (!DepositPreauthEntryR(account, ctx.tx[sfUnauthorize], ctx.view))
return tecNO_ENTRY;
}
else if (ctx.tx.isFieldPresent(sfAuthorizeCredentials))
@@ -140,16 +141,16 @@ DepositPreauth::preclaim(PreclaimContext const& ctx)
// Verify that the Preauth entry they asked to add is not already
// in the ledger.
if (ctx.view.exists(keylet::depositPreauth(account, sorted)))
if (DepositPreauthEntryR(account, sorted, ctx.view))
return tecDUPLICATE;
}
else if (ctx.tx.isFieldPresent(sfUnauthorizeCredentials))
{
// Verify that the Preauth entry is in the ledger.
if (!ctx.view.exists(
keylet::depositPreauth(
account,
credentials::makeSorted(ctx.tx.getFieldArray(sfUnauthorizeCredentials)))))
if (!DepositPreauthEntryR(
account,
credentials::makeSorted(ctx.tx.getFieldArray(sfUnauthorizeCredentials)),
ctx.view))
return tecNO_ENTRY;
}
return tesSUCCESS;
@@ -176,27 +177,27 @@ DepositPreauth::doApply()
// Preclaim already verified that the Preauth entry does not yet exist.
// Create and populate the Preauth entry.
AccountID const auth{ctx_.tx[sfAuthorize]};
Keylet const preauthKeylet = keylet::depositPreauth(accountID_, auth);
auto slePreauth = std::make_shared<SLE>(preauthKeylet);
DepositPreauthEntryW entryPreauth(accountID_, auth, view(), j_);
entryPreauth.newSLE();
slePreauth->setAccountID(sfAccount, accountID_);
slePreauth->setAccountID(sfAuthorize, auth);
view().insert(slePreauth);
entryPreauth->setAccountID(sfAccount, accountID_);
entryPreauth->setAccountID(sfAuthorize, auth);
entryPreauth.insert();
auto const page = view().dirInsert(
keylet::ownerDir(accountID_), preauthKeylet, describeOwnerDir(accountID_));
keylet::ownerDir(accountID_), entryPreauth.keylet(), describeOwnerDir(accountID_));
JLOG(j_.trace()) << "Adding DepositPreauth to owner directory "
<< to_string(preauthKeylet.key) << ": " << (page ? "success" : "failure");
<< to_string(entryPreauth.key()) << ": " << (page ? "success" : "failure");
if (!page)
return tecDIR_FULL; // LCOV_EXCL_LINE
slePreauth->setFieldU64(sfOwnerNode, *page);
entryPreauth->setFieldU64(sfOwnerNode, *page);
// If we succeeded, the new entry counts against the creator's reserve.
increaseOwnerCount(applyViewContext, sleOwner, 1, j_);
addSponsorToLedgerEntry(applyViewContext, slePreauth);
addSponsorToLedgerEntry(applyViewContext, entryPreauth.mutableRawSle());
}
else if (ctx_.tx.isFieldPresent(sfUnauthorize))
{
@@ -232,30 +233,30 @@ DepositPreauth::doApply()
sortedLE.pushBack(std::move(cred));
}
Keylet const preauthKey = keylet::depositPreauth(accountID_, sortedTX);
auto slePreauth = std::make_shared<SLE>(preauthKey);
if (!slePreauth)
DepositPreauthEntryW entryPreauth(accountID_, sortedTX, view(), j_);
entryPreauth.newSLE();
if (!entryPreauth)
return tefINTERNAL; // LCOV_EXCL_LINE
slePreauth->setAccountID(sfAccount, accountID_);
slePreauth->peekFieldArray(sfAuthorizeCredentials) = std::move(sortedLE);
entryPreauth->setAccountID(sfAccount, accountID_);
entryPreauth->peekFieldArray(sfAuthorizeCredentials) = std::move(sortedLE);
view().insert(slePreauth);
entryPreauth.insert();
auto const page = view().dirInsert(
keylet::ownerDir(accountID_), preauthKey, describeOwnerDir(accountID_));
keylet::ownerDir(accountID_), entryPreauth.keylet(), describeOwnerDir(accountID_));
JLOG(j_.trace()) << "Adding DepositPreauth to owner directory " << to_string(preauthKey.key)
<< ": " << (page ? "success" : "failure");
JLOG(j_.trace()) << "Adding DepositPreauth to owner directory "
<< to_string(entryPreauth.key()) << ": " << (page ? "success" : "failure");
if (!page)
return tecDIR_FULL; // LCOV_EXCL_LINE
slePreauth->setFieldU64(sfOwnerNode, *page);
entryPreauth->setFieldU64(sfOwnerNode, *page);
// If we succeeded, the new entry counts against the creator's reserve.
increaseOwnerCount(applyViewContext, sleOwner, 1, j_);
addSponsorToLedgerEntry(applyViewContext, slePreauth);
addSponsorToLedgerEntry(applyViewContext, entryPreauth.mutableRawSle());
}
else if (ctx_.tx.isFieldPresent(sfUnauthorizeCredentials))
{
@@ -271,7 +272,7 @@ TER
DepositPreauth::removeFromLedger(ApplyView& view, UInt256 const& preauthIndex, beast::Journal j)
{
// Existence already checked in preclaim and AccountDelete
auto const slePreauth{view.peek(keylet::depositPreauth(preauthIndex))};
DepositPreauthEntryW slePreauth(preauthIndex, view, j);
if (!slePreauth)
{
JLOG(j.warn()) << "Selected DepositPreauth does not exist.";
@@ -293,9 +294,9 @@ DepositPreauth::removeFromLedger(ApplyView& view, UInt256 const& preauthIndex, b
if (!sleOwner)
return tefINTERNAL; // LCOV_EXCL_LINE
decreaseOwnerCountForObject(view, sleOwner, slePreauth, 1, j);
decreaseOwnerCountForObject(view, sleOwner, slePreauth.mutableRawSle(), 1, j);
// Remove DepositPreauth from ledger.
view.erase(slePreauth);
slePreauth.erase();
return tesSUCCESS;
}