Compare commits

..
Author SHA1 Message Date
Denis Angell b4b680a587 ci: Address review feedback on the supported build and image 2026-10-07 18:55:57 +00:00
Denis Angell 2bb89eeb17 Local merge develop into dangell7/supported-cicd 2026-10-07 18:54:12 +00:00
Alex Kremer d343b542f1 refactor: Migrate handlers to rpc-spec (B) (#8484) 2026-10-07 13:46:37 +00:00
Ayaz Salikhov 7acd719bf7 build: Use images with Clang 23 except for clang-tidy (#8530) 2026-10-07 13:08:20 +00:00
Ayaz Salikhov b4564d5301 chore: Update pre-commit hooks and image (#8528) 2026-10-07 10:59:37 +00:00
Shawn Xie 60195e6d37 fix: Fix MPT partial payment overflow (#8302) 2026-10-06 23:16:13 +00:00
Ayaz Salikhov 3d526d456e build: Use LLVM 23 (#8522) 2026-10-06 21:19:57 +00:00
Denis AngellandMayukha Vadari f05c9f7913 refactor: Extract escrow lock helpers and paychan test helpers (#7882)
Co-authored-by: Mayukha Vadari <[email protected]>
2026-10-06 19:58:52 +00:00
Harshit GuptaandMayukha Vadari c2a4bc3aa1 fix: Validate vetoed parameter type in feature RPC (#7583)
Co-authored-by: Mayukha Vadari <[email protected]>
2026-10-06 19:44:56 +00:00
Mayukha Vadari 718185e3b2 refactor: Use CheckEntry everywhere (#8349) 2026-10-06 19:26:35 +00:00
Ayaz Salikhov 1d7783bb86 build: Make conan retry with Conan Center's source backups (#8524) 2026-10-06 19:23:38 +00:00
Mayukha Vadari 9fd2c552f5 refactor: Use AmendmentsEntry everywhere (#8368) 2026-10-06 17:59:44 +00:00
Ayaz Salikhov 70b8fd301b chore: Update docker images; link Conan-built tools with a static runtime (#8520) 2026-10-06 16:47:35 +00:00
Mayukha Vadari e6564f553d refactor: Use NegativeUNLEntry everywhere (#8365) 2026-10-06 14:23:24 +00:00
Ayaz Salikhov ed96e60ce3 build: Make clang-tools custom in Nix, to match what's being built (#8521) 2026-10-06 13:59:12 +00:00
Alex Kremer 2ebd745a1b refactor: Migrate handlers to rpc-spec (A) (#8345) 2026-10-06 13:19:20 +00:00
Mayukha Vadari cfcbe45b60 test: Declare, not define, entry instantiations in SLEBase test (#8357) 2026-10-06 12:12:22 +00:00
yinyiqian1andBart 9cbf78ba99 test: Add more tests for granular permissions (#8459)
Co-authored-by: Bart <[email protected]>
2026-10-05 23:18:58 +00:00
Timur Yalymov b8d8738f81 fix: Enforce that MPT issuance flags are never cleared (#8152) 2026-10-05 23:17:36 +00:00
63c97e719f feat: Allow lending transactions in Batch (#8244)
Co-authored-by: Cursor <[email protected]>
Co-authored-by: Vito Tumas <[email protected]>
2026-10-05 23:17:26 +00:00
3ac26f23c7 feat: Add full support for all objects in ledger_entry (#6319)
Co-authored-by: Timur Yalymov <[email protected]>
Co-authored-by: Cursor <[email protected]>
Co-authored-by: Vito Tumas <[email protected]>
Co-authored-by: Ayaz Salikhov <[email protected]>
2026-10-05 23:17:14 +00:00
BartandBart ff9410bc56 build: Define XRPL_ASAN, XRPL_TSAN, and XRPL_UBSAN compile definitions (#8483)
Co-authored-by: Bart <[email protected]>
2026-10-05 23:15:08 +00:00
Mayukha Vadari 1798262d7a refactor: Use LedgerHashesEntry everywhere (#8369) 2026-10-05 18:15:02 +00:00
Mayukha Vadari cd633b9ac9 refactor: Use EscrowEntry everywhere (#8354) 2026-10-05 17:51:18 +00:00
Ayaz Salikhov 5c5f7d315a chore: Update nix flake file (#8479) 2026-10-05 16:58:41 +00:00
Mayukha Vadari 0f7493ce50 refactor: Use FeeSettingsEntry everywhere (#8370) 2026-10-05 16:56:41 +00:00
Harshit Gupta 40f61f828a fix: Add string type validation for channel_id and signature (#7582) 2026-10-05 16:55:14 +00:00
Mayukha Vadari 108277f4b7 test: Migrate three beast suites from beast::unit_test to gtest (#7993) 2026-10-05 15:28:05 +00:00
Denis Angell 48ca26c2a4 ci: add the all-amendments supported build workflow 2026-09-12 14:20:05 -04:00
211 changed files with 5631 additions and 3751 deletions

No files matched your search

+72
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()
+9 -1
View File
@@ -44,4 +44,12 @@ runs:
--conf:all tools.build:jobs=${BUILD_NPROC} \
--conf:all tools.build:verbosity="${LOG_VERBOSITY}" \
--conf:all tools.compilation:verbosity="${LOG_VERBOSITY}" \
.
--format=json \
. >"${RUNNER_TEMP}/conan-graph.json"
# Tools that run during the build may only load glibc from the Nix store,
# as their package ID survives a GCC runtime update.
- name: Check build-context packages for Nix store dependencies (Linux)
if: ${{ runner.os == 'Linux' }}
shell: bash
run: ./bin/check-build-context-runtime.sh "${RUNNER_TEMP}/conan-graph.json"
@@ -99,6 +99,8 @@ class LinuxConfig:
suffix: str = ""
extra_cmake_args: str = ""
package: PackageConfig | None = None # set to also package this config
# Flip every amendment to Supported::Yes before building (perf/test only).
force_supported: bool = False
def __post_init__(self) -> None:
if isinstance(self.package, dict):
@@ -186,6 +188,7 @@ class MatrixEntry:
image: str = "" # container image; empty for macOS/Windows (runs natively)
compiler: str = "" # compiler name ("gcc" or "clang"); empty for macOS/Windows
toolchain: str = "" # "nix" for the flake's CI environment; see PlatformConfig
force_supported: bool = False # flip amendments to Supported::Yes before build
@dataclasses.dataclass
@@ -253,6 +256,7 @@ def expand_linux_matrix(linux: LinuxFile, minimal: bool) -> list[MatrixEntry]:
architecture=arch_info,
sanitizers=sanitizer,
compiler=compiler,
force_supported=cfg.force_supported,
)
)
+18 -9
View File
@@ -1,5 +1,5 @@
{
"image_tag": "sha-060957e",
"image_tag": "sha-3d526d4",
"configs": {
"ubuntu": [
{
@@ -17,7 +17,6 @@
"minimal": true,
"benchmark": true
},
{
"compiler": ["gcc"],
"build_type": ["Release"],
@@ -30,7 +29,6 @@
"arch": ["arm64"],
"minimal": false
},
{
"compiler": ["gcc", "clang"],
"build_type": ["Debug", "Release"],
@@ -38,7 +36,6 @@
"minimal": false,
"sanitizers": ["address", "undefinedbehavior"]
},
{
"compiler": ["clang"],
"build_type": ["Debug"],
@@ -62,9 +59,22 @@
"minimal": false,
"suffix": "unity",
"extra_cmake_args": "-Dunity=ON"
},
{
"compiler": ["gcc"],
"build_type": ["Release"],
"arch": ["amd64"],
"minimal": false,
"suffix": "supported",
"force_supported": true,
"extra_cmake_args": "-Dvalidator_keys=ON",
"package": {
"type": "deb",
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-e6055dd",
"variant": "supported"
}
}
],
"debian": [
{
"compiler": ["gcc"],
@@ -74,7 +84,7 @@
"extra_cmake_args": "-Dvalidator_keys=ON",
"package": {
"type": "deb",
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-3a2d19f"
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-e6055dd"
}
},
{
@@ -86,12 +96,11 @@
"extra_cmake_args": "-Dvalidator_keys=ON -Dassert=ON",
"package": {
"type": "deb",
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-3a2d19f",
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-e6055dd",
"variant": "assert"
}
}
],
"rhel": [
{
"compiler": ["gcc"],
@@ -101,7 +110,7 @@
"extra_cmake_args": "-Dvalidator_keys=ON",
"package": {
"type": "rpm",
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-3a2d19f"
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-e6055dd"
}
}
]
-1
View File
@@ -13,7 +13,6 @@ on:
- "!nix/devshell.nix"
- "!nix/check-tools/**"
- "bin/default-loader-path.sh"
- "bin/install-sanitizer-libs.sh"
pull_request:
paths:
- ".github/workflows/build-nix-images.yml"
@@ -5,7 +5,6 @@ on:
branches:
- develop
paths:
- ".github/workflows/build-packaging-images.yml"
- "bin/install-packaging-tools.sh"
- "package/images/packaging/**"
pull_request:
@@ -5,7 +5,6 @@ on:
branches:
- develop
paths:
- ".github/workflows/build-pre-commit-image.yml"
- "bin/pre-commit/Dockerfile"
- "rust-toolchain.toml"
pull_request:
+105
View File
@@ -0,0 +1,105 @@
# Package the "all amendments Supported::Yes" build into a runtime Docker image
# and push it to GHCR, as a drop-in for the rippleci/xrpld image xrpl.js uses
# for standalone testing -- except every amendment is built Supported::Yes.
#
# This does NOT build or package anything: the Trigger workflow already builds
# the supported binary and the supported .deb (the force_supported build config
# and the matching supported package config in linux.json). This workflow waits
# for a successful Trigger run on develop, downloads that run's supported .deb
# artifact, installs it into a slim base (docker/supported.Dockerfile, which
# replicates rippleci's layout), and pushes ghcr.io/xrplf/xrpld/supported.
#
# Perf/test artifact only -- never run it on a production validator.
name: Build supported Docker image
on:
workflow_run:
workflows: ["Trigger"]
types: [completed]
branches: [develop]
# Manual runs: point at a specific completed Trigger run via its run id.
workflow_dispatch:
inputs:
trigger_run_id:
description: "Run id of the Trigger workflow whose supported .deb to package."
required: true
type: string
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
env:
IMAGE_NAME: ghcr.io/xrplf/xrpld/supported
# The supported .deb artifact uploaded by reusable-package.yml:
# <artifact_name>-pkg, where artifact_name carries the -supported suffix.
DEB_ARTIFACT: xrpld-ubuntu-gcc-release-amd64-supported-pkg
SOURCE_RUN_ID: ${{ github.event.workflow_run.id || github.event.inputs.trigger_run_id }}
jobs:
image:
# Only for successful Trigger runs (workflow_run), and only on the canonical
# repo where GITHUB_TOKEN can push to ghcr.io/xrplf/*.
if: ${{ github.repository == 'XRPLF/rippled' && (github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success') }}
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
- name: Download the supported .deb from the Trigger run
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ env.DEB_ARTIFACT }}
path: dl
run-id: ${{ env.SOURCE_RUN_ID }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Assemble build context
run: |
set -euo pipefail
mkdir -p docker-context
deb="$(find dl -name '*.deb' | head -n1)"
[ -n "${deb}" ] || {
echo "::error::no supported .deb found in run ${SOURCE_RUN_ID}"
exit 1
}
mv "${deb}" docker-context/xrpld.deb
echo "Packaging $(basename "${deb}") into ${IMAGE_NAME}"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: Login to GitHub Container Registry
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker metadata
id: meta
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=sha-,format=short
type=raw,value=latest,enable=${{ github.event_name == 'workflow_run' }}
- name: Build and push
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
context: docker-context
file: docker/supported.Dockerfile
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
+1 -1
View File
@@ -34,7 +34,7 @@ permissions:
jobs:
audit:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
permissions:
contents: read
# Needed to open an issue on scheduled failures.
+1 -1
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-473fe44" }'
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-70b8fd3" }'
+1 -1
View File
@@ -41,7 +41,7 @@ env:
jobs:
build:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -74,6 +74,11 @@ on:
required: false
type: string
default: ""
force_supported:
description: "Flip every amendment to Supported::Yes before building. For perf/test builds only; never for release artifacts."
required: false
type: boolean
default: false
secrets:
CODECOV_TOKEN:
@@ -128,6 +133,20 @@ jobs:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Force all amendments to Supported::Yes
if: ${{ inputs.force_supported && runner.os == 'Linux' }}
run: |
set -euo pipefail
MACRO="include/xrpl/protocol/detail/features.macro"
echo "Flipping Supported::No -> Supported::Yes in ${MACRO}:"
grep -n 'Supported::No,' "${MACRO}" || echo " (none found)"
sed -i 's/Supported::No,/Supported::Yes,/g' "${MACRO}"
if grep -q 'Supported::No,' "${MACRO}"; then
echo "::error::Supported::No entries remain after sed"
exit 1
fi
git diff -- "${MACRO}"
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
with:
@@ -52,5 +52,6 @@ jobs:
sanitizers: ${{ matrix.sanitizers }}
compiler: ${{ matrix.compiler || '' }}
toolchain: ${{ matrix.toolchain || '' }}
force_supported: ${{ matrix.force_supported || false }}
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
needs: [determine-files]
if: ${{ needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.need_full_run == 'true' }}
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-060957e"
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-ed96e60"
permissions:
contents: read
issues: write
+3 -3
View File
@@ -28,7 +28,7 @@ permissions:
jobs:
clippy:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -41,7 +41,7 @@ jobs:
coverage:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -70,7 +70,7 @@ jobs:
doc:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+1 -1
View File
@@ -40,7 +40,7 @@ defaults:
jobs:
upload:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
env:
REMOTE_NAME: ${{ inputs.remote_name }}
CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.remote_username }}
+6 -5
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]
+11
View File
@@ -29,6 +29,16 @@ Version 3.5.0 is not yet released.
### Additions in 3.5.0
- `subscribe`, `unsubscribe`: Added an optional `mpt_issuances` request field, an array of MPT issuance IDs (hex strings). Subscribers receive a message with `type` `mptTransaction` for each validated transaction whose metadata affects a subscribed issuance; the message has the same fields as the `transactions` stream. MPT issuance subscriptions count toward the per-connection subscription limit. An empty array, a non-array value, or an invalid ID returns `invalidParams`. ([#5671](https://github.com/XRPLF/rippled/pull/5671))
- `ledger_entry`: Add full support for checks, NFT offers, payment channels, and signer lists. ([#6319](https://github.com/XRPLF/rippled/pull/6319))
### Bugfixes in 3.5.0
- `channel_authorize`: The `channel_id` field now returns an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
- `channel_verify`: The `channel_id` and `signature` fields now return an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
### Bugfixes in 3.5.0
- `feature`: The admin-only `vetoed` field now returns `invalidParams` unless its value is a boolean. [#7583](https://github.com/XRPLF/rippled/pull/7583)
## XRP Ledger server version 3.4.0
@@ -50,6 +60,7 @@ Version 3.4.0 is not yet released. These changes are available in the 3.4.0 beta
- `account_lines`: The `peer` field now returns an error if the value is not a string. [#7728](https://github.com/XRPLF/rippled/pull/7728)
- `ledger`: `delivered_amount` is now included in the metadata of successful `AccountDelete` transactions when transactions are expanded (`expand`, or admin-only `full`). Previously it was only added for `Payment` and `CheckCash`, which made `ledger` inconsistent with `tx` and `account_tx`. [#5706](https://github.com/XRPLF/rippled/pull/5706)
- `noripple_check`: The `transactions` field is no longer included in error responses; it is still returned (possibly as an empty array) whenever `transactions` is `true` and the request succeeds. A malformed `account` is now rejected before the ledger is looked up, so that error response no longer carries the `ledger_hash`, `ledger_index`, and `validated` fields ([#6303](https://github.com/XRPLF/rippled/pull/6303)).
- `transaction_entry`: An object or an array in `tx_hash` now returns `malformedRequest`, like any other value that is not a hex hash, instead of an `internal` error.
## XRP Ledger server version 3.3.0
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
# Fail if a binary of a build-context Conan package loads anything from the Nix
# store other than glibc, or cannot resolve a library at all.
#
# Only binaries linked by the Nix toolchain are checked, i.e. those recording a
# store path as their interpreter or RUNPATH. Prebuilt upstream binaries (such
# as the ones the cmake package ships) use the system loader instead.
#
# Build-context packages provide the tools that run during the build (protoc,
# grpc_cpp_plugin, ...). Their package ID does not change when a Nix toolchain
# update moves the GCC runtime to a new store path, so a cached binary has to
# get by with the pinned glibc alone. See docs/build/nix.md.
#
# Usage: bin/check-build-context-runtime.sh <graph.json>
# <graph.json> is the output of `conan install --format=json`.
set -euo pipefail
if [ "$#" -ne 1 ]; then
echo "usage: $0 <graph.json>" >&2
exit 2
fi
if [ "$(uname -s)" != "Linux" ]; then
echo "$0: Linux only" >&2
exit 2
fi
folders="$(jq -r '.graph.nodes[] | select(.context == "build" and .package_folder) | .package_folder' "$1" | sort -u)"
checked=0
failed=0
while IFS= read -r file; do
case "$(file -b "${file}")" in
ELF*) ;;
*) continue ;;
esac
[[ "$(readelf -ldW "${file}")" == */nix/store/* ]] || continue
checked=$((checked + 1))
# `ldd` lists the interpreter and every library as the loader resolves them.
if deps="$(ldd "${file}" 2>&1)"; then
bad="$(printf '%s\n' "${deps}" |
grep -E 'not found|/nix/store/' |
grep -vE '/nix/store/[^/]+-glibc-[^/]+/' || true)"
else
case "${deps}" in
*"not a dynamic executable"*) continue ;;
esac
bad="${deps}"
fi
if [ -n "${bad}" ]; then
failed=$((failed + 1))
echo "::error file=${file}::loads a library from the Nix store other than glibc"
echo "${file}"
echo "${bad}" | sed 's/^/ /'
fi
done < <(
# shellcheck disable=SC2086 # one folder per line, no spaces in Conan paths
[ -z "${folders}" ] || find ${folders} -type f \( -perm -u+x -o -name '*.so*' \)
)
echo "Build-context packages: checked ${checked} binaries, ${failed} failed."
[ "${failed}" -eq 0 ]
+17 -6
View File
@@ -20,9 +20,11 @@
# development setups, but not in the macOS CI environment. They are checked
# everywhere except when running in CI on macOS.
#
# Tools that Nix also exposes under a version-suffixed name (`clang-tidy-22`,
# `g++-15`, ...) are probed under both names: a suffixed name can break while
# the plain one still works (see mkVersionedToolLinks in nix/packages.nix).
# Tools that Nix also exposes under a version-suffixed name
# (`clang-tidy-<v>`, `g++-<v>`, ...) are probed under both names:
# a suffixed name can break while the plain one still works
# (see mkVersionedToolLinks in nix/packages.nix).
# The suffix is the major version of the plain `clang` / `gcc` on PATH.
#
# Tools scoped to a single dev shell rather than to commonPackages are checked
# only in that shell, keyed off XRPL_DEVSHELL.
@@ -34,9 +36,16 @@
set -uo pipefail
# Version suffixes of the Nix tool links, tracking nix/packages.nix.
gcc_version=15
llvm_version=22
# major_version <compiler>
# Major version of a compiler on PATH, or "unknown" when it isn't there.
major_version() {
local version
version="$("$1" -dumpversion 2>/dev/null)" || version=""
version="${version%%.*}"
printf '%s' "${version:-unknown}"
}
llvm_version="$(major_version clang)"
missing=()
checked=0
@@ -112,6 +121,7 @@ if [ "${os}" = "linux" ] || [ "${os}" = "macos" ]; then
check ClangBuildAnalyzer
check curl
check file
check jq
check less
check make
# net-tools netstat reports "net-tools X.Y"; macOS ships BSD netstat with no
@@ -180,6 +190,7 @@ fi
if [ "${os}" = "linux" ]; then
echo
echo "GCC toolchain:"
gcc_version="$(major_version gcc)"
check gcc
check "gcc-${gcc_version}"
check g++
+1 -1
View File
@@ -23,7 +23,7 @@ apt-get clean
rm -rf /var/lib/apt/lists/*
EOF
ARG PRE_COMMIT_VERSION=4.6.0
ARG PRE_COMMIT_VERSION=4.6.2
RUN pip install --no-cache --break-system-packages \
pre-commit==${PRE_COMMIT_VERSION}
+20 -7
View File
@@ -26,8 +26,6 @@ import sys
import tempfile
from pathlib import Path
CLANG_TIDY_VERSION = 22
# Extensions run-clang-tidy can analyse: `.cpp` translation units and, thanks to
# the `verify_headers` build option, `.h`/`.hpp` headers (each has its own
# compile_commands.json entry). `.ipp` fragments have no entry and are skipped.
@@ -39,8 +37,21 @@ TIDY_EXTENSIONS = {".cpp", ".h", ".hpp"}
FILEPATH_RE = re.compile(r"^(\s*(?:-\s+)?FilePath:\s*)'((?:[^']|'')*)'\s*$")
def find_tool(name: str) -> str | None:
for candidate in (f"{name}-{CLANG_TIDY_VERSION}", name):
def clang_tidy_major() -> str | None:
"""Major version of the `clang-tidy` on PATH, which run-clang-tidy invokes."""
if not (clang_tidy := shutil.which("clang-tidy")):
return None
output = subprocess.run(
[clang_tidy, "--version"], capture_output=True, text=True
).stdout
m = re.search(r"LLVM version (\d+)", output)
return m.group(1) if m else None
def find_tool(name: str, version: str | None) -> str | None:
"""Prefer `<name>-<version>`, so a host tool of another version can't win."""
candidates = ([f"{name}-{version}"] if version else []) + [name]
for candidate in candidates:
if path := shutil.which(candidate):
return path
return None
@@ -103,8 +114,9 @@ def main():
if not files:
return 0
run_clang_tidy = find_tool("run-clang-tidy")
clang_apply_replacements = find_tool("clang-apply-replacements")
version = clang_tidy_major()
run_clang_tidy = find_tool("run-clang-tidy", version)
clang_apply_replacements = find_tool("clang-apply-replacements", version)
missing = [
name
for name, path in (
@@ -114,9 +126,10 @@ def main():
if not path
]
if missing:
tried = f" (tried the '-{version}' suffix too)" if version else ""
print(
f"clang-tidy check failed: TIDY is enabled but {' and '.join(missing)} "
f"was not found in PATH (tried the '-{CLANG_TIDY_VERSION}' suffix too).",
f"was not found in PATH{tried}.",
file=sys.stderr,
)
return 1
+9
View File
@@ -292,6 +292,14 @@ if(xrpld)
)
target_sources(xrpld PRIVATE ${sources})
rpcspec_generate_instantiations(
OUT_VAR rpcspec_instantiations
VALUE_TYPE "::json::Value"
VIEW_HEADER "xrpld/rpc/detail/JsonObjectView.hpp"
HANDLERS book_changes ledger transaction_entry
)
target_sources(xrpld PRIVATE ${rpcspec_instantiations})
if(tests)
file(
GLOB_RECURSE sources
@@ -322,6 +330,7 @@ if(xrpld)
# antithesis_instrumentation.h, which is not exported as INTERFACE
target_include_directories(
xrpld
SYSTEM
PRIVATE ${CMAKE_SOURCE_DIR}/external/antithesis-sdk
)
endif()
+6 -1
View File
@@ -77,19 +77,24 @@ if(is_clang)
message(STATUS " Ignorelist: ${ignorelist_path}")
endif()
# Define SANITIZERS macro for BuildInfo.cpp
# Define the SANITIZERS macro for BuildInfo.cpp, plus one of XRPL_ASAN,
# XRPL_TSAN and XRPL_UBSAN per active sanitizer, so that code can test for a
# specific one with #ifdef instead of parsing the dot-joined SANITIZERS string.
set(sanitizers_list)
if(SANITIZERS MATCHES "address")
set(enable_asan ON)
list(APPEND sanitizers_list "ASAN")
target_compile_definitions(common INTERFACE XRPL_ASAN)
endif()
if(SANITIZERS MATCHES "thread")
set(enable_tsan ON)
list(APPEND sanitizers_list "TSAN")
target_compile_definitions(common INTERFACE XRPL_TSAN)
endif()
if(SANITIZERS MATCHES "undefinedbehavior")
set(enable_ubsan ON)
list(APPEND sanitizers_list "UBSAN")
target_compile_definitions(common INTERFACE XRPL_UBSAN)
endif()
if(sanitizers_list)
+6 -2
View File
@@ -3,7 +3,7 @@
"requires": [
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1782392402.420688",
"xrpl-rpc-spec/0.1.19#870b2d3abcfbbf13b61c2d3c69495060%1790348286.187549",
"xrpl-rpc-spec/0.1.21#d536f87a2ae7d313452746cfa3ac4404%1790869005.122975",
"sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1782392403.185447",
"soci/4.0.3#e726491a03468795453f7c83fc924a96%1782392402.679521",
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1782307151.633168",
@@ -20,7 +20,7 @@
"libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1782392403.066892",
"jemalloc/5.3.1#1fc58d55316041f10fbc1e8a2eae632a%1776700028.228",
"gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1782392402.791979",
"grpc/1.81.1#b87796a4269034856cbc1a2522db16eb%1788275071.530512",
"grpc/1.81.1#aaa93ab6cda2f2baa6a84490582c8adf%1791284951.826256",
"fast_float/8.2.10#f6f28d6bb22112078e7dbda611caf681%1785888854.601666",
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1782307148.15562",
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1782392402.538492",
@@ -34,11 +34,15 @@
"build_requires": [
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
"strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1782395692.540639",
"re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1782392402.431897",
"protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933",
"openssl/3.6.3#f806de8933e3bf6f01016c6a888cee2e%1783945160.863288",
"nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1782395690.33162",
"msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649",
"m4/1.4.19#1727f439cf74e83826ec96d0b4904eee%1784541921.659",
"grpc/1.81.1#aaa93ab6cda2f2baa6a84490582c8adf%1791284951.826256",
"cmake/4.3.3#840cf00ea09777e05c2050a50a82c722%1782392418.696091",
"c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1782392402.681654",
"b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1782392402.624226",
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
"autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86",
+9 -1
View File
@@ -3,5 +3,13 @@
core:non_interactive=True
core.download:parallel={{ os.cpu_count() }}
core.upload:parallel={{ os.cpu_count() }}
tools.files.download:retry=5
# Fall back to Conan Center's source backups when a recipe's upstream URL is down
# (e.g. the GNU FTP mirrors), see
# https://github.com/conan-io/conan-center-index/issues/28147#issuecomment-3183544772
# The backups are only tried once every upstream URL has used up its retries,
# so keep the retries low.
core.sources:download_urls=["origin", "https://c3i.jfrog.io/artifactory/conan-center-backup-sources"]
tools.files.download:retry=1
tools.files.download:retry_wait=10
# Fail fast on unreachable hosts (default connect timeout is 30s), keep the 60s read timeout.
core.net.http:timeout=(5, 60)
+24 -3
View File
@@ -29,9 +29,9 @@ os.version={{ min_macos_version }}
[conf]
{# The Boost recipe builds with b2, which doesn't use Conan's toolchain files. #}
{# Instead it hand-rolls the compiler for user-config.jam, #}
{# and its fallback probes a version-suffixed binary (e.g. `g++-15`) before plain `g++`. #}
{# Inside the Nix shell the wrapper only provides `g++`/`gcc` (no `-15` suffix), #}
{# so on a host that also has a system `g++-15` the probe escapes Nix #}
{# and its fallback probes a version-suffixed binary (e.g. `g++-<major>`) before plain `g++`. #}
{# Inside the Nix shell the wrapper only provides `g++`/`gcc` (no `-<major>` suffix), #}
{# so on a host that also has a system `g++-<major>` the probe escapes Nix #}
{# and picks the system compiler, which is mismatched with the Nix libraries #}
{# and breaks the build (e.g. Boost.Stacktrace link checks fail). #}
{# Pinning the executables here short-circuits that probe so Boost (and the rest of the toolchain) #}
@@ -49,6 +49,17 @@ tools.build:compiler_executables={'c':'{{ cc_exe }}','cpp':'{{ cxx_exe }}'}
user.package:cppstd_version=23
tools.info.package_id:confs+=["user.package:cppstd_version"]
{% if os == "Linux" and context == "build" %}
{# Build-context executables (protoc, grpc_cpp_plugin, build tools) run during the build #}
{# and would otherwise load libstdc++/libgcc from a Nix store path #}
{# that might change with a Nix toolchain update. #}
{# --as-needed drops the ones they link but don't use, #}
{# such as libatomic for grpc_cpp_plugin on arm64. #}
{% set static_runtime_flags = ["-static-libstdc++", "-static-libgcc", "-Wl,--as-needed"] %}
tools.build:exelinkflags+={{ static_runtime_flags }}
tools.info.package_id:confs+=["tools.build:exelinkflags"]
{% endif %}
{% if os == "Macos" %}
[buildenv]
{# os.version adds -mmacosx-version-min to compiler command lines, #}
@@ -58,3 +69,13 @@ tools.info.package_id:confs+=["user.package:cppstd_version"]
{# Scoped to boost/* since it is the only gap. #}
boost/*:MACOSX_DEPLOYMENT_TARGET={{ min_macos_version }}
{% endif %}
{% if os == "Linux" and context == "build" %}
{# b2 links itself with its own script, which ignores exelinkflags #}
{# and only takes CXXFLAGS when use_cxx_env is set. #}
[options]
b2/*:use_cxx_env=True
[buildenv]
b2/*:CXXFLAGS={{ static_runtime_flags | join(" ") }}
{% endif %}
+3
View File
@@ -5,6 +5,9 @@ include(default)
{% if not sanitizers %}
{# Sanitizers not configured; no additional settings needed #}
{% elif context == "build" %}
{# Build-context packages are tools we run, not code we test, #}
{# so don't instrument them #}
{% else %}
{% if compiler == "msvc" %}
+7 -2
View File
@@ -40,7 +40,7 @@ class Xrpl(ConanFile):
"nudb/2.0.9",
"openssl/3.6.3",
"soci/4.0.3",
"xrpl-rpc-spec/0.1.19",
"xrpl-rpc-spec/0.1.21",
"zlib/1.3.2",
]
@@ -49,7 +49,8 @@ class Xrpl(ConanFile):
]
tool_requires = [
"protobuf/6.33.5",
"grpc/<host_version>",
"protobuf/<host_version>",
]
default_options = {
@@ -123,6 +124,10 @@ class Xrpl(ConanFile):
"xxhash/*:shared": False,
}
# default_options only reach the host context;
# give tool_requires (and their dependencies) the same dependency options.
default_build_options = {k: v for k, v in default_options.items() if "/" in k}
def set_version(self):
self.version = self.version or DEV_VERSION
+5 -6
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
+28
View File
@@ -0,0 +1,28 @@
# Runtime image for the perf/test xrpld build with all amendments Supported::Yes.
# Installs the .deb into ubuntu:jammy (matching rippleci/xrpld): gives
# /usr/bin/xrpld, /etc/xrpld/xrpld.cfg, and the xrpld user.
# NOT for production validators.
ARG BASE_IMAGE=ubuntu:jammy@sha256:b8b6ee6aa931ecd9d0d952abc34dc0e5f7c6a30c6bb71b079fe399fde0329c02
FROM ${BASE_IMAGE}
# Build context must contain the supported package as xrpld.deb.
COPY xrpld.deb /tmp/xrpld.deb
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends ca-certificates jq /tmp/xrpld.deb; \
rm -rf /var/lib/apt/lists/* /tmp/xrpld.deb
RUN set -eux; \
id -u xrpld >/dev/null 2>&1 || \
useradd --system --home-dir /var/lib/xrpld --shell /sbin/nologin --user-group xrpld
# Symlink for consumers that exec /opt/xrpld/bin/xrpld.
RUN set -eux; \
mkdir -p /var/log/xrpld /var/lib/xrpld /opt/xrpld/bin; \
chown -R xrpld:xrpld /var/log/xrpld /var/lib/xrpld; \
ln -sf /usr/bin/xrpld /opt/xrpld/bin/xrpld
EXPOSE 2459/tcp 5005/tcp 6006/tcp
USER xrpld
ENTRYPOINT ["/usr/bin/xrpld"]
+9 -7
View File
@@ -10,14 +10,15 @@ This document explains how to set one up.
support it — see [compiler support for C++23][cpp23-support].
The versions currently tested in CI are:
| Compiler | Version |
| ----------- | ------------------ |
| GCC | 15.2 |
| Clang | 22 |
| Apple Clang | 21 |
| MSVC | Visual Studio 2026 |
| Compiler | Version |
| ----------- | ------------------------------- |
| GCC | `gccVersion` in [packages.nix] |
| Clang | `llvmVersion` in [packages.nix] |
| Apple Clang | 21 |
| MSVC | Visual Studio 2026 |
LLVM tools (`clang-tidy` and `clang-format`) are also pinned to version 22.
LLVM tools (`clang-tidy` and `clang-format`)
come from the same LLVM release as Clang.
### Older compilers
@@ -156,3 +157,4 @@ version out of the box — run it via `run-clang-tidy`. No separate installation
is needed.
[cpp23-support]: https://en.cppreference.com/w/cpp/compiler_support/23
[packages.nix]: ../../nix/packages.nix
+16 -4
View File
@@ -194,10 +194,22 @@ bin/check-nix-store-refs.sh ~/.conan2-nix
```
It works on Linux too, but asserts something narrower there: the toolchain always
writes the store into `PT_INTERP` and `RUNPATH`, and CI builds inside an image
whose store is fixed for its lifetime, so that is fine. Only the binaries
[`PatchNixBinary.cmake`](../../cmake/PatchNixBinary.cmake) retargets to the
system loader have to be clean, and those are what CI checks:
writes the store into `PT_INTERP` and `RUNPATH`. That is fine for the pinned
glibc, whose path does not move, but not for the GCC runtime, which moves with
every GCC update. So [`conan/profiles/default`](../../conan/profiles/default)
links build-context packages, whose executables run during the build, with
`-static-libstdc++ -static-libgcc -Wl,--as-needed`, and
[`conan/profiles/sanitizers`](../../conan/profiles/sanitizers) does not
instrument them. CI checks that they load nothing from the store but glibc, from
the graph `conan install --format=json` writes:
```bash
bin/check-build-context-runtime.sh graph.json
```
Only the binaries [`PatchNixBinary.cmake`](../../cmake/PatchNixBinary.cmake)
retargets to the system loader have to be fully clean, and those are what CI
checks:
```bash
bin/check-nix-store-refs.sh build/xrpld
+1 -1
View File
@@ -6,7 +6,7 @@ project(antithesis-sdk-cpp VERSION 0.4.4 LANGUAGES CXX)
add_library(antithesis-sdk-cpp INTERFACE antithesis_sdk.h)
# Note, both sections below created by xrpld project
target_include_directories(antithesis-sdk-cpp INTERFACE
target_include_directories(antithesis-sdk-cpp SYSTEM INTERFACE
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)
Generated
+6 -6
View File
@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1781173989,
"narHash": "sha256-fnzKKPvS+oieI/pTzotA5tkoM47EB1NpaBcgk4R97hE=",
"lastModified": 1791130267,
"narHash": "sha256-1sjwcQMcgAbmiip/VivBSiK8p2bTkQGOvCuO7vnwfx4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "8c91a71d13451abc40eb9dae8910f972f979852f",
"rev": "9013764fcc0ea99fa16cf7aa7decf8a5c3889dd2",
"type": "github"
},
"original": {
@@ -47,11 +47,11 @@
]
},
"locked": {
"lastModified": 1784611586,
"narHash": "sha256-OfqgY+0hp/zseZB7uyH0U8kIDPS4scZZCyAurEplvG0=",
"lastModified": 1791189933,
"narHash": "sha256-Y8eN7ki0Urx4Ojf4w1xSpWg8uk/3lJqK+E0Oth77rH0=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "14f58845249f3552a89b07772626b8d3c632fa86",
"rev": "e60029353d0c48d216bc4b065168ccd4079c166f",
"type": "github"
},
"original": {
@@ -17,7 +17,7 @@
namespace xrpl {
template <typename Key>
static std::size_t
std::size_t
extract(Key const& key)
{
return key;
+1 -1
View File
@@ -20,7 +20,7 @@ namespace beast::unit_test {
namespace detail {
template <class String>
static std::string
std::string
makeReason(String const& reason, char const* file, int line)
{
std::string s(reason);
+1 -2
View File
@@ -5,7 +5,6 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Keylet.h>
@@ -212,7 +211,7 @@ canWithdraw(
ReadView const& view,
AccountID const& from,
AccountID const& to,
AccountRootEntryR const& toSle,
SLE::ConstRef toSle,
STAmount const& amount,
bool hasDestinationTag,
std::optional<std::vector<UInt256>> const& credentialIDs = std::nullopt);
@@ -7,20 +7,9 @@
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/XRPAmount.h>
#include <cstdint>
#include <optional>
namespace xrpl {
struct Adjustment
{
std::int32_t ownerCountDelta = 0;
std::int32_t accountCountDelta = 0;
};
template <typename ViewT>
class AccountRootEntry : public SLEBase<ViewT, ltACCOUNT_ROOT>
{
@@ -38,123 +27,6 @@ public:
: Base(keylet::account(id), view, j)
{
}
/**
* Returns the account reserve, in drops.
*
* Actual owner count can be adjusted by delta in ownerCountAdj
* Actual reserve count can be adjusted by delta in accountCountAdj
* The reserve is calculated as:
* (ownerCount + "sponsoring object count" - "sponsored object count" + additionalOwnerCount) *
* increment + (1 if not sponsored account + sponsoringAccountCount) * "reserve base"
*
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative
* to subtract.
* @return The account reserve amount in drops
*/
[[nodiscard]] XRPAmount
reserve(Adjustment adj = {}) const;
/**
* Return number of the objects which reserve is covered by the account (so called "owner
* count"). Actual owner count can be adjusted by delta in ownerCountAdj.
*
* @param ownerCountAdj Adjustment to the owner count (default: 0)
* @return The adjusted owner count
*/
[[nodiscard]] std::uint32_t
ownerCount(std::int32_t ownerCountAdj = 0) const;
/**
* Check if this account has sufficient reserve.
*
* @param ctx The apply-view context (view + tx)
* @param accBalance The account's balance
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative
* to subtract.
* @param insufReserveCode The transaction result code to return if the reserve is
* insufficient (default: tecINSUFFICIENT_RESERVE).
* @return Transaction result code
*/
[[nodiscard]] TER
checkReserve(
ApplyViewContext ctx,
XRPAmount accBalance,
std::optional<AccountRootEntry<ReadView>> const& sponsorSle,
Adjustment adj,
TER insufReserveCode = tecINSUFFICIENT_RESERVE) const;
/**
* Check if this account has sufficient reserve, deriving the sponsor internally.
*
* Equivalent to the overload above, but resolves the sponsor via
* getEffectiveTxReserveSponsor(ctx, *this) instead of taking it explicitly. Use this
* in the common case where the sponsor is simply the transaction's reserve
* sponsor for this account. Callers that must force the account's-own-reserve branch
* (passing a null sponsor) or supply a different sponsor should use the
* explicit overload above.
*
* @param ctx The apply-view context (view + tx)
* @param accBalance The account's balance
* @param adj Reserve adjustments (owner/account count deltas)
* @return Transaction result code
*/
[[nodiscard]] TER
checkReserve(ApplyViewContext ctx, XRPAmount accBalance, Adjustment adj) const;
/**
* Increase owner-count fields when the caller supplies the sponsor.
*
* This helper does not create a ledger object. It updates reserve accounting
* after the caller has created/updated an object.
* If sponsorSle is provided, this also adjusts the account's sponsored count
* and the sponsor's sponsoring count.
*
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param count Amount to add to the owner count
*/
void
increaseOwnerCount(std::optional<AccountRootEntry<ApplyView>>& sponsorSle, std::uint32_t count)
requires Base::kIsWritable;
/**
* Increase owner-count fields, deriving the tx reserve sponsor internally.
*
* Equivalent to the overload above, but resolves the sponsor via
* getEffectiveTxReserveSponsor(ctx, *this) instead of taking it explicitly. Use
* this when the sponsor is the transaction's reserve sponsor for this account
* (the common create path). Deletion paths, which derive the sponsor from an
* object's sfSponsor field, should keep using the explicit overload.
*
* @param ctx The apply-view context (view + tx)
* @param count Amount to add to the owner count
*/
void
increaseOwnerCount(ApplyViewContext ctx, std::uint32_t count)
requires Base::kIsWritable;
/**
* Decrease owner-count fields when the caller supplies the sponsor.
*
* This helper does not delete a ledger object. It updates reserve accounting
* after the caller has removed an owner-counted reserve, or for special
* owner-count changes whose sponsor cannot be derived from an object's
* sfSponsor field.
*
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param count Amount to remove from the owner count
*/
void
decreaseOwnerCount(std::optional<AccountRootEntry<ApplyView>>& sponsorSle, std::uint32_t count)
requires Base::kIsWritable;
private:
void
adjustOwnerCountSigned(
std::optional<AccountRootEntry<ApplyView>>& sponsorSle,
std::int32_t adjustment)
requires Base::kIsWritable;
};
using AccountRootEntryR = AccountRootEntry<ReadView>;
@@ -1,11 +1,17 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <map>
#include <set>
namespace xrpl {
@@ -25,6 +31,52 @@ public:
: Base(keylet::amendments(), view, j)
{
}
/**
* Returns the set of amendments this entry reports as enabled.
*
* @return the set of enabled amendments.
*/
[[nodiscard]] std::set<UInt256>
enabledAmendments() const
{
std::set<UInt256> amendments;
if (this->exists() && (*this)->isFieldPresent(sfAmendments))
{
auto const& v = (*this)->getFieldV256(sfAmendments);
amendments.insert_range(v);
}
return amendments;
}
/**
* Returns a map of amendments that have achieved majority, to the time
* majority was reached.
*
* @return a map of amendment to the time majority was reached.
*/
[[nodiscard]] std::map<UInt256, NetClock::time_point>
majorityAmendments() const
{
std::map<UInt256, NetClock::time_point> ret;
if (this->exists() && (*this)->isFieldPresent(sfMajorities))
{
using TimePoint = NetClock::time_point;
using Duration = TimePoint::duration;
auto const majorities = (*this)->getFieldArray(sfMajorities);
for (auto const& m : majorities)
{
ret[m.getFieldH256(sfAmendment)] = TimePoint(Duration(m.getFieldU32(sfCloseTime)));
}
}
return ret;
}
};
using AmendmentsEntryR = AmendmentsEntry<ReadView>;
@@ -1,11 +1,17 @@
#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/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STVector256.h>
#include <cstddef>
#include <optional>
namespace xrpl {
@@ -25,6 +31,31 @@ public:
: Base(keylet::skip(), view, j)
{
}
/**
* Looks up a hash `diff` slots back from the most recent entry in the
* sfHashes vector (diff == 0 is the most recent entry).
*
* Callers decide which skip list entry to read and how to translate a
* target ledger sequence into `diff`; this only does the bounds check
* and vector indexing shared by both the recent (stride 1) and distant
* (stride 256) skip lists.
*
* @param diff how many slots back from the most recent hash to look up;
* 0 is the most recent hash.
* @return the hash at that slot, or std::nullopt if the entry does not
* exist or `diff` is out of range.
*/
[[nodiscard]] std::optional<UInt256>
hashAt(std::size_t diff) const
{
if (!this->exists())
return std::nullopt;
STVector256 const vec = (*this)->getFieldV256(sfHashes);
if (vec.size() > diff)
return vec[vec.size() - diff - 1];
return std::nullopt;
}
};
using LedgerHashesEntryR = LedgerHashesEntry<ReadView>;
+164 -60
View File
@@ -4,8 +4,8 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Rate.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h>
@@ -46,55 +46,30 @@ isGlobalFrozen(ReadView const& view, AccountID const& issuer);
[[nodiscard]] XRPAmount
xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j);
namespace detail {
struct Adjustment
{
std::int32_t ownerCountDelta = 0;
std::int32_t accountCountDelta = 0;
};
/**
* An owner count cannot be negative. If adjustment would cause a negative
* owner count, clamp the owner count at 0. Similarly for overflow. This
* adjustment allows the ownerCount to be adjusted up or down in multiple steps.
* If id != std::nullopt, then do error reporting.
* Returns the account reserve, in drops.
*
* Shared by AccountRootEntry::ownerCount() and the owner-count helpers.
* Actual owner count can be adjusted by delta in ownerCountAdj
* Actual reserve count can be adjusted by delta in accountCountAdj
* The reserve is calculated as:
* (ownerCount + "sponsoring object count" - "sponsored object count" + additionalOwnerCount) *
* increment + (1 if not sponsored account + sponsoringAccountCount) * "reserve base"
*
* @param currentOwnerCount The owner count before adjustment
* @param ownerCountAdj Positive to add to count, negative to reduce count
* @param id The account ID to use for error reporting, or std::nullopt to
* skip error reporting
* @param view The ledger view to read from
* @param sle The ledger entry for the account
* @param j Journal for logging
* @return The adjusted owner count
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative to
* subtract.
* @return The account reserve amount in drops
*/
std::uint32_t
confineOwnerCount(
std::uint32_t currentOwnerCount,
std::int32_t ownerCountAdj,
std::optional<AccountID> const& id = std::nullopt,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
/**
* Clamps and writes an owner-count field of sle, then updates sle in view.
*
* Shared by AccountRootEntry and adjustLoanBrokerOwnerCount().
*
* @return The adjusted owner count
*/
std::uint32_t
adjustOwnerCountImpl(
ApplyView& view,
SLE::Ref sle,
SF_UINT32 const& sfield,
AccountID const& accID,
std::int32_t ownerCountAdj,
beast::Journal j);
/**
* Returns the number of account reserves funded by this account: 1 for itself
* (0 if sponsored by another account) plus the count of accounts it sponsors.
* Shared by AccountRootEntry::reserve() and xrpLiquid().
*/
std::uint32_t
accountCountImpl(AccountRootEntryR const& sle, std::int32_t accountCountAdj, beast::Journal j);
} // namespace detail
[[nodiscard]] XRPAmount
accountReserve(ReadView const& view, SLE::ConstRef sle, beast::Journal j, Adjustment adj = {});
/**
* Convenience overload that accepts AccountID instead of SLE.
@@ -109,9 +84,114 @@ accountCountImpl(AccountRootEntryR const& sle, std::int32_t accountCountAdj, bea
[[nodiscard]] inline XRPAmount
accountReserve(ReadView const& view, AccountID const& id, beast::Journal j, Adjustment adj = {})
{
return AccountRootEntryR(id, view, j).reserve(adj);
return accountReserve(view, view.read(keylet::account(id)), j, adj);
}
/**
* Check if an account has sufficient reserve.
*
* @param view The ledger view to read from
* @param tx The transaction being processed
* @param accSle The account's ledger entry
* @param accBalance The account's balance
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative to
* subtract.
* @param j Journal for logging (default: null sink)
* @param insufReserveCode The transaction result code to return if the reserve is insufficient
* (default: tecINSUFFICIENT_RESERVE).
* @return Transaction result code
*/
[[nodiscard]] TER
checkReserve(
ApplyViewContext ctx,
SLE::ConstRef accSle,
XRPAmount accBalance,
SLE::ConstRef sponsorSle,
Adjustment adj,
beast::Journal j,
TER insufReserveCode = tecINSUFFICIENT_RESERVE);
/**
* Check if an account has sufficient reserve, deriving the sponsor internally.
*
* Equivalent to the overload above, but resolves the sponsor via
* getEffectiveTxReserveSponsor(ctx, accSle) instead of taking it explicitly. Use this
* in the common case where the sponsor is simply the transaction's reserve
* sponsor for accSle. Callers that must force the account's-own-reserve branch
* (passing a null sponsor) or supply a different sponsor should use the
* explicit overload above.
*
* @param ctx The apply-view context (view + tx)
* @param accSle The account's ledger entry
* @param accBalance The account's balance
* @param adj Reserve adjustments (owner/account count deltas)
* @param j Journal for logging (default: null sink)
* @return Transaction result code
*/
[[nodiscard]] TER
checkReserve(
ApplyViewContext ctx,
SLE::ConstRef accSle,
XRPAmount accBalance,
Adjustment adj,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
/**
* Return number of the objects which reserve is covered by the account(sle) (so called "owner
* count"). Actual owner count can be adjusted by delta in ownerCountAdj.
*
* @param sle The account's ledger entry
* @param j Journal for logging
* @param ownerCountAdj Adjustment to the owner count (default: 0)
* @return The adjusted owner count
*/
std::uint32_t
ownerCount(SLE::ConstRef sle, beast::Journal j, std::int32_t ownerCountAdj = 0);
/**
* Increase owner-count fields when the caller supplies the sponsor.
*
* This helper does not create a ledger object. It updates reserve accounting
* after the caller has created/updated an object.
* If sponsorSle is provided, this also adjusts the account's sponsored count
* and the sponsor's sponsoring count.
*
* @param view The apply view for making changes
* @param accountSle The account's ledger entry
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param count Amount to add to the owner count
* @param j Journal for logging
*/
void
increaseOwnerCount(
ApplyView& view,
SLE::Ref accountSle,
SLE::Ref sponsorSle,
std::uint32_t count,
beast::Journal j);
/**
* Increase owner-count fields, deriving the tx reserve sponsor internally.
*
* Equivalent to the overload above, but resolves the sponsor via
* getEffectiveTxReserveSponsor(ctx, accountSle) instead of taking it explicitly. Use
* this when the sponsor is the transaction's reserve sponsor for accountSle
* (the common create path). Deletion paths, which derive the sponsor from an
* object's sfSponsor field, should keep using the explicit overload.
*
* @param ctx The apply-view context (view + tx)
* @param accountSle The account's ledger entry
* @param count Amount to add to the owner count
* @param j Journal for logging
*/
void
increaseOwnerCount(
ApplyViewContext ctx,
SLE::Ref accountSle,
std::uint32_t count,
beast::Journal j);
/**
* Convenience overload that accepts AccountID instead of SLE references.
*
@@ -129,13 +209,36 @@ increaseOwnerCount(
std::uint32_t count,
beast::Journal j)
{
AccountRootEntryW accountSle(account, view, j);
std::optional<AccountRootEntryW> sponsorSle;
if (sponsor)
sponsorSle.emplace(*sponsor, view);
accountSle.increaseOwnerCount(sponsorSle, count);
increaseOwnerCount(
view,
view.peek(keylet::account(account)),
sponsor ? view.peek(keylet::account(*sponsor)) : SLE::pointer(),
count,
j);
}
/**
* Decrease owner-count fields when the caller supplies the sponsor.
*
* This helper does not delete a ledger object. It updates reserve accounting
* after the caller has removed an owner-counted reserve, or for special
* owner-count changes whose sponsor cannot be derived from an object's
* sfSponsor field.
*
* @param view The apply view for making changes
* @param accountSle The account's ledger entry
* @param sponsorSle The sponsor's ledger entry (if applicable)
* @param count Amount to remove from the owner count
* @param j Journal for logging
*/
void
decreaseOwnerCount(
ApplyView& view,
SLE::Ref accountSle,
SLE::Ref sponsorSle,
std::uint32_t count,
beast::Journal j);
/**
* Convenience overload that accepts AccountID instead of SLE references.
*
@@ -153,11 +256,12 @@ decreaseOwnerCount(
std::uint32_t count,
beast::Journal j)
{
AccountRootEntryW accountSle(account, view, j);
std::optional<AccountRootEntryW> sponsorSle;
if (sponsor)
sponsorSle.emplace(*sponsor, view);
accountSle.decreaseOwnerCount(sponsorSle, count);
decreaseOwnerCount(
view,
view.peek(keylet::account(account)),
sponsor ? view.peek(keylet::account(*sponsor)) : SLE::pointer(),
count,
j);
}
/**
@@ -177,7 +281,7 @@ decreaseOwnerCount(
void
decreaseOwnerCountForObject(
ApplyView& view,
AccountRootEntryW& accountSle,
SLE::Ref accountSle,
SLE::Ref objectSle,
std::uint32_t count,
beast::Journal j);
@@ -199,7 +303,7 @@ decreaseOwnerCountForObject(
std::uint32_t count,
beast::Journal j)
{
AccountRootEntryW accountSle(account, view);
SLE::Ref accountSle = view.peek(keylet::account(account));
decreaseOwnerCountForObject(view, accountSle, objectSle, count, j);
}
@@ -263,7 +367,7 @@ getPseudoAccountFields();
* - null pointer
*/
[[nodiscard]] bool
isPseudoAccount(AccountRootEntryR const& sleAcct);
isPseudoAccount(SLE::const_pointer sleAcct);
/**
* Convenience overload that reads the account from the view.
@@ -271,7 +375,7 @@ isPseudoAccount(AccountRootEntryR const& sleAcct);
[[nodiscard]] inline bool
isPseudoAccount(ReadView const& view, AccountID const& accountId)
{
return isPseudoAccount(AccountRootEntryR(accountId, view));
return isPseudoAccount(view.read(keylet::account(accountId)));
}
/**
@@ -292,6 +396,6 @@ createPseudoAccount(ApplyView& view, UInt256 const& pseudoOwnerKey, SField const
* - If the SLE requires a destination tag, checks that there is a tag.
*/
[[nodiscard]] TER
checkDestinationAndTag(AccountRootEntryR const& toSle, bool hasDestinationTag);
checkDestinationAndTag(SLE::ConstRef toSle, bool hasDestinationTag);
} // namespace xrpl
+314 -57
View File
@@ -2,9 +2,11 @@
#include <xrpl/basics/Log.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/entries/AccountRootEntry.h>
#include <xrpl/ledger/ReadView.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>
@@ -27,31 +29,290 @@
namespace xrpl {
namespace detail {
/**
* Before fixCleanup3_2_0, EscrowCancel passes the escrow SLE as sleDest.
* Return what the old reserve check returned for it, without adopting a
* non-AccountRoot SLE into an AccountRootEntry: the tx reserve sponsor's
* error if the escrow owner submitted the tx, else tefINTERNAL.
* Validate that @p account may lock @p amount of a token for later delivery
* to @p dest.
*
* @param ctx the apply view context for the escrow transaction.
* @param sleDest the non-AccountRoot SLE that was passed as the destination.
* @return the tx reserve sponsor's error code if the escrow owner submitted
* the tx, else tefINTERNAL.
* The lock-side counterpart of escrowUnlockPreclaimHelper: every issuer
* control (locking opt-in, authorization, freeze/lock, transferability,
* spendable balance) that gates locking token value lives here, so any
* transactor that locks funds applies the same rules. The signature is
* view-based rather than PreclaimContext-based so it can also run from
* doApply.
*/
template <ValidIssueType T>
TER
escrowLockPreclaimHelper(
ReadView const& view,
AccountID const& account,
AccountID const& dest,
STAmount const& amount,
beast::Journal j);
template <>
inline TER
escrowDestNotAccountResult(ApplyViewContext ctx, SLE::ConstRef sleDest)
escrowLockPreclaimHelper<Issue>(
ReadView const& view,
AccountID const& account,
AccountID const& dest,
STAmount const& amount,
beast::Journal j)
{
if (sleDest->getAccountID(sfAccount) == ctx.tx[sfAccount])
{
if (auto const sponsor = getTxReserveSponsor(ctx); !sponsor)
return sponsor.error(); // LCOV_EXCL_LINE
}
return tefINTERNAL;
auto const& issue = amount.get<Issue>();
auto const& issuer = amount.getIssuer();
// If the issuer is the same as the account, return tecNO_PERMISSION
if (issuer == account)
return tecNO_PERMISSION;
// If the lsfAllowTrustLineLocking is not enabled, return tecNO_PERMISSION
auto const sleIssuer = view.read(keylet::account(issuer));
if (!sleIssuer)
return tecNO_ISSUER;
if (!sleIssuer->isFlag(lsfAllowTrustLineLocking))
return tecNO_PERMISSION;
// If the account does not have a trustline to the issuer, return tecNO_LINE
auto const sleRippleState = view.read(keylet::trustLine(account, issuer, issue.currency));
if (!sleRippleState)
return tecNO_LINE;
STAmount const balance = (*sleRippleState)[sfBalance];
// If balance is positive, issuer must have higher address than account
if (balance > beast::kZero && issuer < account)
return tecNO_PERMISSION; // LCOV_EXCL_LINE
// If balance is negative, issuer must have lower address than account
if (balance < beast::kZero && issuer > account)
return tecNO_PERMISSION; // LCOV_EXCL_LINE
// If the issuer has requireAuth set, check if the account is authorized
if (auto const ter = requireAuth(view, issue, account); !isTesSuccess(ter))
return ter;
// If the issuer has requireAuth set, check if the destination is authorized
if (auto const ter = requireAuth(view, issue, dest); !isTesSuccess(ter))
return ter;
// If the issuer has frozen the account, return tecFROZEN
if (isFrozen(view, account, issue))
return tecFROZEN;
// If the issuer has frozen the destination, return tecFROZEN
if (isFrozen(view, dest, issue))
return tecFROZEN;
STAmount const spendableAmount =
accountHolds(view, account, issue.currency, issuer, FreezeHandling::IgnoreFreeze, j);
// If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
if (spendableAmount <= beast::kZero)
return tecINSUFFICIENT_FUNDS;
// If the spendable amount is less than the amount, return
// tecINSUFFICIENT_FUNDS
if (spendableAmount < amount)
return tecINSUFFICIENT_FUNDS;
// If the amount is not addable to the balance, return tecPRECISION_LOSS
if (!canAdd(spendableAmount, amount))
return tecPRECISION_LOSS;
return tesSUCCESS;
}
} // namespace detail
template <>
inline TER
escrowLockPreclaimHelper<MPTIssue>(
ReadView const& view,
AccountID const& account,
AccountID const& dest,
STAmount const& amount,
beast::Journal j)
{
AccountID const issuer = amount.getIssuer();
// If the issuer is the same as the account, return tecNO_PERMISSION
if (issuer == account)
return tecNO_PERMISSION;
// If the mpt does not exist, return tecOBJECT_NOT_FOUND
auto const issuanceKey = keylet::mptokenIssuance(amount.get<MPTIssue>().getMptID());
auto const sleIssuance = view.read(issuanceKey);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
// If the lsfMPTCanEscrow is not enabled, return tecNO_PERMISSION
if (!sleIssuance->isFlag(lsfMPTCanEscrow))
return tecNO_PERMISSION;
// If the issuer is not the same as the issuer of the mpt, return
// tecNO_PERMISSION
if (sleIssuance->getAccountID(sfIssuer) != issuer)
return tecNO_PERMISSION; // LCOV_EXCL_LINE
// If the account does not have the mpt, return tecOBJECT_NOT_FOUND
if (!view.exists(keylet::mptoken(issuanceKey.key, account)))
return tecOBJECT_NOT_FOUND;
// If the issuer has requireAuth set, check if the account is
// authorized
auto const& mptIssue = amount.get<MPTIssue>();
if (auto const ter = requireAuth(view, mptIssue, account, AuthType::WeakAuth);
!isTesSuccess(ter))
return ter;
// If the issuer has requireAuth set, check if the destination is
// authorized
if (auto const ter = requireAuth(view, mptIssue, dest, AuthType::WeakAuth); !isTesSuccess(ter))
return ter;
// If the issuer has frozen the account, return tecLOCKED
if (isFrozen(view, account, *sleIssuance))
return tecLOCKED;
// If the issuer has frozen the destination, return tecLOCKED
if (isFrozen(view, dest, *sleIssuance))
return tecLOCKED;
// If the mpt cannot be transferred, return tecNO_AUTH
if (auto const ter = canTransfer(view, mptIssue, account, dest); !isTesSuccess(ter))
return ter;
STAmount const spendableAmount = accountHolds(
view,
account,
amount.get<MPTIssue>(),
FreezeHandling::IgnoreFreeze,
AuthHandling::IgnoreAuth,
j);
// If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
if (spendableAmount <= beast::kZero)
return tecINSUFFICIENT_FUNDS;
// If the spendable amount is less than the amount, return
// tecINSUFFICIENT_FUNDS
if (spendableAmount < amount)
return tecINSUFFICIENT_FUNDS;
return tesSUCCESS;
}
template <ValidIssueType T>
TER
escrowLockApplyHelper(
ApplyView& view,
AccountID const& issuer,
AccountID const& sender,
STAmount const& amount,
beast::Journal journal);
template <>
inline TER
escrowLockApplyHelper<Issue>(
ApplyView& view,
AccountID const& issuer,
AccountID const& sender,
STAmount const& amount,
beast::Journal journal)
{
// Defensive: Issuer cannot create an escrow
if (issuer == sender)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const ter =
directSendNoFee(view, sender, issuer, amount, !amount.holds<MPTIssue>(), journal);
if (!isTesSuccess(ter))
return ter; // LCOV_EXCL_LINE
return tesSUCCESS;
}
template <>
inline TER
escrowLockApplyHelper<MPTIssue>(
ApplyView& view,
AccountID const& issuer,
AccountID const& sender,
STAmount const& amount,
beast::Journal journal)
{
// Defensive: Issuer cannot create an escrow
if (issuer == sender)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const ter = lockEscrowMPT(view, sender, amount, journal);
if (!isTesSuccess(ter))
return ter; // LCOV_EXCL_LINE
return tesSUCCESS;
}
template <ValidIssueType T>
TER
escrowUnlockPreclaimHelper(
ReadView const& view,
AccountID const& account,
STAmount const& amount,
bool checkFreeze = true);
template <>
inline TER
escrowUnlockPreclaimHelper<Issue>(
ReadView const& view,
AccountID const& account,
STAmount const& amount,
bool checkFreeze)
{
AccountID const& issuer = amount.getIssuer();
// If the issuer is the same as the account, return tesSUCCESS
if (issuer == account)
return tesSUCCESS;
// If the issuer has requireAuth set, check if the destination is authorized
if (auto const ter = requireAuth(view, amount.get<Issue>(), account); !isTesSuccess(ter))
return ter;
// If the issuer has deep frozen the destination, return tecFROZEN
if (checkFreeze &&
isDeepFrozen(view, account, amount.get<Issue>().currency, amount.getIssuer()))
return tecFROZEN;
return tesSUCCESS;
}
template <>
inline TER
escrowUnlockPreclaimHelper<MPTIssue>(
ReadView const& view,
AccountID const& account,
STAmount const& amount,
bool checkFreeze)
{
AccountID const& issuer = amount.getIssuer();
// If the issuer is the same as the account, return tesSUCCESS
if (issuer == account)
return tesSUCCESS;
// If the mpt does not exist, return tecOBJECT_NOT_FOUND
auto const issuanceKey = keylet::mptokenIssuance(amount.get<MPTIssue>().getMptID());
auto const sleIssuance = view.read(issuanceKey);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
// If the issuer has requireAuth set, check if the account is
// authorized
auto const& mptIssue = amount.get<MPTIssue>();
if (auto const ter = requireAuth(view, mptIssue, account, AuthType::WeakAuth);
!isTesSuccess(ter))
return ter;
// If the issuer has frozen the account, return tecLOCKED
if (checkFreeze && isFrozen(view, account, *sleIssuance))
return tecLOCKED;
return tesSUCCESS;
}
//------------------------------------------------------------------------------
template <ValidIssueType T>
TER
@@ -81,9 +342,6 @@ escrowUnlockApplyHelper<Issue>(
bool createAsset,
beast::Journal journal)
{
auto const& issue = amount.get<Issue>();
Keylet const trustLineKey = keylet::trustLine(receiver, issue);
bool const recvLow = issuer > receiver;
bool const senderIssuer = issuer == sender;
bool const receiverIssuer = issuer == receiver;
@@ -93,20 +351,25 @@ escrowUnlockApplyHelper<Issue>(
if (receiverIssuer)
return tesSUCCESS;
auto const& issue = amount.get<Issue>();
Keylet const trustLineKey = keylet::trustLine(receiver, issue);
bool const recvLow = issuer > receiver;
if (!ctx.view.exists(trustLineKey) && createAsset)
{
// Can the account cover the trust line's reserve?
if (sleDest->getType() != ltACCOUNT_ROOT)
return detail::escrowDestNotAccountResult(ctx, sleDest);
auto const destSle = AccountRootEntryR(sleDest, ctx.view, journal);
auto sponsorSle = getEffectiveTxReserveSponsor(ctx, destSle);
auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, sleDest);
if (!sponsorSle)
return sponsorSle.error(); // LCOV_EXCL_LINE
auto& sponsor = *sponsorSle;
if (auto const ret = destSle.checkReserve(
ctx, xrpBalance, sponsor, {.ownerCountDelta = 1}, tecNO_LINE_INSUF_RESERVE);
if (auto const ret = checkReserve(
ctx,
sleDest,
xrpBalance,
*sponsorSle,
{.ownerCountDelta = 1},
journal,
tecNO_LINE_INSUF_RESERVE);
!isTesSuccess(ret))
{
JLOG(journal.trace()) << "Trust line does not exist. "
@@ -119,22 +382,22 @@ escrowUnlockApplyHelper<Issue>(
initialBalance.get<Issue>().account = noAccount();
if (TER const ter = trustCreate(
ctx.view, // payment sandbox
recvLow, // is dest low?
issuer, // source
receiver, // destination
trustLineKey.key, // ledger index
sleDest, // Account to add to
false, // authorize account
!sleDest->isFlag(lsfDefaultRipple), //
false, // freeze trust line
false, // deep freeze trust line
initialBalance, // zero initial balance
Issue(currency, receiver), // limit of zero
0, // quality in
0, // quality out
sponsor ? sponsor->mutableRawSle() : SLE::pointer(), // sponsor
journal); // journal
ctx.view, // payment sandbox
recvLow, // is dest low?
issuer, // source
receiver, // destination
trustLineKey.key, // ledger index
sleDest, // Account to add to
false, // authorize account
!sleDest->isFlag(lsfDefaultRipple), //
false, // freeze trust line
false, // deep freeze trust line
initialBalance, // zero initial balance
Issue(currency, receiver), // limit of zero
0, // quality in
0, // quality out
*sponsorSle, // sponsor
journal); // journal
!isTesSuccess(ter))
{
return ter; // LCOV_EXCL_LINE
@@ -229,29 +492,23 @@ escrowUnlockApplyHelper<MPTIssue>(
auto const mptKeylet = keylet::mptoken(issuanceKey.key, receiver);
if (!ctx.view.exists(mptKeylet) && createAsset && !receiverIssuer)
{
if (sleDest->getType() != ltACCOUNT_ROOT)
return detail::escrowDestNotAccountResult(ctx, sleDest);
auto const destSle = AccountRootEntryR(sleDest, ctx.view, journal);
auto sponsorSle = getEffectiveTxReserveSponsor(ctx, destSle);
auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, sleDest);
if (!sponsorSle)
return sponsorSle.error(); // LCOV_EXCL_LINE
auto& sponsor = *sponsorSle;
if (auto const ret = destSle.checkReserve(ctx, xrpBalance, sponsor, {.ownerCountDelta = 1});
if (auto const ret = checkReserve(
ctx, sleDest, xrpBalance, *sponsorSle, {.ownerCountDelta = 1}, journal);
!isTesSuccess(ret))
return ret;
if (auto const ter = createMPToken(
ctx.view, mptID, receiver, sponsor ? sponsor->mutableRawSle() : SLE::pointer(), 0);
if (auto const ter = createMPToken(ctx.view, mptID, receiver, *sponsorSle, 0);
!isTesSuccess(ter))
{
return ter; // LCOV_EXCL_LINE
}
// update owner count.
AccountRootEntryW receiverSle(receiver, ctx.view, journal);
receiverSle.increaseOwnerCount(sponsor, 1);
increaseOwnerCount(ctx.view, sleDest, *sponsorSle, 1, journal);
}
if (!ctx.view.exists(mptKeylet) && !receiverIssuer)
+11 -12
View File
@@ -2,7 +2,6 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h>
@@ -55,11 +54,11 @@ getTxReserveSponsorID(STTx const& tx);
* Return a mutable SLE for the transaction's reserve sponsor account.
*
* @param ctx The apply-view context (view + tx)
* @return The sponsor account entry, nullopt if the tx is not
* @return The sponsor account SLE, a null pointer if the tx is not
* reserve-sponsored, or tecINTERNAL if the sponsor account cannot
* be loaded (an already-checked invariant).
*/
std::expected<std::optional<AccountRootEntryW>, TER>
std::expected<SLE::pointer, TER>
getTxReserveSponsor(ApplyViewContext ctx);
/**
@@ -67,29 +66,29 @@ getTxReserveSponsor(ApplyViewContext ctx);
*
* @param view The ledger read view
* @param tx The transaction to inspect
* @return The sponsor account entry, nullopt if the tx is not
* @return The sponsor account SLE, a null pointer if the tx is not
* reserve-sponsored, or tecINTERNAL if the sponsor account cannot
* be loaded (an already-checked invariant).
*/
std::expected<std::optional<AccountRootEntryR>, TER>
std::expected<SLE::const_pointer, TER>
getTxReserveSponsor(ReadView const& view, STTx const& tx);
/**
* The transaction's reserve sponsor for the given account, if applicable.
*
* A reserve sponsor only covers the transaction submitter's own objects, so
* this returns the tx reserve sponsor entry only when accountSle is the tx's
* own (non-pseudo) account; otherwise it returns nullopt. This is
* this returns the tx reserve sponsor SLE only when accountSle is the tx's own
* (non-pseudo) account; otherwise it returns a null sponsor pointer. This is
* the single source of truth for the "sponsor applies to tx.Account only" rule
* that the sponsor-deriving helper overloads in AccountRootHelpers rely on.
*
* @param ctx The apply-view context (view + tx)
* @param accountSle The account whose sponsor is being resolved
* @return The sponsor entry (nullopt if unsponsored), or tecINTERNAL if the
* @return The sponsor SLE (nullptr if unsponsored), or tecINTERNAL if the
* sponsor account cannot be loaded (an already-checked invariant)
*/
[[nodiscard]] std::expected<std::optional<AccountRootEntryW>, TER>
getEffectiveTxReserveSponsor(ApplyViewContext ctx, AccountRootEntryR const& accountSle);
[[nodiscard]] std::expected<SLE::pointer, TER>
getEffectiveTxReserveSponsor(ApplyViewContext ctx, SLE::ConstRef accountSle);
/**
* Return the AccountID stored in the given sponsor field of a ledger entry, or nullopt if absent.
@@ -106,9 +105,9 @@ getLedgerEntryReserveSponsorID(SLE::ConstRef sle, SF_ACCOUNT const& field = sfSp
* @param view The mutable apply view
* @param sle The ledger entry whose sponsor field is inspected
* @param field The field that holds the sponsor AccountID (defaults to sfSponsor)
* @return The sponsor account entry, or nullopt if the entry is unsponsored.
* @return The sponsor account SLE, or a null pointer if the entry is unsponsored.
*/
std::optional<AccountRootEntryW>
SLE::pointer
getLedgerEntryReserveSponsor(
ApplyView& view,
SLE::ConstRef sle,
-28
View File
@@ -1,28 +0,0 @@
#pragma once
namespace xrpl {
/**
* @brief Enumeration of ledger shortcuts for specifying which ledger to use.
*
* These shortcuts provide a convenient way to reference commonly used ledgers
* without needing to specify their exact hash or sequence number.
*/
enum class LedgerShortcut {
/**
* The current working ledger (open, not yet closed)
*/
Current,
/**
* The most recently closed ledger (may not be validated)
*/
Closed,
/**
* The most recently validated ledger
*/
Validated
};
} // namespace xrpl
-16
View File
@@ -9,7 +9,6 @@
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/LedgerHeader.h>
#include <xrpl/protocol/LedgerShortcut.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/TxMeta.h>
#include <xrpl/protocol/TxSearched.h>
@@ -105,21 +104,6 @@ public:
using TxnMetaLedgerType = std::tuple<Blob, Blob, std::uint32_t>;
using MetaTxsList = std::vector<TxnMetaLedgerType>;
using LedgerSequence = uint32_t;
using LedgerHash = UInt256;
using LedgerSpecifier = std::variant<LedgerRange, LedgerShortcut, LedgerSequence, LedgerHash>;
struct AccountTxArgs
{
AccountID account;
std::optional<LedgerSpecifier> ledger;
bool binary = false;
bool forward = false;
uint32_t limit = 0;
std::optional<AccountTxMarker> marker;
std::optional<DelegateFilter> delegate;
};
struct AccountTxResult
{
std::variant<AccountTxs, MetaTxsList> transactions;
@@ -27,18 +27,6 @@
namespace xrpl {
/**
* Returns true if sleAcct is an AccountRoot carrying a pseudo-account field.
*
* isPseudoAccount() takes a view-bound AccountRootEntry, which is not
* available while visiting entries, so invariant checks use this instead.
*
* @param sleAcct the SLE to check.
* @return true if sleAcct is an AccountRoot carrying a pseudo-account field.
*/
[[nodiscard]] bool
isPseudoAccountSle(SLE::ConstRef sleAcct);
#if GENERATING_DOCS
/**
* @brief Prototype for invariant check implementations.
@@ -42,6 +42,14 @@ class ValidMPTIssuance
*/
bool referenceHoldingMutated_ = false;
/**
* Flags cleared on an existing MPTokenIssuance, except lsfMPTLocked,
* which tfMPTUnlock clears legitimately. Every other issuance flag is
* fixed at creation or set-once via MPTokenIssuanceSet, so any bit
* accumulated here is a bug. Enforced post-fixCleanup3_5_0.
*/
std::uint32_t issuanceFlagsCleared_ = 0;
/**
* MPTokens and RippleStates deleted during apply. finalize() checks each
* holder's AccountRoot to detect vault pseudo-account holdings deleted
+2 -3
View File
@@ -5,7 +5,6 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -26,7 +25,7 @@ checkFreeze(
XRPL_ASSERT(src != dst, "xrpl::checkFreeze : unequal input accounts");
// check freeze
if (auto sle = AccountRootEntryR(dst, view))
if (auto sle = view.read(keylet::account(dst)))
{
if (sle->isFlag(lsfGlobalFreeze))
{
@@ -50,7 +49,7 @@ checkFreeze(
if (view.rules().enabled(fixFrozenLPTokenTransfer))
{
if (auto const sleDst = AccountRootEntryR(dst, view);
if (auto const sleDst = view.read(keylet::account(dst));
sleDst && sleDst->isFieldPresent(sfAMMID))
{
auto const sleAmm = view.read(keylet::amm((*sleDst)[sfAMMID]));
@@ -2,7 +2,6 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/STLedgerEntry.h>
@@ -13,7 +12,6 @@
#include <xrpl/tx/Transactor.h>
#include <cstdint>
#include <optional>
namespace xrpl {
@@ -58,8 +56,8 @@ private:
Keylet const& sponsorshipKeylet,
AccountID const& sponsorID,
AccountID const& sponseeID,
AccountRootEntryW& sponsorAccSle,
std::optional<AccountRootEntryW>& reserveSponsorAccSle);
SLE::Ref sponsorAccSle,
SLE::Ref reserveSponsorAccSle);
};
} // namespace xrpl
@@ -57,6 +57,12 @@ public:
ReadView const& view,
beast::Journal const& j) override;
/**
* Inner transaction types that preflight rejects before LendingProtocolV1_2.
*
* Once the amendment is enabled the list only matters when replaying older
* ledgers. Remove it when LendingProtocolV1_2 is retired.
*/
static constexpr auto kDisabledTxTypes = std::to_array<TxType>({
ttVAULT_CREATE,
ttVAULT_SET,
+83 -80
View File
@@ -2,145 +2,148 @@ Detected OS: macos (Darwin arm64)
Core build tools:
✅ cmake
cmake version 4.1.2
/nix/store/gvabsb4yqb5xsqzqph54rijnn4zpihnp-cmake-4.1.2/bin/cmake
cmake version 4.4.3
/nix/store/q85csxf4s4shx89zif097h1ql4ax1rrz-cmake-4.4.3/bin/cmake
✅ conan
Conan version 2.28.1
/nix/store/9jiyxmkpwmn6dcqs0765s83riw3l5ail-conan-2.28.1/bin/conan
Conan version 2.33.0
/nix/store/rp0zf22rx3iwnhxp4d53ncirn4lzg68j-conan-2.33.0/bin/conan
✅ git
git version 2.54.0
/nix/store/a14yxcqvv9x2l9mllgpirzhvz93pgprg-git-2.54.0/bin/git
git version 2.55.0
/nix/store/gw7c7m0dwca5lg4152x9lpmxpj171bzw-git-2.55.0/bin/git
✅ python3
Python 3.13.13
/nix/store/ygxqin6ydzjfawywqpp5pal8wv6sf5bh-python3-3.13.13/bin/python3.13
Python 3.14.7
/nix/store/0kcws5blwbdyxqxjd1w8hjipz61xny3k-python3-3.14.7/bin/python3.14
Development tooling:
✅ ccache
ccache version 4.13.6
/nix/store/57davyvs6p6dkrl3svzwg1ph18wsy4cz-ccache-4.13.6/bin/ccache
/nix/store/ydr5nlzxp1djb5256y0zzqa87vz55gsk-ccache-4.13.6/bin/ccache
✅ clang
clang version 22.1.7
/nix/store/192glrb2cldvziyf3378mzjqbzx3ih4g-clang-wrapper-22.1.7/bin/clang
✅ clang-22
clang version 22.1.7
/nix/store/rbap7zqq7mw00fyqa02p5rj7gqjp4w5i-clang-22/bin/clang-22
clang version 23.1.0
/nix/store/2c16z6akvv65znb8330sl5qpklaf3194-clang-wrapper-23.1.0/bin/clang
✅ clang-23
clang version 23.1.0
/nix/store/vfd0q2395vyn0bsjsh1b4068icy1x9ph-clang-23/bin/clang-23
✅ clang++
clang version 22.1.7
/nix/store/192glrb2cldvziyf3378mzjqbzx3ih4g-clang-wrapper-22.1.7/bin/clang++
✅ clang++-22
clang version 22.1.7
/nix/store/v9haf787f7bcz0mq1sad4bpyx21pj6li-clang++-22/bin/clang++-22
clang version 23.1.0
/nix/store/2c16z6akvv65znb8330sl5qpklaf3194-clang-wrapper-23.1.0/bin/clang++
✅ clang++-23
clang version 23.1.0
/nix/store/0i6kfnif2v4sqyv5fzfg8a9n09rw9lkp-clang++-23/bin/clang++-23
✅ ClangBuildAnalyzer
ClangBuildAnalyzer 1.6.0
/nix/store/4l50ds9fa2mkvh7wg8qzrlbmjs12sb8l-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
/nix/store/c7jjnw29ra78jdlzjww2m374izhy05n8-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
✅ curl
curl 8.20.0 (aarch64-apple-darwin25.3.0) libcurl/8.20.0 OpenSSL/3.6.2 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.69.0 mit-krb5/1.22.1
/nix/store/kclq0czaxvsgh4ym9ld7b6iwy50l1snk-curl-8.20.0-bin/bin/curl
curl 8.22.0 (aarch64-apple-darwin25.6.0) libcurl/8.22.0 OpenSSL/3.5.8 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.70.0 mit-krb5/1.22.2
/nix/store/pq1h17abqy6q5y6k5dn9qj0fwb89flba-curl-8.22.0-bin/bin/curl
✅ file
file-5.47
/nix/store/dax63li7wwcbqxxkkgzc4g2rx7d4w86x-file-5.47/bin/file
file-5.48
/nix/store/y44vpziwbzfm8020dzlqqbybyyy7lb6g-file-5.48/bin/file
✅ jq
jq-1.8.2
/nix/store/wm7v59a2lhj1w2k8jz53spcs1iizm9lv-jq-1.8.2-bin/bin/jq
✅ less
less 692 (PCRE2 regular expressions)
/nix/store/lvr16y75r1pdxpdv0aph5ak2yd0hkvqm-less-692/bin/less
less 710 (PCRE2 regular expressions)
/nix/store/3yn3dx5fwg5i0inqqzwnxq7f6lwhpjqa-less-710/bin/less
✅ make
GNU Make 4.4.1
/nix/store/8wwiw8pwyhrkzyq28hqzxfl4z84lks81-gnumake-4.4.1/bin/make
/nix/store/8l4wgxmhdxfvc9g18y76bnxl1ghgcp7n-gnumake-4.4.1/bin/make
✅ netstat
present
/nix/store/qsd1kzqb0ahrk433vmyl245gp623j19s-network_cmds-730.80.3/bin/netstat
/nix/store/57fqvgdav8lrmzndkwm7qrgksl01yj23-network_cmds-741.100.2/bin/netstat
✅ ninja
1.13.2
/nix/store/bqykhrblarkj4fl0hz2mf8ngwfv6x6bz-ninja-1.13.2/bin/ninja
/nix/store/infm4vlx71q83bqz0k559w1gn4b0rq4i-ninja-1.13.2/bin/ninja
✅ perl
v5.42.0
/nix/store/js13ri9fvm0ajk1fpd3acigys2a9whdv-perl-5.42.0/bin/perl
v5.42.3
/nix/store/7rvr6qjfzk2ybzn1imjw6c6qq1n1a9cr-perl-5.42.3/bin/perl
✅ pkg-config
0.29.2
/nix/store/lzrwr375jqhhbca116kja96xf1md83l8-pkg-config-wrapper-0.29.2/bin/pkg-config
/nix/store/nhgylvj98klqggy54h7gbc3b2ia4a00y-pkg-config-wrapper-0.29.2/bin/pkg-config
✅ vim
VIM - Vi IMproved 9.2 (2026 Feb 14, compiled Jan 01 1980 00:00:00)
/nix/store/6vbkykg92w603c0sw3mkk7p7mfaawbns-vim-9.2.0389/bin/vim
/nix/store/akaa9kqm3b8rlkv61kvsqr2l2j70rvxb-vim-9.2.1001/bin/vim
✅ zip
Zip 3.0
/nix/store/z6ph729vcakbvz3wh8ln1wk6mi06w487-zip-3.0/bin/zip
/nix/store/dvawr36npnad4xa6dxi2ss0fw44aa82r-zip-3.0/bin/zip
✅ clang-apply-replacements
clang-apply-replacements version 22.1.7
/nix/store/vzyyjf3cm1hbj9wcr2qcb66x6j98zpy7-clang-tools-22.1.7/bin/clang-apply-replacements
✅ clang-apply-replacements-22
clang-apply-replacements version 22.1.7
/nix/store/m3ii69rca4077lf4wlk7m3jcag1fs577-clang-apply-replacements-22/bin/clang-apply-replacements-22
clang-apply-replacements version 23.1.0
/nix/store/mva6ngy45m9in3m2lsfccj1y0z6n1f5s-clang-tools-23.1.0/bin/clang-apply-replacements
✅ clang-apply-replacements-23
clang-apply-replacements version 23.1.0
/nix/store/872k02mqr21hxwcpfwaqkxljfj60aak0-clang-apply-replacements-23/bin/clang-apply-replacements-23
✅ clang-format
clang-format version 22.1.7
/nix/store/vzyyjf3cm1hbj9wcr2qcb66x6j98zpy7-clang-tools-22.1.7/bin/clang-format
✅ clang-format-22
clang-format version 22.1.7
/nix/store/4fawqy6ngqcsqd2ygyyzm93q0xy3f5gs-clang-format-22/bin/clang-format-22
clang-format version 23.1.0
/nix/store/mva6ngy45m9in3m2lsfccj1y0z6n1f5s-clang-tools-23.1.0/bin/clang-format
✅ clang-format-23
clang-format version 23.1.0
/nix/store/wf30x6lcya44n2y1fagd6q7x7p4gyl6f-clang-format-23/bin/clang-format-23
✅ clang-tidy
LLVM version 22.1.7
/nix/store/vzyyjf3cm1hbj9wcr2qcb66x6j98zpy7-clang-tools-22.1.7/bin/clang-tidy
✅ clang-tidy-22
LLVM version 22.1.7
/nix/store/jqw4280saixaxxihwdba9ldm2fsm6dr3-clang-tidy-22/bin/clang-tidy-22
LLVM version 23.1.0
/nix/store/mva6ngy45m9in3m2lsfccj1y0z6n1f5s-clang-tools-23.1.0/bin/clang-tidy
✅ clang-tidy-23
LLVM version 23.1.0
/nix/store/kgx00aass66g02p1s4gqqf65kq39m4ci-clang-tidy-23/bin/clang-tidy-23
✅ dot
dot - graphviz version 12.2.1 (0)
/nix/store/ijb4fbnqa6wzlpqnhb6q9knqpf7qqn5z-graphviz-12.2.1/bin/dot
dot - graphviz version 15.1.1 (0)
/nix/store/mc99a6bpbk2waym2cnw6ifmxli4ndb4x-graphviz-15.1.1/bin/dot
✅ doxygen
1.16.1
/nix/store/kbryjdpq9jizjb0ws0nzbf2h2ymbdiwm-doxygen-1.16.1/bin/doxygen
1.17.0
/nix/store/kz43yaj0wg6fx6cbrcmi2442z1ramy0c-doxygen-1.17.0/bin/doxygen
✅ gcovr
gcovr 8.4
/nix/store/wn8jiyh9p0bybs96s4163qp3k8vfmczx-python3.13-gcovr-8.4/bin/gcovr
/nix/store/czj1vxsizrbba280gg22cys40qxkqjgr-python3.14-gcovr-8.4/bin/gcovr
✅ gh
gh version 2.94.0 (nixpkgs)
/nix/store/fhnpw0hs0gjms1ha6ap02jq7rx13gkbp-gh-2.94.0/bin/gh
gh version 2.102.0 (2026-09-30)
/nix/store/s8bahl6zssvry93ihivfmk1l6c58byrr-gh-2.102.0/bin/gh
✅ git-cliff
git-cliff 2.13.1
/nix/store/cy0wwhgxa7yvrz97zydbq6sqmixc90fq-git-cliff-2.13.1/bin/git-cliff
git-cliff 2.14.2
/nix/store/k4m5yk0qb7hfslwsq1zjajz1d94j12bj-git-cliff-2.14.2/bin/git-cliff
✅ git-lfs
git-lfs/3.7.1 (3.7.1; darwin arm64; go 1.26.3)
/nix/store/k9r7zjfjplqa4d5s71cqvf2iv73jd9mc-git-lfs-3.7.1/bin/git-lfs
git-lfs/3.8.0 (3.8.0; darwin arm64; go 1.26.8)
/nix/store/wzixjr3yb40a13m2q654hm3bdjn6sal3-git-lfs-3.8.0/bin/git-lfs
✅ gpg
gpg (GnuPG) 2.4.9
/nix/store/cgh6iwzz5jgx9z5whka4vgj210i6npc6-gnupg-2.4.9/bin/gpg
/nix/store/0ldfwnwx385i5kh7cyvxx4mkvgjhs5rh-gnupg-2.4.9/bin/gpg
✅ pre-commit
pre-commit 4.5.1
/nix/store/z3cca68620w0w10f090szgzdnmh1waf2-pre-commit-4.5.1/bin/pre-commit
pre-commit 4.6.2
/nix/store/ivh54xypg9qvd3ha9lis0i8p4nkf8n7a-pre-commit-4.6.2/bin/pre-commit
✅ run-clang-tidy
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
/nix/store/4x28x911z2f9y7adqlh3qspp4a16dig7-run-clang-tidy/bin/run-clang-tidy
✅ run-clang-tidy-22
/nix/store/zjbzr154xan5xg9pmjiv0zkwklyb94wv-run-clang-tidy/bin/run-clang-tidy
✅ run-clang-tidy-23
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
/nix/store/x8iymrh76sk5q91ryg5pa7i32s6gfh34-run-clang-tidy-22/bin/run-clang-tidy-22
/nix/store/svhfrpgx2j581brsqmkpav9b286v22yy-run-clang-tidy-23/bin/run-clang-tidy-23
Rust toolchain:
✅ cargo
cargo 1.97.1 (c980f4866 2026-06-30)
/nix/store/bnfk1sl4s9angb0vj1cj9a5y5zvqinwy-rust-minimal-1.97.1/bin/cargo
/nix/store/gklji8yq8yrx1k039c10kwz60vqf2dxj-rust-minimal-1.97.1/bin/cargo
✅ cargo-audit
cargo-audit-audit 0.22.1
/nix/store/snwkga2f5gyf404h7mmp9wriwxb8v65f-cargo-audit-0.22.1/bin/cargo-audit
cargo-audit-audit 0.22.2
/nix/store/7jgrwj557l91940aj0ag4i924ima1cqn-cargo-audit-0.22.2/bin/cargo-audit
✅ cargo-llvm-cov
cargo-llvm-cov 0.8.5
/nix/store/fpiqdh91gwyxalqp409ynm0s0g086w7w-cargo-llvm-cov-0.8.5/bin/cargo-llvm-cov
cargo-llvm-cov 0.9.0
/nix/store/5q1h285z8zzkw2qxig9a0b1avcsk1cf0-cargo-llvm-cov-0.9.0/bin/cargo-llvm-cov
✅ cargo-nextest
cargo-nextest 0.9.137
/nix/store/ylz7m947mhkgsp6i7611id3s3gcd58nq-cargo-nextest-0.9.137/bin/cargo-nextest
cargo-nextest 0.9.146
/nix/store/69v3hx3k597hcxd2zy7yad7fg0aw5yxd-cargo-nextest-0.9.146/bin/cargo-nextest
✅ clippy-driver
clippy 0.1.97 (8bab26f4f6 2026-07-14)
/nix/store/bnfk1sl4s9angb0vj1cj9a5y5zvqinwy-rust-minimal-1.97.1/bin/clippy-driver
/nix/store/gklji8yq8yrx1k039c10kwz60vqf2dxj-rust-minimal-1.97.1/bin/clippy-driver
✅ rust-analyzer
rust-analyzer 1.97.1 (8bab26f4 2026-07-14)
/nix/store/j6apc5pmd0giy15da9p650r8zklslmvi-rust-analyzer-preview-1.97.1-aarch64-apple-darwin/bin/rust-analyzer
/nix/store/30rbyk8gx7v53fxqhs4pp0fvxfjycspr-rust-analyzer-preview-1.97.1-aarch64-apple-darwin/bin/rust-analyzer
✅ rust-nightly
rustc 1.99.0-nightly (87e5904f5 2026-07-20)
/nix/store/fqpjz4l0nsnji8b2pz57mnj0akbp6hcl-rust-nightly/bin/rust-nightly
rustc 1.101.0-nightly (282215592 2026-10-04)
/nix/store/a9552rf3pylcnkijc1z0hf1lcnv50djq-rust-nightly/bin/rust-nightly
✅ rustc
rustc 1.97.1 (8bab26f4f 2026-07-14)
/nix/store/bnfk1sl4s9angb0vj1cj9a5y5zvqinwy-rust-minimal-1.97.1/bin/rustc
/nix/store/gklji8yq8yrx1k039c10kwz60vqf2dxj-rust-minimal-1.97.1/bin/rustc
✅ rustfmt
rustfmt 1.9.0-stable (8bab26f4f6 2026-07-14)
/nix/store/5ymwgr9jqjz7zzbmj0j5vqbwcd3kp0vm-rustfmt-preview-1.97.1-aarch64-apple-darwin/bin/rustfmt
/nix/store/0jmdipyn8266j9kqx2xxm2qkxlrlrjfc-rustfmt-preview-1.97.1-aarch64-apple-darwin/bin/rustfmt
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
✅ All 45 checked tools are present and runnable.
✅ All 46 checked tools are present and runnable.
+99 -96
View File
@@ -2,173 +2,176 @@ Detected OS: linux (Linux x86_64)
Core build tools:
✅ cmake
cmake version 4.1.2
/nix/store/r9941n32g4wyvggz2703dlplbdq8a6rd-cmake-4.1.2/bin/cmake
cmake version 4.4.3
/nix/store/jcvvpih1046akxcwh9hdiak5q24jqcf0-cmake-4.4.3/bin/cmake
✅ conan
Conan version 2.28.1
/nix/store/lxny9y4jvjdws7hgz1mygvb7hjrpmna5-conan-2.28.1/bin/conan
Conan version 2.33.0
/nix/store/b4lnzrqc60glhl9al1nakfc0vd20kdna-conan-2.33.0/bin/conan
✅ git
git version 2.54.0
/nix/store/bcnisk3ydfgv26v2gw3zlky24g00yww2-git-2.54.0/bin/git
git version 2.55.0
/nix/store/lg46w7hrjx7kylsh6645c9l975i8h43b-git-2.55.0/bin/git
✅ python3
Python 3.13.13
/nix/store/60m4rxhg2fldqaak400c0lry96ijrzqn-python3-3.13.13/bin/python3.13
Python 3.14.7
/nix/store/lb41b0anx1f98y9y5s9mdv97gjgsq740-python3-3.14.7/bin/python3.14
Development tooling:
✅ ccache
ccache version 4.13.6
/nix/store/c9wwl7s5i6rsfwvf4v0xbbmzx5m6jgfr-ccache-4.13.6/bin/ccache
/nix/store/p1a1s700dqsw1b3b8d2ba64nqw68zgpy-ccache-4.13.6/bin/ccache
✅ clang
clang version 22.1.7
/nix/store/ff0hrp9r9i3pa5arkdw0sgmzp8d576qi-clang-wrapper-22.1.7/bin/clang
✅ clang-22
clang version 22.1.7
/nix/store/dagc2rq44gfbr7w7yvvqca3yqpc9gqbq-clang-22/bin/clang-22
clang version 23.1.0
/nix/store/mlqh1xrp0zi3i5g9b0zjcz6zlbbzdgb8-clang-wrapper-23.1.0/bin/clang
✅ clang-23
clang version 23.1.0
/nix/store/xgi7q1bady9dk89zvjmiicjzzp1gvm7x-clang-23/bin/clang-23
✅ clang++
clang version 22.1.7
/nix/store/ff0hrp9r9i3pa5arkdw0sgmzp8d576qi-clang-wrapper-22.1.7/bin/clang++
✅ clang++-22
clang version 22.1.7
/nix/store/l5m8clin1npl605wdkd8mr18ggxww3z4-clang++-22/bin/clang++-22
clang version 23.1.0
/nix/store/mlqh1xrp0zi3i5g9b0zjcz6zlbbzdgb8-clang-wrapper-23.1.0/bin/clang++
✅ clang++-23
clang version 23.1.0
/nix/store/4slsaz29v72xgc4g36cp94f0p41a81pv-clang++-23/bin/clang++-23
✅ ClangBuildAnalyzer
ClangBuildAnalyzer 1.6.0
/nix/store/bshlmn8fqw55nsnm581xqlfbahfkykxx-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
/nix/store/gvx8im1c89vspwb8ixa91lr1dagbi241-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
✅ curl
curl 8.20.0 (x86_64-pc-linux-gnu) libcurl/8.20.0 OpenSSL/3.6.2 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.69.0 mit-krb5/1.22.1
/nix/store/zbwymrp4lcfjc4kkk0n4779v0kjjz58z-curl-8.20.0-bin/bin/curl
curl 8.22.0 (x86_64-pc-linux-gnu) libcurl/8.22.0 OpenSSL/3.5.8 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.70.0 mit-krb5/1.22.2
/nix/store/305w9ipyg497mz9dq31abdf61qk58k29-curl-8.22.0-bin/bin/curl
✅ file
file-5.47
/nix/store/bizyfqdw0h67wzqmp10knmf9s2pqahdb-file-5.47/bin/file
file-5.48
/nix/store/g0fbnccaan8q0rxlw43xnbyb90i94vlc-file-5.48/bin/file
✅ jq
jq-1.8.2
/nix/store/m3y7hqmy20nd1ps6qy8410a326255bf0-jq-1.8.2-bin/bin/jq
✅ less
less 692 (PCRE2 regular expressions)
/nix/store/c6bacbn93qg4a7g9n4czww8rg24dvysr-less-692/bin/less
less 710 (PCRE2 regular expressions)
/nix/store/zi4d0awnc6crz18s177bv9y2yz9al3lq-less-710/bin/less
✅ make
GNU Make 4.4.1
/nix/store/d3bwqm6bymhy3pdgbvf7vxjqfp31m3j1-gnumake-4.4.1/bin/make
/nix/store/z565rgmn9vccv2h0g87z725pw610jmm8-gnumake-4.4.1/bin/make
✅ netstat
net-tools 2.10
/nix/store/jmyzqvgflnswmws7rnxx6g3zbj680xvd-net-tools-2.10/bin/netstat
/nix/store/9i6j9lrsliyz1ww2f8xx18z36wc9n38a-net-tools-2.10/bin/netstat
✅ ninja
1.13.2
/nix/store/7a235m7crqbb4h49sak20fqxpw3n7hr0-ninja-1.13.2/bin/ninja
/nix/store/4nsdla28c4177ssp0hlyv5l2yzj8wcba-ninja-1.13.2/bin/ninja
✅ perl
v5.42.0
/nix/store/6plwsm6pkq79yjv4xvy8csk2pd4hzr67-perl-5.42.0/bin/perl
v5.42.3
/nix/store/8g4dmf7l8q1mf9w4wfmlcl8gvdgmhb8v-perl-5.42.3/bin/perl
✅ pkg-config
0.29.2
/nix/store/1m05k7xgfnw6jc21xxk5681ni3ar97wf-pkg-config-wrapper-0.29.2/bin/pkg-config
/nix/store/b9izmrfjp0qnnyahdwwrzdwi87s1h179-pkg-config-wrapper-0.29.2/bin/pkg-config
✅ vim
VIM - Vi IMproved 9.2 (2026 Feb 14, compiled Jan 01 1980 00:00:00)
/nix/store/hvyqx52g4g2fxhgpans3fksjj6lmlyaw-vim-9.2.0389/bin/vim
/nix/store/9swnd5pf8p8w1gwcbhdpm2yx705kbp38-vim-9.2.1001/bin/vim
✅ zip
Zip 3.0
/nix/store/qnd2ag67hrjj0b6vbmisdshf50r6s72n-zip-3.0/bin/zip
/nix/store/5ypvkry3qra47dylc9kfk36r1q9vha80-zip-3.0/bin/zip
✅ clang-apply-replacements
clang-apply-replacements version 22.1.7
/nix/store/4zp1rjpj2xijrv4kqpwsy3ixwb2r6nlk-clang-tools-22.1.7/bin/clang-apply-replacements
✅ clang-apply-replacements-22
clang-apply-replacements version 22.1.7
/nix/store/py2wihg0a96qcppv4hjmww547xabr0fb-clang-apply-replacements-22/bin/clang-apply-replacements-22
clang-apply-replacements version 23.1.0
/nix/store/ipnj8b3s6f00ngi26fi7p5h9lxv6a3s3-clang-tools-23.1.0/bin/clang-apply-replacements
✅ clang-apply-replacements-23
clang-apply-replacements version 23.1.0
/nix/store/lbyc9hrkkymybah7b6n8c7sijlgldfz0-clang-apply-replacements-23/bin/clang-apply-replacements-23
✅ clang-format
clang-format version 22.1.7
/nix/store/4zp1rjpj2xijrv4kqpwsy3ixwb2r6nlk-clang-tools-22.1.7/bin/clang-format
✅ clang-format-22
clang-format version 22.1.7
/nix/store/kz820ccifjlwqnwqjsx7kbiajrgsmbrh-clang-format-22/bin/clang-format-22
clang-format version 23.1.0
/nix/store/ipnj8b3s6f00ngi26fi7p5h9lxv6a3s3-clang-tools-23.1.0/bin/clang-format
✅ clang-format-23
clang-format version 23.1.0
/nix/store/40w351b7i7aqhpl5wmicfnp2ij8k12g9-clang-format-23/bin/clang-format-23
✅ clang-tidy
LLVM version 22.1.7
/nix/store/4zp1rjpj2xijrv4kqpwsy3ixwb2r6nlk-clang-tools-22.1.7/bin/clang-tidy
✅ clang-tidy-22
LLVM version 22.1.7
/nix/store/gdrkvpw846lkyzh8y9p3zx50g6ml2v84-clang-tidy-22/bin/clang-tidy-22
LLVM version 23.1.0
/nix/store/ipnj8b3s6f00ngi26fi7p5h9lxv6a3s3-clang-tools-23.1.0/bin/clang-tidy
✅ clang-tidy-23
LLVM version 23.1.0
/nix/store/40rj38k5ygq7sawkiv0cdaljclbspwz9-clang-tidy-23/bin/clang-tidy-23
✅ dot
dot - graphviz version 12.2.1 (0)
/nix/store/12rgns2296s4qcja778gvcbx61z77rc4-graphviz-12.2.1/bin/dot
dot - graphviz version 15.1.1 (0)
/nix/store/f7r47nc0d13xa4c2xaaxa6dp3pzm9sp1-graphviz-15.1.1/bin/dot
✅ doxygen
1.16.1
/nix/store/k0vzr5lvgq1byraknzwvk51wcgpnsrkh-doxygen-1.16.1/bin/doxygen
1.17.0
/nix/store/q6yx2nsimj9xmckmgw4br2cnapbgnqpk-doxygen-1.17.0/bin/doxygen
✅ gcovr
gcovr 8.4
/nix/store/iyzi7fpyclqrha054adnizvif02lg49x-python3.13-gcovr-8.4/bin/gcovr
/nix/store/shx7mfl8n4kx11icvwyj5x7cmf6z5ahq-python3.14-gcovr-8.4/bin/gcovr
✅ gh
gh version 2.94.0 (nixpkgs)
/nix/store/pidh15szlsb1vc41xdsa3xbdghdazvby-gh-2.94.0/bin/gh
gh version 2.102.0 (2026-09-30)
/nix/store/66h5dr9v94x04myh2kabx06rq9763jfc-gh-2.102.0/bin/gh
✅ git-cliff
git-cliff 2.13.1
/nix/store/1q851fs62shgjhc03fxxdkpzxdjg7k11-git-cliff-2.13.1/bin/git-cliff
git-cliff 2.14.2
/nix/store/sl19b42d69b3w2vb9pxp6jbqk841z8vj-git-cliff-2.14.2/bin/git-cliff
✅ git-lfs
git-lfs/3.7.1 (3.7.1; linux amd64; go 1.26.3)
/nix/store/6ljwpal7b1756708m33vj0crpral7mvl-git-lfs-3.7.1/bin/git-lfs
git-lfs/3.8.0 (3.8.0; linux amd64; go 1.26.8)
/nix/store/rp9ld1f6h83xmf2rb5fpib5wmr46fy9f-git-lfs-3.8.0/bin/git-lfs
✅ gpg
gpg (GnuPG) 2.4.9
/nix/store/wx7vk8babxkgy813r70yc67vcwnmagbx-gnupg-2.4.9/bin/gpg
/nix/store/8gm9aq3sspqmvvh7c0x7djcivj2x7yvn-gnupg-2.4.9/bin/gpg
✅ pre-commit
pre-commit 4.5.1
/nix/store/bj6i9vl34cij5h0r165y40hrjqak0bmz-pre-commit-4.5.1/bin/pre-commit
pre-commit 4.6.2
/nix/store/6blf72f7sdmlrqjggxvk5ij4cxb7fk4c-pre-commit-4.6.2/bin/pre-commit
✅ run-clang-tidy
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
/nix/store/sbg911hs9dbclrzlp04br3iyfpgnaj6r-run-clang-tidy/bin/run-clang-tidy
✅ run-clang-tidy-22
/nix/store/y7isn3dr8bildnp78vk5nhcav63g80dz-run-clang-tidy/bin/run-clang-tidy
✅ run-clang-tidy-23
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
/nix/store/n8yak1ap308gvi7gmrniw0ybsx80fjws-run-clang-tidy-22/bin/run-clang-tidy-22
/nix/store/pm5a8465hs9zb5i116b39i0y3xfpw6n3-run-clang-tidy-23/bin/run-clang-tidy-23
Rust toolchain:
✅ cargo
cargo 1.97.1 (c980f4866 2026-06-30)
/nix/store/88abzp43ywyzql1rhf8jh5aj5n5j7xzr-cargo-1.97.1-x86_64-unknown-linux-gnu/bin/cargo
/nix/store/60b0cz400q34wj2gzav5a41i7y6jzlw3-cargo-1.97.1-x86_64-unknown-linux-gnu/bin/cargo
✅ cargo-audit
cargo-audit-audit 0.22.1
/nix/store/2w9if868piw98xz057sz97jnjvf7hnvf-cargo-audit-0.22.1/bin/cargo-audit
cargo-audit-audit 0.22.2
/nix/store/kksgynfwir3pfii9qkbj3gcc61an0d4s-cargo-audit-0.22.2/bin/cargo-audit
✅ cargo-llvm-cov
cargo-llvm-cov 0.8.5
/nix/store/jjpdf1l6izz6607a346ykra9sndzaw7h-cargo-llvm-cov-0.8.5/bin/cargo-llvm-cov
cargo-llvm-cov 0.9.0
/nix/store/4y8qxx0mlm22hnxlw2cmbcwpxispw02h-cargo-llvm-cov-0.9.0/bin/cargo-llvm-cov
✅ cargo-nextest
cargo-nextest 0.9.137
/nix/store/jhkr7gwyrchkml33gyns9cy0yn7b57qc-cargo-nextest-0.9.137/bin/cargo-nextest
cargo-nextest 0.9.146
/nix/store/q0anzqrazmdr8n1049ca28098q6lv2y8-cargo-nextest-0.9.146/bin/cargo-nextest
✅ clippy-driver
clippy 0.1.97 (8bab26f4f6 2026-07-14)
/nix/store/40d3mzka7r1ps71l0yv2fs6616nbw85m-rust-minimal-1.97.1/bin/clippy-driver
/nix/store/kk0kqdc4f7am21yp30rr8jcrnib5xqzy-rust-minimal-1.97.1/bin/clippy-driver
✅ rust-analyzer
rust-analyzer 1.97.1 (8bab26f 2026-07-14)
/nix/store/lr3m97p3hx1k22a7c44pb0wa7rbayhfi-rust-analyzer-preview-1.97.1-x86_64-unknown-linux-gnu/bin/rust-analyzer
/nix/store/4mglk7qw9jqbv5nwlx9ahdnpcn5sz70r-rust-analyzer-preview-1.97.1-x86_64-unknown-linux-gnu/bin/rust-analyzer
✅ rust-nightly
rustc 1.99.0-nightly (87e5904f5 2026-07-20)
/nix/store/j7kf7a5h4xypzp6x1skg4dsdx2k4fwb3-rust-nightly/bin/rust-nightly
rustc 1.101.0-nightly (282215592 2026-10-04)
/nix/store/qwyzkvba3f9569wjj45b4iyb7nz7qbnr-rust-nightly/bin/rust-nightly
✅ rustc
rustc 1.97.1 (8bab26f4f 2026-07-14)
/nix/store/40d3mzka7r1ps71l0yv2fs6616nbw85m-rust-minimal-1.97.1/bin/rustc
/nix/store/kk0kqdc4f7am21yp30rr8jcrnib5xqzy-rust-minimal-1.97.1/bin/rustc
✅ rustfmt
rustfmt 1.9.0-stable (8bab26f4f6 2026-07-14)
/nix/store/6f1icmb2za20kxn30pgmbv5jq9fnbf4z-rustfmt-preview-1.97.1-x86_64-unknown-linux-gnu/bin/rustfmt
/nix/store/y5gf8a3hix7pnwzdwcfpf3acqhzv3xy6-rustfmt-preview-1.97.1-x86_64-unknown-linux-gnu/bin/rustfmt
GCC toolchain:
✅ gcc
gcc (GCC) 15.2.0
/nix/store/3dd6y3pq00i3r85l45jvz63wjya403nl-gcc-wrapper-15.2.0/bin/gcc
gcc (GCC) 15.3.0
/nix/store/bslmkbaiymxxdc6lwcdb1qyw745nds5j-gcc-wrapper-15.3.0/bin/gcc
✅ gcc-15
gcc (GCC) 15.2.0
/nix/store/d6iri2s6bzqq5ac3fg25j6hgnn1lz44f-gcc-15/bin/gcc-15
gcc (GCC) 15.3.0
/nix/store/h6f2qc8kgwf7r81gwb10csvpjqfc2404-gcc-15/bin/gcc-15
✅ g++
g++ (GCC) 15.2.0
/nix/store/3dd6y3pq00i3r85l45jvz63wjya403nl-gcc-wrapper-15.2.0/bin/g++
g++ (GCC) 15.3.0
/nix/store/bslmkbaiymxxdc6lwcdb1qyw745nds5j-gcc-wrapper-15.3.0/bin/g++
✅ g++-15
g++ (GCC) 15.2.0
/nix/store/gm3msmmxq055lm9gprkfjj9d2gdz1mpg-g++-15/bin/g++-15
g++ (GCC) 15.3.0
/nix/store/jwncv76v61ld9l99v0b1dkmf810if65s-g++-15/bin/g++-15
✅ cpp
cpp (GCC) 15.2.0
/nix/store/3dd6y3pq00i3r85l45jvz63wjya403nl-gcc-wrapper-15.2.0/bin/cpp
cpp (GCC) 15.3.0
/nix/store/bslmkbaiymxxdc6lwcdb1qyw745nds5j-gcc-wrapper-15.3.0/bin/cpp
✅ cpp-15
cpp (GCC) 15.2.0
/nix/store/bn3gmn0m7g4gn2i0yml46fljc7mghiq5-cpp-15/bin/cpp-15
cpp (GCC) 15.3.0
/nix/store/jmi558xj8v7lz2fm6wrradh40dp48zx9-cpp-15/bin/cpp-15
✅ gcov
gcov (GCC) 15.2.0
/nix/store/xvv5sm5i8x0ks6ypfkzl7c4j9srnxz7k-gcc-15.2.0/bin/gcov
gcov (GCC) 15.3.0
/nix/store/n2ab7kf7mm84hna35x463mizcy52pf1h-gcc-15.3.0/bin/gcov
Mold:
✅ mold
mold 2.41.0 (compatible with GNU ld)
/nix/store/2w6fpgxjzzyqmd25wzplm23dfa49a0p2-mold-unwrapped-wrapper-2.41.0/bin/mold
mold 2.42.1 (compatible with GNU ld)
/nix/store/9dcddrfxlfl9n3wfibi5jkmp22bjkvkh-mold-unwrapped-wrapper-2.42.1/bin/mold
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
✅ All 53 checked tools are present and runnable.
✅ All 54 checked tools are present and runnable.
+99 -96
View File
@@ -2,173 +2,176 @@ Detected OS: linux (Linux aarch64)
Core build tools:
✅ cmake
cmake version 4.1.2
/nix/store/nkcpxjifkambzlrwh27a8igvhnbchibg-cmake-4.1.2/bin/cmake
cmake version 4.4.3
/nix/store/39cq2g3d3flq2lmb6hc09grxs4xaax8p-cmake-4.4.3/bin/cmake
✅ conan
Conan version 2.28.1
/nix/store/8i2gyqgc00xvxg9xm6y7n0ilncdv8imw-conan-2.28.1/bin/conan
Conan version 2.33.0
/nix/store/grz6a77mllqzzmg198qagx1r9zhvfijw-conan-2.33.0/bin/conan
✅ git
git version 2.54.0
/nix/store/ixp98f9avf8ikpdrmp40cj33g0dazyp9-git-2.54.0/bin/git
git version 2.55.0
/nix/store/kj6aff4gmz3snpp35rl3gysbl9srd81a-git-2.55.0/bin/git
✅ python3
Python 3.13.13
/nix/store/lqn6mbgzzdrqq2qkwddcmxj9z6amdd86-python3-3.13.13/bin/python3.13
Python 3.14.7
/nix/store/81ag9nxz1flw3xjkv1vvqg8y2ipx2ins-python3-3.14.7/bin/python3.14
Development tooling:
✅ ccache
ccache version 4.13.6
/nix/store/2q39xi2kbi04ibga7635f2sl148d1mzv-ccache-4.13.6/bin/ccache
/nix/store/nzb1lir9sw06fn4635kfx055myqanaz8-ccache-4.13.6/bin/ccache
✅ clang
clang version 22.1.7
/nix/store/xjqffrq9i7la058s9865ig71l9sp1ys5-clang-wrapper-22.1.7/bin/clang
✅ clang-22
clang version 22.1.7
/nix/store/vcf6ilfwn57828hwzyp6zlyr24j9j6yw-clang-22/bin/clang-22
clang version 23.1.0
/nix/store/g8sc13kz6jarzip643hk01832x40v8ms-clang-wrapper-23.1.0/bin/clang
✅ clang-23
clang version 23.1.0
/nix/store/j8qvcg9150s5n09qg8p62q5z3ci02hd9-clang-23/bin/clang-23
✅ clang++
clang version 22.1.7
/nix/store/xjqffrq9i7la058s9865ig71l9sp1ys5-clang-wrapper-22.1.7/bin/clang++
✅ clang++-22
clang version 22.1.7
/nix/store/xby0f6gamr7m27zp5cndsvghbp9lgb3c-clang++-22/bin/clang++-22
clang version 23.1.0
/nix/store/g8sc13kz6jarzip643hk01832x40v8ms-clang-wrapper-23.1.0/bin/clang++
✅ clang++-23
clang version 23.1.0
/nix/store/n62cn5w7fgbslamy3dgm8zhl5yly7zq0-clang++-23/bin/clang++-23
✅ ClangBuildAnalyzer
ClangBuildAnalyzer 1.6.0
/nix/store/h893hd4q1bb6ily2lby5dzyfrrzd2nvj-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
/nix/store/ml2991pbdhh0qcxqj9331lhpsg449vky-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
✅ curl
curl 8.20.0 (aarch64-unknown-linux-gnu) libcurl/8.20.0 OpenSSL/3.6.2 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.69.0 mit-krb5/1.22.1
/nix/store/i1s0lqwlrmjd2dxzgy2p84cxqqsb0bmk-curl-8.20.0-bin/bin/curl
curl 8.22.0 (aarch64-unknown-linux-gnu) libcurl/8.22.0 OpenSSL/3.5.8 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.70.0 mit-krb5/1.22.2
/nix/store/94c2x2bl3xb7mx43sg1bs1hd7pnw83ac-curl-8.22.0-bin/bin/curl
✅ file
file-5.47
/nix/store/dx973zg9km2w9albsib2vw9wyvacfrlw-file-5.47/bin/file
file-5.48
/nix/store/66sd1x1hls0yijibn00iz08jh4fnas9z-file-5.48/bin/file
✅ jq
jq-1.8.2
/nix/store/kr5py0dcqc9f3l9148qd1axh0z77lld3-jq-1.8.2-bin/bin/jq
✅ less
less 692 (PCRE2 regular expressions)
/nix/store/1blb3s7hhsr77wqi598m6k1qkfp3ms0w-less-692/bin/less
less 710 (PCRE2 regular expressions)
/nix/store/n6z9dv3yjlgvfx1nmrx6qzyv8vzim1l2-less-710/bin/less
✅ make
GNU Make 4.4.1
/nix/store/9ngw1ippk25jjj5fjxv36xbp6iq7rxdx-gnumake-4.4.1/bin/make
/nix/store/q07jxvck60qgrg4p1ywypddh5zz6i9s2-gnumake-4.4.1/bin/make
✅ netstat
net-tools 2.10
/nix/store/7vdsz21f0s499s5yyqzp5s4676q4yxdd-net-tools-2.10/bin/netstat
/nix/store/rfmhd3f8drg3wqyr2mhyrlkd7vyp2pxv-net-tools-2.10/bin/netstat
✅ ninja
1.13.2
/nix/store/8ksx98gsbn5lmlizcmw57yd4sg0k2p58-ninja-1.13.2/bin/ninja
/nix/store/lfkdyggn1ffslfd830l35jrvapr5lzri-ninja-1.13.2/bin/ninja
✅ perl
v5.42.0
/nix/store/5wnly69vv1i3y97al4v3xrqymf9hlzgq-perl-5.42.0/bin/perl
v5.42.3
/nix/store/nyp5q4d2cb0pghi4i7nscb97bqkb6kp3-perl-5.42.3/bin/perl
✅ pkg-config
0.29.2
/nix/store/c7vwy0gl1q0agl2h22gi0m9dg7xxad2l-pkg-config-wrapper-0.29.2/bin/pkg-config
/nix/store/h82n3d0wdrgskdc3yvmz5l3c50h2snvp-pkg-config-wrapper-0.29.2/bin/pkg-config
✅ vim
VIM - Vi IMproved 9.2 (2026 Feb 14, compiled Jan 01 1980 00:00:00)
/nix/store/v8c7pvx26irvy9k5sbwd183cyvckzzb3-vim-9.2.0389/bin/vim
/nix/store/h39h0qq4i80sp3yd7sxjn2wf497v5rln-vim-9.2.1001/bin/vim
✅ zip
Zip 3.0
/nix/store/5mh19mvbv9ym2sm9vymyyaac5l2cj2jq-zip-3.0/bin/zip
/nix/store/lfwhq17wfcmjy823fldhlhxj1hjchdzc-zip-3.0/bin/zip
✅ clang-apply-replacements
clang-apply-replacements version 22.1.7
/nix/store/s53p2m776iqaz7acgr5csgpsd18w15h7-clang-tools-22.1.7/bin/clang-apply-replacements
✅ clang-apply-replacements-22
clang-apply-replacements version 22.1.7
/nix/store/bg4kn8z81hk7b9284rjqvr51wpfjqc24-clang-apply-replacements-22/bin/clang-apply-replacements-22
clang-apply-replacements version 23.1.0
/nix/store/jh9xhz6gwxyz3rfx7vy5g4j5d71w940r-clang-tools-23.1.0/bin/clang-apply-replacements
✅ clang-apply-replacements-23
clang-apply-replacements version 23.1.0
/nix/store/1ajzrfr62m3cianfh9i97r30a7vp1xmb-clang-apply-replacements-23/bin/clang-apply-replacements-23
✅ clang-format
clang-format version 22.1.7
/nix/store/s53p2m776iqaz7acgr5csgpsd18w15h7-clang-tools-22.1.7/bin/clang-format
✅ clang-format-22
clang-format version 22.1.7
/nix/store/79v57mzcw8ng8kl7p961ck08ymhp31v7-clang-format-22/bin/clang-format-22
clang-format version 23.1.0
/nix/store/jh9xhz6gwxyz3rfx7vy5g4j5d71w940r-clang-tools-23.1.0/bin/clang-format
✅ clang-format-23
clang-format version 23.1.0
/nix/store/5nfddq7xgbp4zmj8jn7xk1pxyyn5wiwl-clang-format-23/bin/clang-format-23
✅ clang-tidy
LLVM version 22.1.7
/nix/store/s53p2m776iqaz7acgr5csgpsd18w15h7-clang-tools-22.1.7/bin/clang-tidy
✅ clang-tidy-22
LLVM version 22.1.7
/nix/store/wdyd6cb9z1lyi37lbzvwldgcc7yv1n5c-clang-tidy-22/bin/clang-tidy-22
LLVM version 23.1.0
/nix/store/jh9xhz6gwxyz3rfx7vy5g4j5d71w940r-clang-tools-23.1.0/bin/clang-tidy
✅ clang-tidy-23
LLVM version 23.1.0
/nix/store/cawfgsx0vsslc1f007cavmy8md9drb1r-clang-tidy-23/bin/clang-tidy-23
✅ dot
dot - graphviz version 12.2.1 (0)
/nix/store/58rrk4yzwpmyxvl8cqm18h3dhv24zf00-graphviz-12.2.1/bin/dot
dot - graphviz version 15.1.1 (0)
/nix/store/vz4zb8d1rfigzzdn3i0hd4kff28vk02l-graphviz-15.1.1/bin/dot
✅ doxygen
1.16.1
/nix/store/hq32kzwpl89wgr49iq0gmqn9r5n072zq-doxygen-1.16.1/bin/doxygen
1.17.0
/nix/store/6q4z332wc9jnvad71wjj87lgjxidhgzl-doxygen-1.17.0/bin/doxygen
✅ gcovr
gcovr 8.4
/nix/store/sml3xbbfhhlhk6h7jnlg19pdbx9b764b-python3.13-gcovr-8.4/bin/gcovr
/nix/store/v548fjz51k2nmr257vjnd0zp3bxpc2r1-python3.14-gcovr-8.4/bin/gcovr
✅ gh
gh version 2.94.0 (nixpkgs)
/nix/store/7hh2qi0gj2ifbxbl56cjzbiyfc379bji-gh-2.94.0/bin/gh
gh version 2.102.0 (2026-09-30)
/nix/store/vgg6gnq74h76b4r2ac2q9366f2s5qxwx-gh-2.102.0/bin/gh
✅ git-cliff
git-cliff 2.13.1
/nix/store/bidn3pz53yd6qlg711917xx0q10hqmqv-git-cliff-2.13.1/bin/git-cliff
git-cliff 2.14.2
/nix/store/hrlgliq7l3fl2qrdlc197mvscs4n03rd-git-cliff-2.14.2/bin/git-cliff
✅ git-lfs
git-lfs/3.7.1 (3.7.1; linux arm64; go 1.26.3)
/nix/store/4rsklvkbac5bayy0zv12kxyvspi4sshd-git-lfs-3.7.1/bin/git-lfs
git-lfs/3.8.0 (3.8.0; linux arm64; go 1.26.8)
/nix/store/pa2g4xdvr4a73m6mv4cqs0pik1ka1xp5-git-lfs-3.8.0/bin/git-lfs
✅ gpg
gpg (GnuPG) 2.4.9
/nix/store/ka4i8zz5ni3rzqnzcxbfvwr95fk8pn6q-gnupg-2.4.9/bin/gpg
/nix/store/3qc90b7qkxz7na3xnpd2qb8yvcq8zdp6-gnupg-2.4.9/bin/gpg
✅ pre-commit
pre-commit 4.5.1
/nix/store/n981w6hjfar2l81kxbxs2wxl64vwa5kj-pre-commit-4.5.1/bin/pre-commit
pre-commit 4.6.2
/nix/store/5f3av75nc7n7xbf2hlvlagzpp2g8g562-pre-commit-4.6.2/bin/pre-commit
✅ run-clang-tidy
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
/nix/store/4z2fyklg78klallr7x9j02kz92hnxp4m-run-clang-tidy/bin/run-clang-tidy
✅ run-clang-tidy-22
/nix/store/nlg35d9ccslsq5qny7raxyyyrxgk7vsq-run-clang-tidy/bin/run-clang-tidy
✅ run-clang-tidy-23
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
/nix/store/f8m0p9ad40brp9ahy4i0h27kqjkya1j9-run-clang-tidy-22/bin/run-clang-tidy-22
/nix/store/a50nf8hp8p8l8pgcf9fs0j25hij5acw3-run-clang-tidy-23/bin/run-clang-tidy-23
Rust toolchain:
✅ cargo
cargo 1.97.1 (c980f4866 2026-06-30)
/nix/store/6hch2qrr86n2sa2m90lrpxrfxxwbkayl-cargo-1.97.1-aarch64-unknown-linux-gnu/bin/cargo
/nix/store/nci0zxxj2fiq0dlkpqzbnqfh27wz4sq4-cargo-1.97.1-aarch64-unknown-linux-gnu/bin/cargo
✅ cargo-audit
cargo-audit-audit 0.22.1
/nix/store/9rxbrn9aa2r1z96186s69pc7vzizyfch-cargo-audit-0.22.1/bin/cargo-audit
cargo-audit-audit 0.22.2
/nix/store/zldaj03mfz9f21yiby5yymq7v8vqygd7-cargo-audit-0.22.2/bin/cargo-audit
✅ cargo-llvm-cov
cargo-llvm-cov 0.8.5
/nix/store/vwjsi159n89szrx4yh5pc3jlf2gp4fld-cargo-llvm-cov-0.8.5/bin/cargo-llvm-cov
cargo-llvm-cov 0.9.0
/nix/store/iwpcfjah31fgn99ph32ajzz7i22j6al5-cargo-llvm-cov-0.9.0/bin/cargo-llvm-cov
✅ cargo-nextest
cargo-nextest 0.9.137
/nix/store/qb6bcg2fjvm3r9s9j98nmffmf9xwh45s-cargo-nextest-0.9.137/bin/cargo-nextest
cargo-nextest 0.9.146
/nix/store/p5svqr8x1rr7b1i8595pr8qafsr7s6fm-cargo-nextest-0.9.146/bin/cargo-nextest
✅ clippy-driver
clippy 0.1.97 (8bab26f4f6 2026-07-14)
/nix/store/a6p27cg6b8szfixfyvkssx6l0c345zw8-rust-minimal-1.97.1/bin/clippy-driver
/nix/store/ny64zks16ms5d70jk1qsiwsk0fr33ipp-rust-minimal-1.97.1/bin/clippy-driver
✅ rust-analyzer
rust-analyzer 1.97.1 (8bab26f 2026-07-14)
/nix/store/262830dlw2517lnagfx7i7agqgl4fmsd-rust-analyzer-preview-1.97.1-aarch64-unknown-linux-gnu/bin/rust-analyzer
/nix/store/d9s5skhvi1qxj940mylwym2rjicnc2kq-rust-analyzer-preview-1.97.1-aarch64-unknown-linux-gnu/bin/rust-analyzer
✅ rust-nightly
rustc 1.99.0-nightly (87e5904f5 2026-07-20)
/nix/store/c59pxk1yikdlf129qwyg4fplmxcrha0k-rust-nightly/bin/rust-nightly
rustc 1.101.0-nightly (282215592 2026-10-04)
/nix/store/rbsf1gr6f9ikv2izlyh8im117w6hs7h5-rust-nightly/bin/rust-nightly
✅ rustc
rustc 1.97.1 (8bab26f4f 2026-07-14)
/nix/store/a6p27cg6b8szfixfyvkssx6l0c345zw8-rust-minimal-1.97.1/bin/rustc
/nix/store/ny64zks16ms5d70jk1qsiwsk0fr33ipp-rust-minimal-1.97.1/bin/rustc
✅ rustfmt
rustfmt 1.9.0-stable (8bab26f4f6 2026-07-14)
/nix/store/nd8g81wv1smnvdpy4whpcyv2siwjmaan-rustfmt-preview-1.97.1-aarch64-unknown-linux-gnu/bin/rustfmt
/nix/store/dplvgjikmv8909rk0dkqr90ryjg7xn0j-rustfmt-preview-1.97.1-aarch64-unknown-linux-gnu/bin/rustfmt
GCC toolchain:
✅ gcc
gcc (GCC) 15.2.0
/nix/store/rn6svg593xsmn8qcjzk8x9pa1i62c4kb-gcc-wrapper-15.2.0/bin/gcc
gcc (GCC) 15.3.0
/nix/store/g7z555pl99vnwif4jxa05nk1qdc33i1n-gcc-wrapper-15.3.0/bin/gcc
✅ gcc-15
gcc (GCC) 15.2.0
/nix/store/h489d1rmjisfbxh5kmsb0a7c35j8qsdf-gcc-15/bin/gcc-15
gcc (GCC) 15.3.0
/nix/store/vbdsfjk3j1xy5z329sl2d8vp6mq6x09i-gcc-15/bin/gcc-15
✅ g++
g++ (GCC) 15.2.0
/nix/store/rn6svg593xsmn8qcjzk8x9pa1i62c4kb-gcc-wrapper-15.2.0/bin/g++
g++ (GCC) 15.3.0
/nix/store/g7z555pl99vnwif4jxa05nk1qdc33i1n-gcc-wrapper-15.3.0/bin/g++
✅ g++-15
g++ (GCC) 15.2.0
/nix/store/9ywmhz8bmzknrn3pn84g46z8hj3vrmw5-g++-15/bin/g++-15
g++ (GCC) 15.3.0
/nix/store/9ghl998ry4cxlsg6hnq5rn2iipnlkccm-g++-15/bin/g++-15
✅ cpp
cpp (GCC) 15.2.0
/nix/store/rn6svg593xsmn8qcjzk8x9pa1i62c4kb-gcc-wrapper-15.2.0/bin/cpp
cpp (GCC) 15.3.0
/nix/store/g7z555pl99vnwif4jxa05nk1qdc33i1n-gcc-wrapper-15.3.0/bin/cpp
✅ cpp-15
cpp (GCC) 15.2.0
/nix/store/vmjilh1b830qz9yh0a1jj5ads0jxizdk-cpp-15/bin/cpp-15
cpp (GCC) 15.3.0
/nix/store/wj0mv2fv2lhglvpjzhscqpbigkvik6br-cpp-15/bin/cpp-15
✅ gcov
gcov (GCC) 15.2.0
/nix/store/rmwf5hpi1y2m1wpnfvlxmrhksm4djk2j-gcc-15.2.0/bin/gcov
gcov (GCC) 15.3.0
/nix/store/mszfsj00qnv9ygqcqz3w02qzxxskhvlb-gcc-15.3.0/bin/gcov
Mold:
✅ mold
mold 2.41.0 (compatible with GNU ld)
/nix/store/f5qh5a0bx1dslmnf5n5gx0s6aljbswq3-mold-unwrapped-wrapper-2.41.0/bin/mold
mold 2.42.1 (compatible with GNU ld)
/nix/store/gbq334xbibaz4gn184j7gs58m2spgwi7-mold-unwrapped-wrapper-2.42.1/bin/mold
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
✅ All 53 checked tools are present and runnable.
✅ All 54 checked tools are present and runnable.
+3 -2
View File
@@ -7,7 +7,7 @@
...
}:
let
inherit (import ./packages.nix { inherit pkgs; }) commonPackages;
inherit (import ./packages.nix { inherit pkgs customGlibc; }) commonPackages;
# Each forces something absent on the other platform, so both stay lazy.
linux = import ./linux.nix { inherit pkgs customGlibc; };
@@ -21,7 +21,8 @@ let
)
);
toolchain = if pkgs.stdenv.isLinux then linux.toolchain else (darwin.toolchain ++ [ darwinEnv ]);
toolchain =
if pkgs.stdenv.hostPlatform.isLinux then linux.toolchain else (darwin.toolchain ++ [ darwinEnv ]);
in
{
default = pkgs.buildEnv {
+21 -18
View File
@@ -20,15 +20,19 @@ let
# Custom-glibc stdenvs, matching the CI environment. darwin has no custom
# glibc, so there they fall back to the plain nixpkgs stdenvs.
customGccStdenv = if pkgs.stdenv.isLinux then linux.gccStdenv else plainGccStdenv;
customClangStdenv = if pkgs.stdenv.isLinux then linux.clangStdenv else plainClangStdenv;
customGccStdenv = if pkgs.stdenv.hostPlatform.isLinux then linux.gccStdenv else plainGccStdenv;
customClangStdenv =
if pkgs.stdenv.hostPlatform.isLinux then linux.clangStdenv else plainClangStdenv;
# gcov matching each gcc shell, so `-Dcoverage=ON` builds work in the shell.
plainGcov = mkGcov {
name = "plain";
cc = gccPackage.cc;
};
customGccGcov = if pkgs.stdenv.isLinux then linux.gcov else plainGcov;
customGccGcov = if pkgs.stdenv.hostPlatform.isLinux then linux.gcov else plainGcov;
# commonPackages whose clang tools parse with the custom toolchain's headers.
customCommonPackages = (import ./packages.nix { inherit pkgs customGlibc; }).commonPackages;
# Whole directory: init.sh locates the profiles relative to itself.
conanDir = ../conan;
@@ -51,7 +55,7 @@ let
# Not sdkEnv: a shell's stdenv already sets that up. Prepended so the stub
# beats the nixpkgs libresolv this shell's tooling drags in.
darwinLibresolvHook = pkgs.lib.optionalString pkgs.stdenv.isDarwin (
darwinLibresolvHook = pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isDarwin (
pkgs.lib.concatLines (
pkgs.lib.mapAttrsToList (
name: value: ''export ${name}="${value} ''${${name}:-}"''
@@ -85,11 +89,11 @@ let
version ? null,
versionedTools ? [ ],
extraPackages ? [ ],
warningHook ? "",
# Opt out of PatchNixBinary.cmake retargeting binaries to the system
# loader. The plain toolchain links a newer glibc, so it must not be
# patched; the custom toolchain patches by default.
noPatchNixBinary ? false,
# The stock nixpkgs toolchain: warn that it doesn't match CI, keep the
# clang tools off the custom toolchain, and opt out of PatchNixBinary.cmake
# retargeting binaries to the system loader (the plain toolchain links a
# newer glibc, so it must not be patched).
plain ? false,
}:
let
compilerVersionHook =
@@ -109,7 +113,8 @@ let
in
(pkgs.mkShell.override { inherit stdenv; }) (
{
packages = commonPackages ++ versionedLinks ++ extraPackages;
packages =
(if plain then commonPackages else customCommonPackages) ++ versionedLinks ++ extraPackages;
# Marks a managed dev shell, so the build (XrplSanity.cmake) can tell an
# intentional Nix toolchain from one leaked into a bare shell.
XRPL_DEVSHELL = shellName;
@@ -118,15 +123,15 @@ let
${compilerVersionHook}
${darwinLibresolvHook}
${conanHook}
${warningHook}
${pkgs.lib.optionalString plain plainWarningHook}
'';
}
// pkgs.lib.optionalAttrs noPatchNixBinary { XRPLD_NO_PATCH_NIX_BINARY = "1"; }
// pkgs.lib.optionalAttrs plain { XRPLD_NO_PATCH_NIX_BINARY = "1"; }
);
in
rec {
# macOS: Nix Clang. Linux: Nix GCC.
default = if pkgs.stdenv.isDarwin then clang else gcc;
default = if pkgs.stdenv.hostPlatform.isDarwin then clang else gcc;
# gcc/clang use the custom-glibc toolchain, matching CI. On darwin there is no
# custom glibc, so they fall back to the plain nixpkgs toolchain.
@@ -171,7 +176,7 @@ rec {
# The *-plain shells (stock nixpkgs toolchain) exist only on Linux: on darwin
# gcc/clang are already plain, so these would be redundant and are omitted, which
# makes `nix develop .#gcc-plain` fail there rather than silently aliasing gcc.
// pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
// pkgs.lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux {
gcc-plain = makeShell {
shellName = "gcc-plain";
stdenv = plainGccStdenv;
@@ -179,8 +184,7 @@ rec {
version = gccVersion;
versionedTools = gccVersionedTools;
extraPackages = [ plainGcov ];
warningHook = plainWarningHook;
noPatchNixBinary = true;
plain = true;
};
clang-plain = makeShell {
@@ -189,7 +193,6 @@ rec {
compilerName = "clang";
version = llvmVersion;
versionedTools = clangVersionedTools;
warningHook = plainWarningHook;
noPatchNixBinary = true;
plain = true;
};
}
+1
View File
@@ -146,6 +146,7 @@ in
})
];
clang = customClang;
gccStdenv = customStdenv;
clangStdenv = pkgs.stdenvAdapters.overrideCC pkgs.stdenv customClang;
gcov = customGcov;
+38 -7
View File
@@ -1,14 +1,28 @@
{ pkgs }:
{
pkgs,
# With the custom glibc, the clang tools (clang-tidy, ...) parse code with the
# Linux custom toolchain's headers, i.e. the same glibc and libstdc++ as the
# build. Without it, they use the nixpkgs default compiler's.
customGlibc ? null,
}:
let
# Compiler versions used across the dev shell and the CI environment.
# Docs link here and scripts read the version off the tools;
# only the clang-format rev in .pre-commit-config.yaml
# has to be bumped alongside llvmVersion.
gccVersion = 15;
llvmVersion = 22;
llvmVersion = 23;
gccPackage = pkgs."gcc${toString gccVersion}";
llvmPackages = pkgs."llvmPackages_${toString llvmVersion}";
# Bound explicitly so it tracks llvmPackages above, not the `with pkgs` default.
clangTools = llvmPackages.clang-tools;
# isLinux first: darwin must not evaluate the custom glibc.
clangTools = llvmPackages.clang-tools.override (
pkgs.lib.optionalAttrs (pkgs.stdenv.hostPlatform.isLinux && customGlibc != null) {
inherit (import ./linux.nix { inherit pkgs customGlibc; }) clang;
}
);
# In LLVM 22, run-clang-tidy.py moved from share/clang/ to bin/, so nixpkgs
# clang-tools no longer links it. Wrap it manually.
@@ -16,6 +30,21 @@ let
exec ${pkgs.python3}/bin/python3 ${llvmPackages.clang-unwrapped}/bin/run-clang-tidy "$@"
'';
# Conan 2.33 is the first release whose settings.yml accepts clang 23.
# TODO: drop once nixpkgs ships it.
conan = pkgs.conan.overridePythonAttrs (old: {
version = "2.33.0";
src = pkgs.fetchFromGitHub {
owner = "conan-io";
repo = "conan";
tag = "2.33.0";
hash = "sha256-FDJjesqvPiAUAEjeqQt088Vnet/KXHbUyEPytP9MyG4=";
};
dependencies = old.dependencies ++ [ pkgs.python3Packages.truststore ];
# The upstream test suite takes long and needs network access.
doCheck = false;
});
rust = import ./rust.nix { inherit pkgs; };
# Nix wraps its toolchain so that binaries are exposed only under unsuffixed
@@ -25,10 +54,11 @@ let
# - Conan's Boost recipe looks up `g++-<major>` before plain `g++`.
# - bin/pre-commit/clang_tidy_check.py looks up `run-clang-tidy-<v>` and
# `clang-apply-replacements-<v>` before the unsuffixed names.
# On a host that also has the matching system binary (e.g. Ubuntu's
# `/usr/bin/g++-15` or `clang-tidy-22`) the probe escapes Nix and mixes a
# system tool into the Nix environment. Generate version-suffixed symlinks
# next to a package's tools so those probes resolve to the Nix ones.
# On a host that also has the matching system binary
# (e.g. Ubuntu's `/usr/bin/g++-<v>` or `clang-tidy-<v>`),
# the probe escapes Nix and mixes a system tool into the Nix environment.
# Generate version-suffixed symlinks next to a package's tools
# so those probes resolve to the Nix ones.
#
# Compiler links must point at whichever compiler is active in a given
# environment (the plain stdenv compiler in the dev shell, the custom-glibc
@@ -112,6 +142,7 @@ in
gnumake
gnupg # needed for signing commits & codecov/codecov-action
graphviz
jq
less # needed for git diff
mold
nettools # provides netstat, used to debug failures in CI
+3 -3
View File
@@ -36,7 +36,7 @@ BASE_NAME = "xrpld"
# The flavours that can be built, '' being the plain xrpld package. A variant
# needs a config in linux.json to be built by CI; see package/README.md.
VARIANTS = ("", "assert")
VARIANTS = ("", "assert", "supported")
# Files both packaging systems consume, staged under the same names.
STAGED_FROM_BUILD = ("xrpld", "validator-keys", "validator-keys-LICENSE")
@@ -323,8 +323,8 @@ def main() -> None:
default="",
choices=VARIANTS,
help="the flavour of the package to build: 'assert' produces "
"xrpld-assert, which ships the same paths as xrpld and replaces it "
"(default: the plain xrpld package)",
"xrpld-assert, 'supported' xrpld-supported, each shipping the same "
"paths as xrpld and replacing it (default: the plain xrpld package)",
)
parser.add_argument(
"--channel",
+7 -4
View File
@@ -11,6 +11,8 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/LedgerTiming.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/FeeSettingsEntry.h>
#include <xrpl/ledger/entries/NegativeUNLEntry.h>
#include <xrpl/nodestore/NodeObject.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Fees.h>
@@ -560,7 +562,7 @@ Ledger::setup()
try
{
if (auto const sle = read(keylet::feeSettings()))
if (auto const sle = FeeSettingsEntryR(*this))
{
bool oldFees = false;
bool newFees = false;
@@ -639,7 +641,7 @@ HashSet<PublicKey>
Ledger::negativeUNL() const
{
HashSet<PublicKey> negUnl;
if (auto sle = read(keylet::negativeUNL()); sle && sle->isFieldPresent(sfDisabledValidators))
if (auto const sle = NegativeUNLEntryR(*this); sle && sle->isFieldPresent(sfDisabledValidators))
{
auto const& nUnlData = sle->getFieldArray(sfDisabledValidators);
for (auto const& n : nUnlData)
@@ -663,7 +665,7 @@ Ledger::negativeUNL() const
std::optional<PublicKey>
Ledger::validatorToDisable() const
{
if (auto sle = read(keylet::negativeUNL()); sle && sle->isFieldPresent(sfValidatorToDisable))
if (auto const sle = NegativeUNLEntryR(*this); sle && sle->isFieldPresent(sfValidatorToDisable))
{
auto d = sle->getFieldVL(sfValidatorToDisable);
auto s = makeSlice(d);
@@ -677,7 +679,8 @@ Ledger::validatorToDisable() const
std::optional<PublicKey>
Ledger::validatorToReEnable() const
{
if (auto sle = read(keylet::negativeUNL()); sle && sle->isFieldPresent(sfValidatorToReEnable))
if (auto const sle = NegativeUNLEntryR(*this);
sle && sle->isFieldPresent(sfValidatorToReEnable))
{
auto d = sle->getFieldVL(sfValidatorToReEnable);
auto s = makeSlice(d);
+3 -3
View File
@@ -3,6 +3,7 @@
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/hash/uhash.h>
#include <xrpl/ledger/detail/ReadViewFwdRange.h>
#include <xrpl/ledger/entries/AmendmentsEntry.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/Rules.h>
@@ -72,9 +73,8 @@ makeRulesGivenLedger(
std::optional const digest = ledger.digest(k.key);
if (digest)
{
auto const sle = ledger.read(k);
if (sle)
return Rules(presets, digest, sle->getFieldV256(sfAmendments));
if (AmendmentsEntryR const entry(k, ledger); entry)
return Rules(presets, digest, entry->getFieldV256(sfAmendments));
}
return Rules(presets);
}
+20 -57
View File
@@ -9,7 +9,8 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/entries/AmendmentsEntry.h>
#include <xrpl/ledger/entries/LedgerHashesEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -116,8 +117,8 @@ isVaultPseudoAccountFrozenForIssuance(
view, {issuer, account}, assetOfHolding(issuanceSle, *sleHolding), depth + 1);
}
auto const mptIssuer = AccountRootEntryR(issuer, view);
if (!mptIssuer.exists())
auto const mptIssuer = view.read(keylet::account(issuer));
if (mptIssuer == nullptr)
{
// LCOV_EXCL_START
UNREACHABLE("xrpl::isVaultPseudoAccountFrozen : null MPToken issuer");
@@ -190,7 +191,7 @@ canTransferLPToken(
{
// Only AMM-issued LPTokens are subject to this check. The LPToken's issuer
// is the AMM account; if it is not an AMM, this is not an LPToken.
auto const sleIssuer = AccountRootEntryR(lpTokenIssuer, view);
auto const sleIssuer = view.read(keylet::account(lpTokenIssuer));
if (!sleIssuer || !sleIssuer->isFieldPresent(sfAMMID))
return tesSUCCESS;
@@ -309,40 +310,13 @@ areCompatible(
std::set<UInt256>
getEnabledAmendments(ReadView const& view)
{
std::set<UInt256> amendments;
if (auto const sle = view.read(keylet::amendments()))
{
if (sle->isFieldPresent(sfAmendments))
{
auto const& v = sle->getFieldV256(sfAmendments);
amendments.insert(v.begin(), v.end());
}
}
return amendments;
return AmendmentsEntryR(view).enabledAmendments();
}
MajorityAmendmentsT
getMajorityAmendments(ReadView const& view)
{
MajorityAmendmentsT ret;
if (auto const sle = view.read(keylet::amendments()))
{
if (sle->isFieldPresent(sfMajorities))
{
using Tp = NetClock::time_point;
using D = Tp::duration;
auto const majorities = sle->getFieldArray(sfMajorities);
for (auto const& m : majorities)
ret[m.getFieldH256(sfAmendment)] = Tp(D(m.getFieldU32(sfCloseTime)));
}
}
return ret;
return AmendmentsEntryR(view).majorityAmendments();
}
std::optional<UInt256>
@@ -362,17 +336,16 @@ hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal)
if (int const diff = ledger.seq() - seq; diff <= 256)
{
// Within 256...
auto const hashIndex = ledger.read(keylet::skip());
LedgerHashesEntryR const hashIndex(ledger, journal);
if (hashIndex)
{
XRPL_ASSERT(
hashIndex->getFieldU32(sfLastLedgerSequence) == (ledger.seq() - 1),
"xrpl::hashOfSeq : matching ledger sequence");
STVector256 vec = hashIndex->getFieldV256(sfHashes);
if (vec.size() >= diff)
return vec[vec.size() - diff];
if (auto const hash = hashIndex.hashAt(diff - 1))
return hash;
JLOG(journal.warn()) << "Ledger " << ledger.seq() << " missing hash for " << seq << " ("
<< vec.size() << "," << diff << ")";
<< hashIndex->getFieldV256(sfHashes).size() << "," << diff << ")";
}
else
{
@@ -388,16 +361,14 @@ hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal)
}
// in skiplist
auto const hashIndex = ledger.read(keylet::skip(seq));
LedgerHashesEntryR const hashIndex(keylet::skip(seq), ledger, journal);
if (hashIndex)
{
auto const lastSeq = hashIndex->getFieldU32(sfLastLedgerSequence);
XRPL_ASSERT(lastSeq >= seq, "xrpl::hashOfSeq : minimum last ledger");
XRPL_ASSERT((lastSeq & 0xff) == 0, "xrpl::hashOfSeq : valid last ledger");
auto const diff = (lastSeq - seq) >> 8;
STVector256 vec = hashIndex->getFieldV256(sfHashes);
if (vec.size() > diff)
return vec[vec.size() - diff - 1];
if (auto const hash = hashIndex.hashAt((lastSeq - seq) >> 8))
return hash;
}
JLOG(journal.warn()) << "Can't get seq " << seq << " from " << ledger.seq() << " error";
return std::nullopt;
@@ -467,7 +438,7 @@ canWithdraw(
ReadView const& view,
AccountID const& from,
AccountID const& to,
AccountRootEntryR const& toSle,
SLE::ConstRef toSle,
STAmount const& amount,
bool hasDestinationTag,
std::optional<std::vector<UInt256>> const& credentialIDs)
@@ -517,7 +488,7 @@ canWithdraw(
bool hasDestinationTag,
std::optional<std::vector<UInt256>> const& credentialIDs)
{
auto const toSle = AccountRootEntryR(to, view);
auto const toSle = view.read(keylet::account(to));
return canWithdraw(view, from, to, toSle, amount, hasDestinationTag, credentialIDs);
}
@@ -542,7 +513,7 @@ doWithdraw(
STAmount const& amount,
beast::Journal j)
{
auto dstSle = AccountRootEntryW(dstAcct, ctx.view);
auto const dstSle = ctx.view.read(keylet::account(dstAcct));
// Create a trust line or MPToken for a self-destination only when there
// is a payout to credit. Post-fixCleanup3_4_0, a zero-value withdraw
@@ -560,8 +531,7 @@ doWithdraw(
}
else
{
if (auto err =
verifyDepositPreauth(ctx.tx, ctx.view, senderAcct, dstAcct, dstSle.rawSle(), j))
if (auto err = verifyDepositPreauth(ctx.tx, ctx.view, senderAcct, dstAcct, dstSle, j))
return err;
}
@@ -584,21 +554,14 @@ doWithdraw(
// sponsor against the destination. accountSend can auto-create a holding
// for dstAcct; keying on the destination ensures a third-party destination's
// holding is never stamped with the tx's reserve sponsor.
auto sponsorSle = getEffectiveTxReserveSponsor(ctx, dstSle);
auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, dstSle);
if (!sponsorSle)
return sponsorSle.error(); // LCOV_EXCL_LINE
// Move the funds directly from the broker's pseudo-account to the
// dstAcct
auto& sponsor = *sponsorSle;
return accountSend(
ctx.view,
sourceAcct,
dstAcct,
amount,
j,
sponsor ? sponsor->mutableRawSle() : SLE::pointer{},
WaiveTransferFee::Yes);
ctx.view, sourceAcct, dstAcct, amount, j, *sponsorSle, WaiveTransferFee::Yes);
}
TER
@@ -1,322 +0,0 @@
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/OwnerCounts.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.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/STTx.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/XRPAmount.h>
#include <cstdint>
#include <limits>
#include <optional>
#include <utility>
namespace xrpl {
template <typename ViewT>
XRPAmount
AccountRootEntry<ViewT>::reserve(Adjustment adj) const
{
auto const& view = this->readView();
auto const j = this->journal();
XRPL_ASSERT(
this->exists() && (*this)->getType() == ltACCOUNT_ROOT, "xrpl::accountReserve : valid sle");
if (!view.rules().enabled(featureSponsor))
{
XRPL_ASSERT(adj.accountCountDelta == 0, "xrpl::accountReserve : no account count delta");
return view.fees().accountReserve(
(*this)->getFieldU32(sfOwnerCount) + adj.ownerCountDelta, 1);
}
std::uint32_t const currentOwnerCount = ownerCount(adj.ownerCountDelta);
std::uint32_t const currentAccountCount =
detail::accountCountImpl(*this, adj.accountCountDelta, j);
return view.fees().accountReserve(currentOwnerCount, currentAccountCount);
}
template <typename ViewT>
std::uint32_t
AccountRootEntry<ViewT>::ownerCount(std::int32_t ownerCountAdj) const
{
auto const j = this->journal();
XRPL_ASSERT(
this->exists() && (*this)->getType() == ltACCOUNT_ROOT,
"xrpl::ownerCount : sle is account root");
AccountID const id = (*this)->getAccountID(sfAccount);
std::uint32_t const currentOwnerCount = (*this)->at(sfOwnerCount);
std::uint32_t const sponsoredOwnerCount = (*this)->at(sfSponsoredOwnerCount);
std::uint32_t const sponsoringOwnerCount = (*this)->at(sfSponsoringOwnerCount);
XRPL_ASSERT(
currentOwnerCount >= sponsoredOwnerCount,
"xrpl::ownerCount : OwnerCount must be greater than or equal to SponsoredOwnerCount");
std::int64_t deltaCount =
static_cast<std::int64_t>(ownerCountAdj) - sponsoredOwnerCount + sponsoringOwnerCount;
if (deltaCount > std::numeric_limits<std::int32_t>::max())
{
// LCOV_EXCL_START
deltaCount = std::numeric_limits<std::int32_t>::max();
JLOG(j.fatal()) << "Account " << id << " delta count exceeds max, "
<< "adjustment: " << ownerCountAdj
<< ", sponsoredCount: " << sponsoredOwnerCount
<< ", sponsoringOwnerCount: " << sponsoringOwnerCount;
// LCOV_EXCL_STOP
}
else if (deltaCount < std::numeric_limits<std::int32_t>::min())
{
// LCOV_EXCL_START
deltaCount = std::numeric_limits<std::int32_t>::min();
JLOG(j.fatal()) << "Account " << id << " delta count is below min, "
<< "adjustment: " << ownerCountAdj
<< ", sponsoredCount: " << sponsoredOwnerCount
<< ", sponsoringCount: " << sponsoringOwnerCount;
// LCOV_EXCL_STOP
}
return detail::confineOwnerCount(currentOwnerCount, deltaCount);
}
template <typename ViewT>
TER
AccountRootEntry<ViewT>::checkReserve(
ApplyViewContext ctx,
XRPAmount accBalance,
std::optional<AccountRootEntry<ReadView>> const& sponsorSle,
Adjustment adj,
TER insufReserveCode) const
{
// TODO: swap to assert after fixCleanup3_2_0 is retired
if (!this->exists() || (*this)->getType() != ltACCOUNT_ROOT)
return tefINTERNAL; // LCOV_EXCL_LINE
XRPL_ASSERT(
!isTesSuccess(insufReserveCode), "xrpl::checkReserve : insufReserveCode is not tesSUCCESS");
if (ctx.view.rules().enabled(featureSponsor))
{
if (sponsorSle)
{
if ((*sponsorSle)->getType() != ltACCOUNT_ROOT)
return tefINTERNAL; // LCOV_EXCL_LINE
auto const sle = ctx.view.read(
keylet::sponsorship(
(*sponsorSle)->getAccountID(sfAccount), (*this)->getAccountID(sfAccount)));
// A reserve-sponsored tx must carry a sponsor signature
// (cosigning path) and/or have a pre-existing sponsorship SLE
// (prefunded path). Absence of both is an internal invariant break.
if (isReserveSponsored(ctx.tx) && !sle && !ctx.tx.isFieldPresent(sfSponsorSignature))
return tecINTERNAL; // LCOV_EXCL_LINE
if (sle)
{
auto const ownerCountAllowed = sle->getFieldU32(sfRemainingOwnerCount);
if (adj.ownerCountDelta > 0 &&
ownerCountAllowed < static_cast<std::uint32_t>(adj.ownerCountDelta))
return insufReserveCode;
}
auto const sponsorBalance = (*sponsorSle)->getFieldAmount(sfBalance).xrp();
XRPAmount const sponsorReserve = sponsorSle->reserve(adj);
if (sponsorBalance < sponsorReserve)
return insufReserveCode;
}
else
{
XRPAmount const reserve = this->reserve(adj);
if (accBalance < reserve)
return insufReserveCode;
}
}
else
{
XRPL_ASSERT(
!sponsorSle,
"xrpl::checkReserve : featureSponsor disabled and sponsorSle not provided");
XRPL_ASSERT(adj.accountCountDelta == 0, "xrpl::checkReserve : accountCountDelta is 0");
auto const reserve = ctx.view.fees().accountReserve(
(*this)->getFieldU32(sfOwnerCount) + adj.ownerCountDelta, 1);
if (accBalance < reserve)
return insufReserveCode;
}
return tesSUCCESS;
}
template <typename ViewT>
TER
AccountRootEntry<ViewT>::checkReserve(ApplyViewContext ctx, XRPAmount accBalance, Adjustment adj)
const
{
auto const sponsorExp = getEffectiveTxReserveSponsor(ctx, *this);
if (!sponsorExp)
return sponsorExp.error(); // LCOV_EXCL_LINE
std::optional<AccountRootEntry<ReadView>> sponsorSle;
if (*sponsorExp)
sponsorSle.emplace(**sponsorExp);
return checkReserve(ctx, accBalance, sponsorSle, adj);
}
template <typename ViewT>
void
AccountRootEntry<ViewT>::adjustOwnerCountSigned(
std::optional<AccountRootEntry<ApplyView>>& sponsorSle,
std::int32_t adjustment)
requires Base::kIsWritable
{
auto& view = this->applyView();
auto const j = this->journal();
if (view.rules().enabled(featureSponsor))
{
XRPL_ASSERT(this->exists(), "xrpl::adjustOwnerCountSigned : valid account sle");
if (!this->exists())
return; // LCOV_EXCL_LINE
auto const accountID = (*this)->getAccountID(sfAccount);
bool const validType = (*this)->getType() == ltACCOUNT_ROOT;
XRPL_ASSERT(validType, "xrpl::adjustOwnerCountSigned : valid account sle type");
if (!validType)
return; // LCOV_EXCL_LINE
XRPL_ASSERT(adjustment, "xrpl::adjustOwnerCountSigned : nonzero adjustment input");
OwnerCounts const currentOwnerCount(this->rawSle());
OwnerCounts totalOwnerCount(currentOwnerCount);
if (sponsorSle)
{
bool const validSponsorType = (*sponsorSle)->getType() == ltACCOUNT_ROOT;
XRPL_ASSERT(validSponsorType, "xrpl::adjustOwnerCountSigned : valid sponsor sle type");
if (!validSponsorType)
return; // LCOV_EXCL_LINE
auto const sponsorID = (*sponsorSle)->getAccountID(sfAccount);
totalOwnerCount.sponsored = detail::adjustOwnerCountImpl(
view, this->mutableRawSle(), sfSponsoredOwnerCount, accountID, adjustment, j);
{
OwnerCounts const sponsorCurrent(sponsorSle->rawSle());
OwnerCounts sponsorAdjustment(sponsorCurrent);
sponsorAdjustment.sponsoring = detail::adjustOwnerCountImpl(
view,
sponsorSle->mutableRawSle(),
sfSponsoringOwnerCount,
sponsorID,
adjustment,
j);
view.adjustOwnerCountHook(sponsorID, sponsorCurrent, sponsorAdjustment);
}
auto sponsorshipSle = view.peek(keylet::sponsorship(sponsorID, accountID));
if (sponsorshipSle && adjustment > 0)
{
// Only decrease the pre-funded ReserveCount on Sponsorship if we assign new
// objects. Removing/reassigning ownership of the object doesn't increase
// RemainingOwnerCount back. Don't call hook because this counter is not something
// that requires reserve (like other sf...OwnerCounts do).
detail::adjustOwnerCountImpl(
view, sponsorshipSle, sfRemainingOwnerCount, sponsorID, -adjustment, j);
}
}
totalOwnerCount.owner = detail::adjustOwnerCountImpl(
view, this->mutableRawSle(), sfOwnerCount, accountID, adjustment, j);
view.adjustOwnerCountHook(accountID, currentOwnerCount, totalOwnerCount);
}
else
{
XRPL_ASSERT(this->exists(), "xrpl::adjustOwnerCountSigned : valid account sle");
if (!this->exists())
return;
// the remaining are only asserts to preserve existing behavior
XRPL_ASSERT(!sponsorSle, "xrpl::adjustOwnerCountSigned : sponsor not enabled");
XRPL_ASSERT(
(*this)->getType() == ltACCOUNT_ROOT,
"xrpl::adjustOwnerCountSigned : valid account sle type");
XRPL_ASSERT(adjustment, "xrpl::adjustOwnerCount : nonzero adjustment input");
std::uint32_t const current{(*this)->getFieldU32(sfOwnerCount)};
AccountID const id = (**this)[sfAccount];
std::uint32_t const adjusted = detail::confineOwnerCount(current, adjustment, id, j);
OwnerCounts const currentOwnerCount(this->rawSle());
OwnerCounts finalOwnerCount(currentOwnerCount);
finalOwnerCount.owner = adjusted;
view.adjustOwnerCountHook(id, currentOwnerCount, finalOwnerCount);
(*this)->at(sfOwnerCount) = adjusted;
this->update();
}
}
template <typename ViewT>
void
AccountRootEntry<ViewT>::increaseOwnerCount(
std::optional<AccountRootEntry<ApplyView>>& sponsorSle,
std::uint32_t count)
requires Base::kIsWritable
{
XRPL_ASSERT(
count != 0 && count <= std::numeric_limits<std::int32_t>::max(),
"xrpl::increaseOwnerCount : count in signed delta range");
if (count == 0 || count > std::numeric_limits<std::int32_t>::max())
return; // LCOV_EXCL_LINE
adjustOwnerCountSigned(sponsorSle, static_cast<std::int32_t>(count));
}
template <typename ViewT>
void
AccountRootEntry<ViewT>::increaseOwnerCount(ApplyViewContext ctx, std::uint32_t count)
requires Base::kIsWritable
{
auto sponsorExp = getEffectiveTxReserveSponsor(ctx, *this);
// The sponsor's existence is validated by checkReserve/checkSponsor before
// any owner-count mutation, so loading it here cannot fail.
XRPL_ASSERT(
sponsorExp.has_value(), "xrpl::increaseOwnerCount : sponsor validated before mutation");
std::optional<AccountRootEntry<ApplyView>> sponsorSle;
if (sponsorExp && *sponsorExp)
sponsorSle.emplace(std::move(**sponsorExp));
increaseOwnerCount(sponsorSle, count);
}
template <typename ViewT>
void
AccountRootEntry<ViewT>::decreaseOwnerCount(
std::optional<AccountRootEntry<ApplyView>>& sponsorSle,
std::uint32_t count)
requires Base::kIsWritable
{
XRPL_ASSERT(
count != 0 && count <= std::numeric_limits<std::int32_t>::max(),
"xrpl::decreaseOwnerCount : count in signed delta range");
if (count == 0 || count > std::numeric_limits<std::int32_t>::max())
return; // LCOV_EXCL_LINE
adjustOwnerCountSigned(sponsorSle, -static_cast<std::int32_t>(count));
}
template class AccountRootEntry<ReadView>;
template class AccountRootEntry<ApplyView>;
} // namespace xrpl
+3 -4
View File
@@ -11,7 +11,6 @@
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
@@ -642,7 +641,7 @@ ammAccountHolds(ReadView const& view, AccountID const& ammAccountID, Asset const
[&](Issue const& issue) {
if (isXRP(issue))
{
if (auto const sle = AccountRootEntryR(ammAccountID, view))
if (auto const sle = view.read(keylet::account(ammAccountID)))
return (*sle)[sfBalance];
}
else if (
@@ -758,7 +757,7 @@ deleteAMMAccount(Sandbox& sb, Asset const& asset, Asset const& asset2, beast::Jo
}
auto const ammAccountID = (*ammSle)[sfAccount];
auto sleAMMRoot = AccountRootEntryW(ammAccountID, sb);
auto sleAMMRoot = sb.peek(keylet::account(ammAccountID));
if (!sleAMMRoot)
{
// LCOV_EXCL_START
@@ -796,7 +795,7 @@ deleteAMMAccount(Sandbox& sb, Asset const& asset, Asset const& asset2, beast::Jo
}
sb.erase(ammSle);
sleAMMRoot.erase();
sb.erase(sleAMMRoot);
return tesSUCCESS;
}
+300 -22
View File
@@ -9,7 +9,6 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/OwnerCounts.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/SponsorHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
@@ -18,6 +17,7 @@
#include <xrpl/protocol/Rate.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/STTx.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/XRPAmount.h>
#include <xrpl/protocol/digest.h>
@@ -38,19 +38,25 @@ isGlobalFrozen(ReadView const& view, AccountID const& issuer)
{
if (isXRP(issuer))
return false;
if (auto const sle = AccountRootEntryR(issuer, view))
if (auto const sle = view.read(keylet::account(issuer)))
return sle->isFlag(lsfGlobalFreeze);
return false;
}
namespace detail {
namespace {
// An owner count cannot be negative. If adjustment would cause a negative
// owner count, clamp the owner count at 0. Similarly for overflow. This
// adjustment allows the ownerCount to be adjusted up or down in multiple steps.
// If id != std::nullopt, then do error reporting.
//
// Returns adjusted owner count.
std::uint32_t
confineOwnerCount(
std::uint32_t currentOwnerCount,
std::int32_t ownerCountAdj,
std::optional<AccountID> const& id,
beast::Journal j)
std::optional<AccountID> const& id = std::nullopt,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
{
std::uint32_t totalOwnerCount{currentOwnerCount + ownerCountAdj};
if (ownerCountAdj > 0)
@@ -85,8 +91,10 @@ confineOwnerCount(
return totalOwnerCount;
}
// Returns the number of account reserves funded by this account: 1 for itself (0 if sponsored by
// another account) plus the count of accounts it sponsors.
std::uint32_t
accountCountImpl(AccountRootEntryR const& sle, std::int32_t accountCountAdj, beast::Journal j)
accountCountImpl(SLE::ConstRef sle, std::int32_t accountCountAdj, beast::Journal j)
{
bool const isSponsored = sle->isFieldPresent(sfSponsor);
std::int64_t const sponsoringAccountCount = sle->getFieldU32(sfSponsoringAccountCount);
@@ -123,25 +131,151 @@ adjustOwnerCountImpl(
{
std::uint32_t const currentOwnerCount = sle->at(sfield);
std::uint32_t const totalOwnerCount =
detail::confineOwnerCount(currentOwnerCount, ownerCountAdj, accID, j);
confineOwnerCount(currentOwnerCount, ownerCountAdj, accID, j);
sle->at(sfield) = totalOwnerCount;
view.update(sle);
return totalOwnerCount;
}
} // namespace detail
void
adjustOwnerCountSigned(
ApplyView& view,
SLE::Ref accountSle,
SLE::Ref sponsorSle,
std::int32_t adjustment,
beast::Journal j)
{
if (view.rules().enabled(featureSponsor))
{
XRPL_ASSERT(accountSle, "xrpl::adjustOwnerCountSigned : valid account sle");
if (!accountSle)
return; // LCOV_EXCL_LINE
auto const accountID = accountSle->getAccountID(sfAccount);
bool const validType = accountSle->getType() == ltACCOUNT_ROOT;
XRPL_ASSERT(validType, "xrpl::adjustOwnerCountSigned : valid account sle type");
if (!validType)
return; // LCOV_EXCL_LINE
XRPL_ASSERT(adjustment, "xrpl::adjustOwnerCountSigned : nonzero adjustment input");
OwnerCounts const currentOwnerCount(accountSle);
OwnerCounts totalOwnerCount(currentOwnerCount);
if (sponsorSle)
{
bool const validSponsorType = sponsorSle->getType() == ltACCOUNT_ROOT;
XRPL_ASSERT(validSponsorType, "xrpl::adjustOwnerCountSigned : valid sponsor sle type");
if (!validSponsorType)
return; // LCOV_EXCL_LINE
auto const sponsorID = sponsorSle->getAccountID(sfAccount);
totalOwnerCount.sponsored = adjustOwnerCountImpl(
view, accountSle, sfSponsoredOwnerCount, accountID, adjustment, j);
{
OwnerCounts const sponsorCurrent(sponsorSle);
OwnerCounts sponsorAdjustment(sponsorCurrent);
sponsorAdjustment.sponsoring = adjustOwnerCountImpl(
view, sponsorSle, sfSponsoringOwnerCount, sponsorID, adjustment, j);
view.adjustOwnerCountHook(sponsorID, sponsorCurrent, sponsorAdjustment);
}
auto sponsorshipSle = view.peek(keylet::sponsorship(sponsorID, accountID));
if (sponsorshipSle && adjustment > 0)
{
// Only decrease the pre-funded ReserveCount on Sponsorship if we assign new
// objects. Removing/reassigning ownership of the object doesn't increase
// RemainingOwnerCount back. Don't call hook because this counter is not something
// that requires reserve (like other sf...OwnerCounts do).
adjustOwnerCountImpl(
view, sponsorshipSle, sfRemainingOwnerCount, sponsorID, -adjustment, j);
}
}
totalOwnerCount.owner =
adjustOwnerCountImpl(view, accountSle, sfOwnerCount, accountID, adjustment, j);
view.adjustOwnerCountHook(accountID, currentOwnerCount, totalOwnerCount);
}
else
{
XRPL_ASSERT(accountSle, "xrpl::adjustOwnerCountSigned : valid account sle");
if (!accountSle)
return;
// the remaining are only asserts to preserve existing behavior
XRPL_ASSERT(sponsorSle == nullptr, "xrpl::adjustOwnerCountSigned : sponsor not enabled");
XRPL_ASSERT(
accountSle->getType() == ltACCOUNT_ROOT,
"xrpl::adjustOwnerCountSigned : valid account sle type");
XRPL_ASSERT(adjustment, "xrpl::adjustOwnerCount : nonzero adjustment input");
std::uint32_t const current{accountSle->getFieldU32(sfOwnerCount)};
AccountID const id = (*accountSle)[sfAccount];
std::uint32_t const adjusted = confineOwnerCount(current, adjustment, id, j);
OwnerCounts const currentOwnerCount(accountSle);
OwnerCounts finalOwnerCount(currentOwnerCount);
finalOwnerCount.owner = adjusted;
view.adjustOwnerCountHook(id, currentOwnerCount, finalOwnerCount);
accountSle->at(sfOwnerCount) = adjusted;
view.update(accountSle);
}
}
} // namespace
std::uint32_t
ownerCount(SLE::ConstRef sle, beast::Journal j, std::int32_t ownerCountAdj)
{
XRPL_ASSERT(sle && sle->getType() == ltACCOUNT_ROOT, "xrpl::ownerCount : sle is account root");
AccountID const id = sle->getAccountID(sfAccount);
std::uint32_t const currentOwnerCount = sle->at(sfOwnerCount);
std::uint32_t const sponsoredOwnerCount = sle->at(sfSponsoredOwnerCount);
std::uint32_t const sponsoringOwnerCount = sle->at(sfSponsoringOwnerCount);
XRPL_ASSERT(
currentOwnerCount >= sponsoredOwnerCount,
"xrpl::ownerCount : OwnerCount must be greater than or equal to SponsoredOwnerCount");
std::int64_t deltaCount =
static_cast<std::int64_t>(ownerCountAdj) - sponsoredOwnerCount + sponsoringOwnerCount;
if (deltaCount > std::numeric_limits<std::int32_t>::max())
{
// LCOV_EXCL_START
deltaCount = std::numeric_limits<std::int32_t>::max();
JLOG(j.fatal()) << "Account " << id << " delta count exceeds max, "
<< "adjustment: " << ownerCountAdj
<< ", sponsoredCount: " << sponsoredOwnerCount
<< ", sponsoringOwnerCount: " << sponsoringOwnerCount;
// LCOV_EXCL_STOP
}
else if (deltaCount < std::numeric_limits<std::int32_t>::min())
{
// LCOV_EXCL_START
deltaCount = std::numeric_limits<std::int32_t>::min();
JLOG(j.fatal()) << "Account " << id << " delta count is below min, "
<< "adjustment: " << ownerCountAdj
<< ", sponsoredCount: " << sponsoredOwnerCount
<< ", sponsoringCount: " << sponsoringOwnerCount;
// LCOV_EXCL_STOP
}
return confineOwnerCount(currentOwnerCount, deltaCount);
}
XRPAmount
xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j)
{
auto const sle = AccountRootEntryR(id, view);
if (!sle.exists())
auto const sle = view.read(keylet::account(id));
if (sle == nullptr)
return beast::kZero;
// Return balance minus reserve
std::uint32_t const currentOwnerCount = detail::confineOwnerCount(
view.ownerCountHook(id, OwnerCounts(sle.rawSle())).count(), ownerCountAdj);
std::uint32_t const currentAccountCount = detail::accountCountImpl(sle, 0, j);
std::uint32_t const currentOwnerCount =
confineOwnerCount(view.ownerCountHook(id, OwnerCounts(sle)).count(), ownerCountAdj);
std::uint32_t const currentAccountCount = accountCountImpl(sle, 0, j);
// Pseudo-accounts have no reserve requirement
auto const reserve = isPseudoAccount(sle)
@@ -166,7 +300,7 @@ xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj,
Rate
transferRate(ReadView const& view, AccountID const& issuer)
{
auto const sle = AccountRootEntryR(issuer, view);
auto const sle = view.read(keylet::account(issuer));
if (sle && sle->isFieldPresent(sfTransferRate))
return Rate{sle->getFieldU32(sfTransferRate)};
@@ -174,10 +308,57 @@ transferRate(ReadView const& view, AccountID const& issuer)
return kParityRate;
}
void
increaseOwnerCount(
ApplyView& view,
SLE::Ref accountSle,
SLE::Ref sponsorSle,
std::uint32_t count,
beast::Journal j)
{
XRPL_ASSERT(
count != 0 && count <= std::numeric_limits<std::int32_t>::max(),
"xrpl::increaseOwnerCount : count in signed delta range");
if (count == 0 || count > std::numeric_limits<std::int32_t>::max())
return; // LCOV_EXCL_LINE
adjustOwnerCountSigned(view, accountSle, sponsorSle, static_cast<std::int32_t>(count), j);
}
void
increaseOwnerCount(ApplyViewContext ctx, SLE::Ref accountSle, std::uint32_t count, beast::Journal j)
{
auto const sponsorExp = getEffectiveTxReserveSponsor(ctx, accountSle);
// The sponsor's existence is validated by checkReserve/checkSponsor before
// any owner-count mutation, so loading it here cannot fail.
XRPL_ASSERT(
sponsorExp.has_value(), "xrpl::increaseOwnerCount : sponsor validated before mutation");
increaseOwnerCount(ctx.view, accountSle, sponsorExp ? *sponsorExp : SLE::pointer(), count, j);
}
void
decreaseOwnerCount(
ApplyView& view,
SLE::Ref accountSle,
SLE::Ref sponsorSle,
std::uint32_t count,
beast::Journal j)
{
XRPL_ASSERT(
count != 0 && count <= std::numeric_limits<std::int32_t>::max(),
"xrpl::decreaseOwnerCount : count in signed delta range");
if (count == 0 || count > std::numeric_limits<std::int32_t>::max())
return; // LCOV_EXCL_LINE
adjustOwnerCountSigned(view, accountSle, sponsorSle, -static_cast<std::int32_t>(count), j);
}
void
decreaseOwnerCountForObject(
ApplyView& view,
AccountRootEntryW& accountSle,
SLE::Ref accountSle,
SLE::Ref objectSle,
std::uint32_t count,
beast::Journal j)
@@ -191,8 +372,8 @@ decreaseOwnerCountForObject(
if (!validObjectType)
return; // LCOV_EXCL_LINE
auto sponsorSle = getLedgerEntryReserveSponsor(view, objectSle);
accountSle.decreaseOwnerCount(sponsorSle, count);
SLE::Ref sponsorSle = getLedgerEntryReserveSponsor(view, objectSle);
decreaseOwnerCount(view, accountSle, sponsorSle, count, j);
}
void
@@ -212,10 +393,107 @@ adjustLoanBrokerOwnerCount(
if (delta == 0)
return; // LCOV_EXCL_LINE
detail::adjustOwnerCountImpl(
adjustOwnerCountImpl(
view, brokerSle, sfOwnerCount, brokerSle->getAccountID(sfAccount), delta, j);
}
XRPAmount
accountReserve(ReadView const& view, SLE::ConstRef sle, beast::Journal j, Adjustment adj)
{
XRPL_ASSERT(sle && sle->getType() == ltACCOUNT_ROOT, "xrpl::accountReserve : valid sle");
if (!view.rules().enabled(featureSponsor))
{
XRPL_ASSERT(adj.accountCountDelta == 0, "xrpl::accountReserve : no account count delta");
return view.fees().accountReserve(sle->getFieldU32(sfOwnerCount) + adj.ownerCountDelta, 1);
}
std::uint32_t const currentOwnerCount = ownerCount(sle, j, adj.ownerCountDelta);
std::uint32_t const currentAccountCount = accountCountImpl(sle, adj.accountCountDelta, j);
return view.fees().accountReserve(currentOwnerCount, currentAccountCount);
}
TER
checkReserve(
ApplyViewContext ctx,
SLE::ConstRef accSle,
XRPAmount accBalance,
SLE::ConstRef sponsorSle,
Adjustment adj,
beast::Journal j,
TER insufReserveCode)
{
// TODO: swap to assert after fixCleanup3_2_0 is retired
if (!accSle || accSle->getType() != ltACCOUNT_ROOT)
return tefINTERNAL; // LCOV_EXCL_LINE
XRPL_ASSERT(
!isTesSuccess(insufReserveCode), "xrpl::checkReserve : insufReserveCode is not tesSUCCESS");
if (ctx.view.rules().enabled(featureSponsor))
{
if (sponsorSle)
{
if (sponsorSle->getType() != ltACCOUNT_ROOT)
return tefINTERNAL; // LCOV_EXCL_LINE
auto const sle = ctx.view.read(
keylet::sponsorship(
sponsorSle->getAccountID(sfAccount), accSle->getAccountID(sfAccount)));
// A reserve-sponsored tx must carry a sponsor signature
// (cosigning path) and/or have a pre-existing sponsorship SLE
// (prefunded path). Absence of both is an internal invariant break.
if (isReserveSponsored(ctx.tx) && !sle && !ctx.tx.isFieldPresent(sfSponsorSignature))
return tecINTERNAL; // LCOV_EXCL_LINE
if (sle)
{
auto const ownerCountAllowed = sle->getFieldU32(sfRemainingOwnerCount);
if (adj.ownerCountDelta > 0 &&
ownerCountAllowed < static_cast<std::uint32_t>(adj.ownerCountDelta))
return insufReserveCode;
}
auto const sponsorBalance = sponsorSle->getFieldAmount(sfBalance).xrp();
XRPAmount const sponsorReserve = accountReserve(ctx.view, sponsorSle, j, adj);
if (sponsorBalance < sponsorReserve)
return insufReserveCode;
}
else
{
XRPAmount const reserve = accountReserve(ctx.view, accSle, j, adj);
if (accBalance < reserve)
return insufReserveCode;
}
}
else
{
XRPL_ASSERT(
!sponsorSle,
"xrpl::checkReserve : featureSponsor disabled and sponsorSle not provided");
XRPL_ASSERT(adj.accountCountDelta == 0, "xrpl::checkReserve : accountCountDelta is 0");
auto const reserve = ctx.view.fees().accountReserve(
accSle->getFieldU32(sfOwnerCount) + adj.ownerCountDelta, 1);
if (accBalance < reserve)
return insufReserveCode;
}
return tesSUCCESS;
}
TER
checkReserve(
ApplyViewContext ctx,
SLE::ConstRef accSle,
XRPAmount accBalance,
Adjustment adj,
beast::Journal j)
{
auto const sponsorExp = getEffectiveTxReserveSponsor(ctx, accSle);
if (!sponsorExp)
return sponsorExp.error(); // LCOV_EXCL_LINE
return checkReserve(ctx, accSle, accBalance, *sponsorExp, adj, j);
}
// ----------------------------------------------------
AccountID
@@ -229,7 +507,7 @@ pseudoAccountAddress(ReadView const& view, UInt256 const& pseudoOwnerKey)
auto const hash = sha512Half(i, view.header().parentHash, pseudoOwnerKey);
rsh(hash.data(), hash.size());
AccountID const ret = AccountID::fromRaw(static_cast<RipeshaHasher::result_type>(rsh));
if (!AccountRootEntryR(ret, view).exists())
if (!view.read(keylet::account(ret)))
return ret;
}
return beast::kZero;
@@ -268,7 +546,7 @@ getPseudoAccountFields()
}
[[nodiscard]] bool
isPseudoAccount(AccountRootEntryR const& sleAcct)
isPseudoAccount(SLE::const_pointer sleAcct)
{
// Intentionally use defensive coding here because it's cheap and makes the
// semantics of true return value clean.
@@ -321,9 +599,9 @@ createPseudoAccount(ApplyView& view, UInt256 const& pseudoOwnerKey, SField const
}
[[nodiscard]] TER
checkDestinationAndTag(AccountRootEntryR const& toSle, bool hasDestinationTag)
checkDestinationAndTag(SLE::ConstRef toSle, bool hasDestinationTag)
{
if (!toSle.exists())
if (toSle == nullptr)
return tecNO_DST;
// The tag is basically account-specific information we don't
@@ -7,7 +7,6 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
@@ -82,7 +81,7 @@ deleteSLE(ApplyView& view, SLE::Ref sleCredential, beast::Journal j)
auto delSLE = [&view, &sleCredential, j](
AccountID const& account, SField const& node, bool isOwner) -> TER {
auto sleAccount = AccountRootEntryW(account, view);
auto const sleAccount = view.peek(keylet::account(account));
if (!sleAccount)
{
// LCOV_EXCL_START
+11 -15
View File
@@ -7,7 +7,6 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -207,7 +206,7 @@ authorizeMPToken(
std::uint32_t flags,
std::optional<AccountID> holderID)
{
auto sleAcct = AccountRootEntryW(account, ctx.view, journal);
auto const sleAcct = ctx.view.peek(keylet::account(account));
if (!sleAcct)
return tecINTERNAL; // LCOV_EXCL_LINE
@@ -243,10 +242,10 @@ authorizeMPToken(
// - create the MPToken object for the holder
// A reserve sponsor only covers tx.Account's own objects.
auto sponsorExp = getEffectiveTxReserveSponsor(ctx, sleAcct);
auto const sponsorExp = getEffectiveTxReserveSponsor(ctx, sleAcct);
if (!sponsorExp)
return sponsorExp.error(); // LCOV_EXCL_LINE
auto& sponsorSle = *sponsorExp;
auto const sponsorSle = *sponsorExp;
// The reserve that is required to create the MPToken. Note
// that although the reserve increases with every item
@@ -256,10 +255,10 @@ authorizeMPToken(
// The "free-tier" shortcut (ownerCount < 2) does not apply once a sponsor is on
// the tx — the sponsor must always cover the reserve (via balance or prefunded
// budget), so this check always runs for sponsored transactions.
if (sponsorSle || sleAcct.ownerCount() >= 2)
if (sponsorSle || ownerCount(sleAcct, journal) >= 2)
{
if (auto const ret =
sleAcct.checkReserve(ctx, priorBalance, sponsorSle, {.ownerCountDelta = 1});
if (auto const ret = checkReserve(
ctx, sleAcct, priorBalance, sponsorSle, {.ownerCountDelta = 1}, journal);
!isTesSuccess(ret))
return ret;
}
@@ -286,8 +285,8 @@ authorizeMPToken(
ctx.view.insert(mptoken);
// Update owner count.
sleAcct.increaseOwnerCount(sponsorSle, 1);
addSponsorToLedgerEntry(mptoken, sponsorSle ? sponsorSle->rawSle() : SLE::const_pointer{});
increaseOwnerCount(ctx.view, sleAcct, sponsorSle, 1, journal);
addSponsorToLedgerEntry(mptoken, sponsorSle);
return tesSUCCESS;
}
@@ -416,7 +415,7 @@ requireAuth(
}
// requireAuth is recursive if the issuer is a vault pseudo-account
auto const sleIssuer = AccountRootEntryR(mptIssuer, view);
auto const sleIssuer = view.read(keylet::account(mptIssuer));
if (!sleIssuer)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -1021,16 +1020,13 @@ checkCreateMPT(
{
return err;
}
auto sleAcct = AccountRootEntryW(holder, view, j);
auto const sleAcct = view.peek(keylet::account(holder));
if (!sleAcct)
{
return tecINTERNAL;
}
std::optional<AccountRootEntryW> sponsorAccSle;
if (sponsorSle)
sponsorAccSle.emplace(sponsorSle->getAccountID(sfAccount), view);
sleAcct.increaseOwnerCount(sponsorAccSle, 1);
increaseOwnerCount(view, sleAcct, sponsorSle, 1, j);
}
return tesSUCCESS;
}
@@ -7,7 +7,6 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
@@ -856,7 +855,7 @@ tokenOfferCreatePreclaim(
if (nftIssuer != acctID && ((nftFlags & nft::kFlagTransferable) == 0))
{
auto const root = AccountRootEntryR(nftIssuer, view);
auto const root = view.read(keylet::account(nftIssuer));
XRPL_ASSERT(root, "xrpl::nft::tokenOfferCreatePreclaim : non-null account");
if (auto minter = (*root)[~sfNFTokenMinter]; minter != acctID)
@@ -887,7 +886,7 @@ tokenOfferCreatePreclaim(
{
// If a destination is specified, the destination must already be in
// the ledger.
auto const sleDst = AccountRootEntryR(*dest, view);
auto const sleDst = view.read(keylet::account(*dest));
if (!sleDst)
return tecNO_DST;
@@ -899,7 +898,7 @@ tokenOfferCreatePreclaim(
if (owner)
{
auto const sleOwner = AccountRootEntryR(*owner, view);
auto const sleOwner = view.read(keylet::account(*owner));
// defensively check
// it should not be possible to specify owner that doesn't exist
@@ -938,8 +937,9 @@ tokenOfferCreateApply(
beast::Journal j,
std::uint32_t txFlags)
{
if (auto const acct = AccountRootEntryW(acctID, view, j);
priorBalance < acct.reserve({.ownerCountDelta = 1}))
Keylet const acctKeylet = keylet::account(acctID);
if (auto const acct = view.read(acctKeylet);
priorBalance < accountReserve(view, acct, j, {.ownerCountDelta = 1}))
return tecINSUFFICIENT_RESERVE;
auto const offerID = keylet::nftokenOffer(acctID, seqProxy);
@@ -1008,7 +1008,7 @@ checkTrustlineAuthorized(
if (view.rules().enabled(fixEnforceNFTokenTrustlineV2))
{
auto const issuerAccount = AccountRootEntryR(issue.account, view);
auto const issuerAccount = view.read(keylet::account(issue.account));
if (!issuerAccount)
{
JLOG(j.debug()) << "xrpl::nft::checkTrustlineAuthorized: can't "
@@ -1060,7 +1060,7 @@ checkTrustlineDeepFrozen(
if (view.rules().enabled(featureDeepFreeze))
{
auto const issuerAccount = AccountRootEntryR(issue.account, view);
auto const issuerAccount = view.read(keylet::account(issue.account));
if (!issuerAccount)
{
JLOG(j.debug()) << "xrpl::nft::checkTrustlineDeepFrozen: can't "
@@ -6,7 +6,6 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
@@ -52,7 +51,7 @@ closeChannel(SLE::Ref slep, ApplyView& view, UInt256 const& key, beast::Journal
}
// Transfer amount back to owner, decrement owner count
auto sle = AccountRootEntryW(src, view);
auto const sle = view.peek(keylet::account(src));
if (!sle)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -60,7 +59,7 @@ closeChannel(SLE::Ref slep, ApplyView& view, UInt256 const& key, beast::Journal
(*slep)[sfAmount] >= (*slep)[sfBalance], "xrpl::closeChannel : minimum channel amount");
(*sle)[sfBalance] = (*sle)[sfBalance] + (*slep)[sfAmount] - (*slep)[sfBalance];
decreaseOwnerCountForObject(view, sle, slep, 1, j);
sle.update();
view.update(sle);
// Remove PayChan from ledger
view.erase(slep);
@@ -7,7 +7,6 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/SponsorHelpers.h>
@@ -134,14 +133,14 @@ isFrozen(
{
if (isXRP(currency))
return false;
auto const sleIssuer = AccountRootEntryR(issuer, view);
if (sleIssuer && sleIssuer->isFlag(lsfGlobalFreeze))
auto sle = view.read(keylet::account(issuer));
if (sle && sle->isFlag(lsfGlobalFreeze))
return true;
if (issuer != account)
{
// Check if the issuer froze the line
auto const sleLine = view.read(keylet::trustLine(account, issuer, currency));
if (sleLine && sleLine->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
sle = view.read(keylet::trustLine(account, issuer, currency));
if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
return true;
}
return false;
@@ -239,7 +238,7 @@ trustCreate(
XRPL_ASSERT(
sleAccount->getAccountID(sfAccount) == (bSetHigh ? uHighAccountID : uLowAccountID),
"xrpl::trustCreate : matching account ID");
auto const slePeer = AccountRootEntryW(bSetHigh ? uLowAccountID : uHighAccountID, view);
auto const slePeer = view.peek(keylet::account(bSetHigh ? uLowAccountID : uHighAccountID));
if (!slePeer)
return tecNO_TARGET;
@@ -284,11 +283,7 @@ trustCreate(
}
sleRippleState->setFieldU32(sfFlags, uFlags);
AccountRootEntryW accountSle(bSetHigh ? uHighAccountID : uLowAccountID, view, j);
std::optional<AccountRootEntryW> sponsorAccSle;
if (sponsorSle)
sponsorAccSle.emplace(sponsorSle->getAccountID(sfAccount), view);
accountSle.increaseOwnerCount(sponsorAccSle, 1);
increaseOwnerCount(view, sleAccount, sponsorSle, 1, j);
addSponsorToLedgerEntry(sleRippleState, sponsorSle, bSetHigh ? sfHighSponsor : sfLowSponsor);
@@ -354,7 +349,7 @@ updateTrustLine(
if (!state)
return false;
auto sle = AccountRootEntryW(sender, view, j);
auto sle = view.peek(keylet::account(sender));
if (!sle)
return false;
@@ -381,9 +376,9 @@ updateTrustLine(
{
// VFALCO Where is the line being deleted?
// Clear the reserve of the sender, possibly delete the line!
auto currentSponsor =
auto const currentSponsor =
getLedgerEntryReserveSponsor(view, state, bSenderHigh ? sfHighSponsor : sfLowSponsor);
sle.decreaseOwnerCount(currentSponsor, 1);
decreaseOwnerCount(view, sle, currentSponsor, 1, j);
// Clear reserve flag.
state->clearFlag(senderReserveFlag);
@@ -469,7 +464,7 @@ issueIOU(
finalBalance.get<Issue>().account = noAccount();
auto receiverAccount = AccountRootEntryW(account, view);
auto const receiverAccount = view.peek(keylet::account(account));
if (!receiverAccount)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -481,7 +476,7 @@ issueIOU(
issue.account,
account,
index.key,
receiverAccount.mutableRawSle(),
receiverAccount,
false,
noRipple,
false,
@@ -584,7 +579,7 @@ requireAuth(ReadView const& view, Issue const& issue, AccountID const& account,
// If this is a weak or legacy check, or if the account has a line, fail if
// auth is required and not set on the line
if (auto const issuerAccount = AccountRootEntryR(issue.account, view);
if (auto const issuerAccount = view.read(keylet::account(issue.account));
issuerAccount && issuerAccount->isFlag(lsfRequireAuth))
{
if (trustLine)
@@ -614,8 +609,8 @@ canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, Acc
auto const& issuerId = issue.getIssuer();
if (issuerId == from || issuerId == to)
return tesSUCCESS;
auto const sleIssuer = AccountRootEntryR(issuerId, view);
if (!sleIssuer.exists())
auto const sleIssuer = view.read(keylet::account(issuerId));
if (sleIssuer == nullptr)
return tefINTERNAL; // LCOV_EXCL_LINE
auto const isRippleDisabled = [&](AccountID account) -> bool {
@@ -670,8 +665,8 @@ addEmptyHolding(
if (isGlobalFrozen(ctx.view, issuerId))
return tecFROZEN; // LCOV_EXCL_LINE
auto const sleSrc = AccountRootEntryW(srcId, ctx.view);
auto sleDst = AccountRootEntryW(dstId, ctx.view, journal);
auto const sleSrc = ctx.view.peek(keylet::account(srcId));
auto const sleDst = ctx.view.peek(keylet::account(dstId));
if (!sleDst || !sleSrc)
return tefINTERNAL; // LCOV_EXCL_LINE
// Create path: DefaultRipple is still required. terNO_RIPPLE is
@@ -686,14 +681,20 @@ addEmptyHolding(
return tecDUPLICATE;
// A reserve sponsor only covers tx.Account's own objects.
auto sponsorExp = getEffectiveTxReserveSponsor(ctx, sleDst);
auto const sponsorExp = getEffectiveTxReserveSponsor(ctx, sleDst);
if (!sponsorExp)
return sponsorExp.error(); // LCOV_EXCL_LINE
auto& sponsorSle = *sponsorExp;
auto const sponsorSle = *sponsorExp;
// Can the account cover the trust line reserve ?
if (auto const ret = sleDst.checkReserve(
ctx, priorBalance, sponsorSle, {.ownerCountDelta = 1}, tecNO_LINE_INSUF_RESERVE);
if (auto const ret = checkReserve(
ctx,
sleDst,
priorBalance,
sponsorSle,
{.ownerCountDelta = 1},
journal,
tecNO_LINE_INSUF_RESERVE);
!isTesSuccess(ret))
{
return ret;
@@ -705,7 +706,7 @@ addEmptyHolding(
srcId,
dstId,
index.key,
sleDst.mutableRawSle(),
sleDst,
/*bAuth=*/false,
/*bNoRipple=*/true,
/*bFreeze=*/false,
@@ -714,7 +715,7 @@ addEmptyHolding(
/*saLimit=*/STAmount{Issue{currency, dstId}},
/*uQualityIn=*/0,
/*uQualityOut=*/0,
sponsorSle ? sponsorSle->mutableRawSle() : SLE::pointer{},
sponsorSle,
journal);
}
@@ -727,7 +728,7 @@ removeEmptyHolding(
{
if (issue.native())
{
auto const sle = AccountRootEntryW(accountID, ctx.view);
auto const sle = ctx.view.read(keylet::account(accountID));
if (!sle)
return tecINTERNAL; // LCOV_EXCL_LINE
@@ -752,14 +753,13 @@ removeEmptyHolding(
if (line->isFlag(lsfLowReserve))
{
// Clear reserve for low account.
auto sleLowAccount =
AccountRootEntryW(line->at(sfLowLimit)->getIssuer(), ctx.view, journal);
auto sleLowAccount = ctx.view.peek(keylet::account(line->at(sfLowLimit)->getIssuer()));
if (!sleLowAccount)
return tecINTERNAL; // LCOV_EXCL_LINE
auto currentLowSponsor = getLedgerEntryReserveSponsor(ctx.view, line, sfLowSponsor);
auto const currentLowSponsor = getLedgerEntryReserveSponsor(ctx.view, line, sfLowSponsor);
sleLowAccount.decreaseOwnerCount(currentLowSponsor, 1);
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.
@@ -770,14 +770,13 @@ removeEmptyHolding(
if (line->isFlag(lsfHighReserve))
{
// Clear reserve for high account.
auto sleHighAccount =
AccountRootEntryW(line->at(sfHighLimit)->getIssuer(), ctx.view, journal);
auto sleHighAccount = ctx.view.peek(keylet::account(line->at(sfHighLimit)->getIssuer()));
if (!sleHighAccount)
return tecINTERNAL; // LCOV_EXCL_LINE
auto currentHighSponsor = getLedgerEntryReserveSponsor(ctx.view, line, sfHighSponsor);
auto const currentHighSponsor = getLedgerEntryReserveSponsor(ctx.view, line, sfHighSponsor);
sleHighAccount.decreaseOwnerCount(currentHighSponsor, 1);
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.
@@ -806,8 +805,8 @@ deleteAMMTrustLine(
auto const& [low, high] = std::minmax(
sleState->getFieldAmount(sfLowLimit).getIssuer(),
sleState->getFieldAmount(sfHighLimit).getIssuer());
auto sleLow = AccountRootEntryW(low, view, j);
auto sleHigh = AccountRootEntryW(high, view, j);
auto sleLow = view.peek(keylet::account(low));
auto sleHigh = view.peek(keylet::account(high));
if (!sleLow || !sleHigh)
return tecINTERNAL; // LCOV_EXCL_LINE
@@ -826,7 +825,7 @@ deleteAMMTrustLine(
if (ammAccountID && (low != *ammAccountID && high != *ammAccountID))
return terNO_AMM;
auto sponsorSle =
auto const sponsorSle =
getLedgerEntryReserveSponsor(view, sleState, !ammLow ? sfLowSponsor : sfHighSponsor);
if (auto const ter = trustDelete(view, sleState, low, high, j); !isTesSuccess(ter))
@@ -839,7 +838,7 @@ deleteAMMTrustLine(
if (!sleState->isFlag(uFlags))
return tecINTERNAL; // LCOV_EXCL_LINE
(!ammLow ? sleLow : sleHigh).decreaseOwnerCount(sponsorSle, 1);
decreaseOwnerCount(view, !ammLow ? sleLow : sleHigh, sponsorSle, 1, j);
return tesSUCCESS;
}
+18 -19
View File
@@ -3,7 +3,6 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/OracleHelpers.h>
#include <xrpl/ledger/helpers/ProposalHelpers.h>
@@ -77,7 +76,7 @@ getTxReserveSponsorID(STTx const& tx)
return {};
}
std::expected<std::optional<AccountRootEntryW>, TER>
std::expected<SLE::pointer, TER>
getTxReserveSponsor(ApplyViewContext ctx)
{
auto const sponsorID = getTxReserveSponsorID(ctx.tx);
@@ -86,17 +85,17 @@ getTxReserveSponsor(ApplyViewContext ctx)
XRPL_ASSERT(
ctx.view.rules().enabled(featureSponsor),
"xrpl::getTxReserveSponsor : sponsor exists + Sponsor enabled");
auto sle = AccountRootEntryW(*sponsorID, ctx.view);
auto sle = ctx.view.peek(keylet::account(*sponsorID));
// already checked in Transactor::checkSponsor
if (!sle.exists())
if (!sle)
return std::unexpected(tecINTERNAL); // LCOV_EXCL_LINE
return sle;
}
return std::nullopt;
return SLE::pointer();
}
std::expected<std::optional<AccountRootEntryR>, TER>
std::expected<SLE::const_pointer, TER>
getTxReserveSponsor(ReadView const& view, STTx const& tx)
{
auto const sponsorID = getTxReserveSponsorID(tx);
@@ -105,18 +104,18 @@ getTxReserveSponsor(ReadView const& view, STTx const& tx)
XRPL_ASSERT(
view.rules().enabled(featureSponsor),
"xrpl::getTxReserveSponsor : sponsor exists + Sponsor enabled");
auto sle = AccountRootEntryR(*sponsorID, view);
auto sle = view.read(keylet::account(*sponsorID));
// already checked in Transactor::checkSponsor
if (!sle.exists())
if (!sle)
return std::unexpected(tecINTERNAL); // LCOV_EXCL_LINE
return sle;
}
return std::nullopt;
return SLE::pointer();
}
std::expected<std::optional<AccountRootEntryW>, TER>
getEffectiveTxReserveSponsor(ApplyViewContext ctx, AccountRootEntryR const& accountSle)
std::expected<SLE::pointer, TER>
getEffectiveTxReserveSponsor(ApplyViewContext ctx, SLE::ConstRef accountSle)
{
// A reserve sponsor only covers tx.Account's own objects.
if (ctx.view.rules().enabled(fixCleanup3_2_0))
@@ -134,7 +133,7 @@ getEffectiveTxReserveSponsor(ApplyViewContext ctx, AccountRootEntryR const& acco
}
if (isPseudoAccount(accountSle) || accountSle->getAccountID(sfAccount) != ctx.tx[sfAccount])
return std::nullopt;
return SLE::pointer();
return getTxReserveSponsor(ctx);
}
@@ -152,7 +151,7 @@ getLedgerEntryReserveSponsorID(SLE::ConstRef sle, SF_ACCOUNT const& field)
return {};
}
std::optional<AccountRootEntryW>
SLE::pointer
getLedgerEntryReserveSponsor(ApplyView& view, SLE::ConstRef sle, SF_ACCOUNT const& field)
{
auto const sponsorID = getLedgerEntryReserveSponsorID(sle, field);
@@ -161,9 +160,9 @@ getLedgerEntryReserveSponsor(ApplyView& view, SLE::ConstRef sle, SF_ACCOUNT cons
XRPL_ASSERT(
view.rules().enabled(featureSponsor),
"xrpl::getLedgerEntryReserveSponsor : sponsor exists + Sponsor enabled");
return AccountRootEntryW(*sponsorID, view);
return view.peek(keylet::account(*sponsorID));
}
return std::nullopt;
return {};
}
void
@@ -186,16 +185,16 @@ addSponsorToLedgerEntry(SLE::Ref sle, SLE::ConstRef sponsorSle, SF_ACCOUNT const
void
addSponsorToLedgerEntry(ApplyViewContext ctx, SLE::Ref sle, SF_ACCOUNT const& field)
{
// getTxReserveSponsor yields nullopt when the tx is not reserve-sponsored,
// so addSponsorToLedgerEntry becomes a no-op then. The error case
// (tecINTERNAL) is an already-checked invariant; skip stamping.
// getTxReserveSponsor yields a null pointer when the tx is not
// reserve-sponsored, so addSponsorToLedgerEntry becomes a no-op then. The
// error case (tecINTERNAL) is an already-checked invariant; skip stamping.
auto const sponsorSle = getTxReserveSponsor(ctx);
if (sponsorSle && *sponsorSle)
{
XRPL_ASSERT(
ctx.view.rules().enabled(featureSponsor),
"xrpl::addSponsorToLedgerEntry : sponsor exists + Sponsor enabled");
addSponsorToLedgerEntry(sle, (**sponsorSle).rawSle(), field);
addSponsorToLedgerEntry(sle, *sponsorSle, field);
}
}
+57 -30
View File
@@ -7,7 +7,6 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
@@ -19,8 +18,10 @@
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/MPTAmount.h>
#include <xrpl/protocol/MPTIssue.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/Quality.h>
#include <xrpl/protocol/Rate.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STAmount.h>
@@ -294,7 +295,7 @@ getLineIfUsable(
// we need to check if the associated assets have been frozen
if (view.rules().enabled(fixFrozenLPTokenTransfer))
{
auto const sleIssuer = AccountRootEntryR(issuer, view);
auto const sleIssuer = view.read(keylet::account(issuer));
if (!sleIssuer)
{
return nullptr; // LCOV_EXCL_LINE
@@ -563,7 +564,7 @@ canAddHolding(ReadView const& view, Issue const& issue)
return tesSUCCESS; // No special checks for XRP
}
auto const issuer = AccountRootEntryR(issue.getIssuer(), view);
auto const issuer = view.read(keylet::account(issue.getIssuer()));
if (!issuer)
{
return terNO_ACCOUNT;
@@ -739,8 +740,6 @@ directSendNoFeeIOU(
auto const senderFreezeFlag = bSenderHigh ? lsfHighFreeze : lsfLowFreeze;
auto const receiverReserveFlag = bSenderHigh ? lsfLowReserve : lsfHighReserve;
AccountRootEntryW senderSle(uSenderID, view, j);
// FIXME This NEEDS to be cleaned up and simplified. It's impossible
// for anyone to understand.
if (saBefore > beast::kZero
@@ -749,7 +748,8 @@ directSendNoFeeIOU(
// Sender is zero or negative.
&& sleRippleState->isFlag(senderReserveFlag)
// Sender reserve is set.
&& sleRippleState->isFlag(senderNoRippleFlag) != senderSle->isFlag(lsfDefaultRipple) &&
&& sleRippleState->isFlag(senderNoRippleFlag) !=
view.read(keylet::account(uSenderID))->isFlag(lsfDefaultRipple) &&
!sleRippleState->isFlag(senderFreezeFlag) &&
!sleRippleState->getFieldAmount(bSenderHigh ? sfHighLimit : sfLowLimit)
// Sender trust limit is 0.
@@ -760,9 +760,9 @@ directSendNoFeeIOU(
// Sender quality out is 0.
{
// Clear the reserve of the sender, possibly delete the line!
auto currentSponsor = getLedgerEntryReserveSponsor(
auto const currentSponsor = getLedgerEntryReserveSponsor(
view, sleRippleState, !bSenderHigh ? sfLowSponsor : sfHighSponsor);
senderSle.decreaseOwnerCount(currentSponsor, 1);
decreaseOwnerCount(view, view.peek(keylet::account(uSenderID)), currentSponsor, 1, j);
removeSponsorFromLedgerEntry(
sleRippleState, !bSenderHigh ? sfLowSponsor : sfHighSponsor);
@@ -807,7 +807,7 @@ directSendNoFeeIOU(
<< to_string(uSenderID) << " -> " << to_string(uReceiverID) << " : "
<< saAmount.getFullText();
auto sleAccount = AccountRootEntryW(uReceiverID, view);
auto const sleAccount = view.peek(keylet::account(uReceiverID));
if (!sleAccount)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -819,7 +819,7 @@ directSendNoFeeIOU(
uSenderID,
uReceiverID,
index.key,
sleAccount.mutableRawSle(),
sleAccount,
false,
noRipple,
false,
@@ -1012,12 +1012,10 @@ accountSendIOU(
*/
TER terResult(tesSUCCESS);
SLE::pointer const sender = uSenderID != beast::kZero
? AccountRootEntryW(uSenderID, view).mutableRawSle()
: SLE::pointer();
SLE::pointer const receiver = uReceiverID != beast::kZero
? AccountRootEntryW(uReceiverID, view).mutableRawSle()
: SLE::pointer();
SLE::pointer const sender =
uSenderID != beast::kZero ? view.peek(keylet::account(uSenderID)) : SLE::pointer();
SLE::pointer const receiver =
uReceiverID != beast::kZero ? view.peek(keylet::account(uReceiverID)) : SLE::pointer();
if (auto stream = j.trace())
{
@@ -1110,9 +1108,8 @@ accountSendMultiIOU(
* ensure that transfers are balanced.
*/
SLE::pointer const sender = senderID != beast::kZero
? AccountRootEntryW(senderID, view).mutableRawSle()
: SLE::pointer();
SLE::pointer const sender =
senderID != beast::kZero ? view.peek(keylet::account(senderID)) : SLE::pointer();
if (auto stream = j.trace())
{
@@ -1143,9 +1140,8 @@ accountSendMultiIOU(
if (!amount || (senderID == receiverID))
continue;
SLE::pointer const receiver = receiverID != beast::kZero
? AccountRootEntryW(receiverID, view).mutableRawSle()
: SLE::pointer();
SLE::pointer const receiver =
receiverID != beast::kZero ? view.peek(keylet::account(receiverID)) : SLE::pointer();
if (auto stream = j.trace())
{
@@ -1343,9 +1339,26 @@ directSendNoLimitMPT(
}
// Sending 3rd party MPTs: transit.
saActual = (waiveFee == WaiveTransferFee::Yes)
? saAmount
: multiply(saAmount, transferRate(view, saAmount.get<MPTIssue>().getMptID()));
if (waiveFee == WaiveTransferFee::Yes)
{
saActual = saAmount;
}
else
{
auto const rate = transferRate(view, saAmount.get<MPTIssue>().getMptID());
if (view.rules().enabled(fixCleanup3_5_0))
{
// Number math loses precision on large MPT amounts, which can
// overcharge the sender. MPTs are integral, so compute the cost
// exactly and round it up, matching the payment engine.
auto const cost = mulRatio(saAmount.mpt(), rate.value, QUALITY_ONE, true);
saActual = STAmount(saAmount.asset(), cost.value());
}
else
{
saActual = multiply(saAmount, rate);
}
}
JLOG(j.debug()) << "directSendNoLimitMPT> " << to_string(uSenderID) << " - > "
<< to_string(uReceiverID) << " : deliver=" << saAmount.getFullText()
@@ -1454,9 +1467,23 @@ directSendNoLimitMultiMPT(
}
// Sending 3rd party MPTs: transit.
STAmount const actualSend = (waiveFee == WaiveTransferFee::Yes)
? amount
: multiply(amount, transferRate(view, amount.get<MPTIssue>().getMptID()));
STAmount actualSend = amount;
if (waiveFee != WaiveTransferFee::Yes)
{
auto const rate = transferRate(view, amount.get<MPTIssue>().getMptID());
if (view.rules().enabled(fixCleanup3_5_0))
{
// Number math loses precision on large MPT amounts, which can
// overcharge the sender. MPTs are integral, so compute the
// cost exactly and round it up, matching the payment engine.
auto const cost = mulRatio(amount.mpt(), rate.value, QUALITY_ONE, true);
actualSend = STAmount(amount.asset(), cost.value());
}
else
{
actualSend = multiply(amount, rate);
}
}
actual += actualSend;
takeFromSender += actualSend;
@@ -1597,8 +1624,8 @@ transferXRP(
XRPL_ASSERT(from != to, "xrpl::transferXRP : sender is not receiver");
XRPL_ASSERT(amount.native(), "xrpl::transferXRP : amount is XRP");
SLE::pointer const sender = AccountRootEntryW(from, view).mutableRawSle();
SLE::pointer const receiver = AccountRootEntryW(to, view).mutableRawSle();
SLE::pointer const sender = view.peek(keylet::account(from));
SLE::pointer const receiver = view.peek(keylet::account(to));
if (!sender || !receiver)
return tefINTERNAL; // LCOV_EXCL_LINE
+3 -1
View File
@@ -1642,7 +1642,9 @@ divRoundImpl(STAmount const& num, STAmount const& den, Asset const& asset, bool
bool const resultNegative = (num.negative() != den.negative());
if (asset.holds<MPTIssue>() && isFeatureEnabled(featureMPTokensV2, false))
// fixCleanup3_5_0: the legacy path below overflows on large MPT amounts.
if (asset.holds<MPTIssue>() &&
(isFeatureEnabled(featureMPTokensV2, true) || isFeatureEnabled(fixCleanup3_5_0, true)))
{
// Match the multiply path above: Number performs the rounded
// operation, then STAmount materializes the final MPT amount using the
+18 -19
View File
@@ -11,7 +11,6 @@
#include <xrpl/json/to_string.h> // IWYU pragma: keep
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DelegateHelpers.h>
@@ -587,7 +586,7 @@ Transactor::checkFee(PreclaimContext const& ctx, XRPAmount baseFee)
if (feePayer.type == FeePayerType::SponsorCoSigned)
{
auto const sponsorReserve = accountReserve(ctx.view, feePayer.id, ctx.j);
auto const sponsorReserve = accountReserve(ctx.view, payerSle, ctx.j);
maxSpendable = payerSle->getFieldAmount(sfBalance).xrp() - sponsorReserve;
}
else
@@ -653,7 +652,7 @@ Transactor::payFee()
XRPAmount spendable = balance;
if (feePayer.type == FeePayerType::SponsorCoSigned)
{
auto const sponsorReserve = accountReserve(view(), feePayer.id, j_);
auto const sponsorReserve = accountReserve(view(), sle, j_);
// max(balance - reserve, 0) with overflow handling
spendable = balance > sponsorReserve ? balance - sponsorReserve : beast::kZero;
}
@@ -701,7 +700,7 @@ Transactor::checkSeqProxy(ReadView const& view, STTx const& tx, beast::Journal j
{
auto const id = tx.getAccountID(sfAccount);
auto const sle = AccountRootEntryR(id, view);
auto const sle = view.read(keylet::account(id));
if (!sle)
{
@@ -766,7 +765,7 @@ Transactor::checkPriorTxAndLastLedger(PreclaimContext const& ctx)
{
auto const id = ctx.tx.getAccountID(sfAccount);
auto const sle = AccountRootEntryR(id, ctx.view);
auto const sle = ctx.view.read(keylet::account(id));
if (!sle)
{
@@ -836,7 +835,7 @@ Transactor::ticketDelete(
// Update the account root's TicketCount. If the ticket count drops to
// zero remove the (optional) field.
auto sleAccount = AccountRootEntryW(account, view);
auto sleAccount = view.peek(keylet::account(account));
if (!sleAccount)
{
// LCOV_EXCL_START
@@ -886,19 +885,19 @@ Transactor::apply()
// If the transactor requires a valid account and the transaction doesn't
// list one, preflight will have already a flagged a failure.
auto sle = AccountRootEntryW(accountID_, view());
auto const sle = view().peek(keylet::account(accountID_));
// sle must exist except for transactions
// that allow zero account.
XRPL_ASSERT(
sle.exists() || accountID_ == beast::kZero,
sle != nullptr || accountID_ == beast::kZero,
"xrpl::Transactor::apply : non-null SLE or zero account");
if (sle)
{
preFeeBalance_ = STAmount{(*sle)[sfBalance]}.xrp();
TER result = consumeSeqProxy(sle.mutableRawSle());
TER result = consumeSeqProxy(sle);
if (!isTesSuccess(result))
return result;
@@ -909,7 +908,7 @@ Transactor::apply()
if (sle->isFieldPresent(sfAccountTxnID))
sle->setFieldH256(sfAccountTxnID, ctx_.tx.getTransactionID());
sle.update();
view().update(sle);
}
return doApply();
@@ -926,7 +925,7 @@ Transactor::checkSign(
bool permitUncreatedAccount)
{
{
auto const sle = AccountRootEntryR(idAccount, view);
auto const sle = view.read(keylet::account(idAccount));
if ((view.rules().enabled(featureLendingProtocol) ||
view.rules().enabled(featureBatchV1_1) || view.rules().enabled(fixCleanup3_3_0)) &&
@@ -992,7 +991,7 @@ Transactor::checkSign(
// Look up the account.
auto const idSigner = calcAccountID(PublicKey(makeSlice(pkSigner)));
auto const sleAccount = AccountRootEntryR(idAccount, view);
auto const sleAccount = view.read(keylet::account(idAccount));
if (!sleAccount)
{
// An account that does not exist yet can only be authorized by its own
@@ -1005,7 +1004,7 @@ Transactor::checkSign(
return tesSUCCESS;
}
return checkSingleSign(view, idSigner, idAccount, sleAccount.rawSle(), j);
return checkSingleSign(view, idSigner, idAccount, sleAccount, j);
}
NotTEC
@@ -1154,7 +1153,7 @@ Transactor::checkMultiSign(
// In any of these cases we need to know whether the account is in
// the ledger. Determine that now.
auto const sleTxSignerRoot = AccountRootEntryR(txSignerAcctID, view);
auto const sleTxSignerRoot = view.read(keylet::account(txSignerAcctID));
if (signingAcctIDFromPubKey == txSignerAcctID)
{
@@ -1297,7 +1296,7 @@ Transactor::reset(XRPAmount fee)
{
ctx_.discard();
auto txnAcct = AccountRootEntryW(ctx_.tx.getAccountID(sfAccount), view());
auto const txnAcct = view().peek(keylet::account(ctx_.tx.getAccountID(sfAccount)));
// The account should never be missing from the ledger. But if it
// is missing then we can't very well charge it a fee, can we?
@@ -1332,7 +1331,7 @@ Transactor::reset(XRPAmount fee)
XRPAmount spendable = balance;
if (feePayer.type == FeePayerType::SponsorCoSigned)
{
auto const sponsorReserve = accountReserve(view(), feePayer.id, j_);
auto const sponsorReserve = accountReserve(view(), payerSle, j_);
// max(balance - reserve, 0) with overflow handling
spendable = balance > sponsorReserve ? balance - sponsorReserve : beast::kZero;
}
@@ -1365,13 +1364,13 @@ Transactor::reset(XRPAmount fee)
payerSle->setFieldAmount(feePayer.balanceField, feeAmountAfter);
}
TER const ter{consumeSeqProxy(txnAcct.mutableRawSle())};
TER const ter{consumeSeqProxy(txnAcct)};
XRPL_ASSERT(isTesSuccess(ter), "xrpl::Transactor::reset : result is tesSUCCESS");
if (isTesSuccess(ter))
{
txnAcct.update();
if (payerSle != txnAcct.mutableRawSle())
view().update(txnAcct);
if (payerSle != txnAcct)
view().update(payerSle);
}
+4 -13
View File
@@ -735,15 +735,6 @@ NoDeepFreezeTrustLinesWithoutFreeze::finalize(
//------------------------------------------------------------------------------
bool
isPseudoAccountSle(SLE::ConstRef sleAcct)
{
auto const& fields = getPseudoAccountFields();
return sleAcct && sleAcct->getType() == ltACCOUNT_ROOT &&
std::ranges::any_of(
fields, [&sleAcct](SField const* sf) { return sleAcct->isFieldPresent(*sf); });
}
void
ValidNewAccountRoot::visitEntry(bool, SLE::ConstRef before, SLE::ConstRef after)
{
@@ -751,7 +742,7 @@ ValidNewAccountRoot::visitEntry(bool, SLE::ConstRef before, SLE::ConstRef after)
{
accountsCreated_++;
accountSeq_ = (*after)[sfSequence];
pseudoAccount_ = isPseudoAccountSle(after);
pseudoAccount_ = isPseudoAccount(after);
flags_ = after->getFlags();
}
}
@@ -1029,9 +1020,9 @@ ValidPseudoAccounts::visitEntry(bool isDelete, SLE::ConstRef before, SLE::ConstR
if (after && after->getType() == ltACCOUNT_ROOT)
{
bool const isPseudo = [&]() {
// isPseudoAccountSle checks that any of the pseudo-account fields
// are set.
if (isPseudoAccountSle(after))
// isPseudoAccount checks that any of the pseudo-account fields are
// set.
if (isPseudoAccount(after))
return true;
// Not all pseudo-accounts have a zero sequence, but all accounts
// with a zero sequence had better be pseudo-accounts.
+27 -11
View File
@@ -23,7 +23,6 @@
#include <xrpl/protocol/TxFormats.h>
#include <xrpl/protocol/UintTypes.h>
#include <xrpl/protocol/XRPAmount.h>
#include <xrpl/tx/invariants/InvariantCheck.h>
#include <xrpl/tx/invariants/InvariantCheckPrivilege.h>
#include <algorithm>
@@ -90,17 +89,24 @@ ValidMPTIssuance::visitEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef
if (fix320Enabled && after->isFieldPresent(sfReferenceHolding))
referenceHoldingSetOnCreate_ = true;
}
else if (fix320Enabled)
else
{
// Modified issuance: detect any change to sfReferenceHolding.
bool const beforePresent = before->isFieldPresent(sfReferenceHolding);
bool const afterPresent = after->isFieldPresent(sfReferenceHolding);
if (beforePresent != afterPresent ||
(afterPresent &&
before->getFieldH256(sfReferenceHolding) !=
after->getFieldH256(sfReferenceHolding)))
// lsfMPTLocked is the only issuance flag with a legal clear path
// (tfMPTUnlock); the rest are fixed at creation or set-once.
issuanceFlagsCleared_ |= before->getFlags() & ~after->getFlags() & ~lsfMPTLocked;
if (fix320Enabled)
{
referenceHoldingMutated_ = true;
// Modified issuance: detect any change to sfReferenceHolding.
bool const beforePresent = before->isFieldPresent(sfReferenceHolding);
bool const afterPresent = after->isFieldPresent(sfReferenceHolding);
if (beforePresent != afterPresent ||
(afterPresent &&
before->getFieldH256(sfReferenceHolding) !=
after->getFieldH256(sfReferenceHolding)))
{
referenceHoldingMutated_ = true;
}
}
}
}
@@ -200,6 +206,16 @@ ValidMPTIssuance::finalize(
return false;
}
// Post-fixCleanup3_5_0: no transaction may clear an issuance flag other
// than lsfMPTLocked, so downstream code can trust set-once flags such as
// lsfMPTCanTransfer.
if (rules.enabled(fixCleanup3_5_0) && issuanceFlagsCleared_ != 0)
{
JLOG(j.fatal()) << "Invariant failed: immutable MPTokenIssuance flag cleared: "
<< issuanceFlagsCleared_;
return false;
}
// Deleting an MPToken with a non-zero MPTAmount is rejected.
if (rules.enabled(fixCleanup3_5_0))
{
@@ -894,7 +910,7 @@ ValidMPTTransfer::visitEntry(
// no trace of its pseudo-account status in the post-transaction view
// isAuthorized() sees at finalize() time.
if (before && before->getType() == ltACCOUNT_ROOT)
pseudoAccountsBefore_[before->at(sfAccount)] = isPseudoAccountSle(before);
pseudoAccountsBefore_[before->at(sfAccount)] = isPseudoAccount(before);
}
bool
+1 -1
View File
@@ -740,7 +740,7 @@ ValidVault::finalize(
return false;
}
if (!isPseudoAccount(AccountRootEntryR(sleSharesIssuer, view)))
if (!isPseudoAccount(sleSharesIssuer))
{
JLOG(j.fatal()) //
<< "Invariant failed: shares issuer must be a "
-23
View File
@@ -13,7 +13,6 @@
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/IOUAmount.h>
#include <xrpl/protocol/MPTAmount.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/Quality.h>
#include <xrpl/protocol/Rules.h>
#include <xrpl/protocol/STAmount.h>
@@ -100,28 +99,6 @@ AMMLiquidity<TIn, TOut>::generateFibSeqOffer(TAmounts<TIn, TOut> const& balances
}
namespace {
template <typename T>
constexpr T
maxAmount()
{
if constexpr (std::is_same_v<T, XRPAmount>)
{
return XRPAmount(STAmount::kMaxNative);
}
else if constexpr (std::is_same_v<T, IOUAmount>)
{
return IOUAmount(STAmount::kMaxValue / 2, STAmount::kMaxOffset);
}
else if constexpr (std::is_same_v<T, STAmount>)
{
return STAmount(STAmount::kMaxValue / 2, STAmount::kMaxOffset);
}
else if constexpr (std::is_same_v<T, MPTAmount>)
{
return MPTAmount(kMaxMpTokenAmount);
}
}
template <typename T>
T
maxOut(T const& out, Asset const& asset)
+2 -3
View File
@@ -5,7 +5,6 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
@@ -837,7 +836,7 @@ DirectStepI<TDerived>::check(StrandContext const& ctx) const
return temBAD_PATH;
}
auto const sleSrc = AccountRootEntryR(src_, ctx.view);
auto const sleSrc = ctx.view.read(keylet::account(src_));
if (!sleSrc)
{
JLOG(j_.warn()) << "DirectStepI: can't receive IOUs from non-existent issuer: " << src_;
@@ -903,7 +902,7 @@ DirectStepI<TDerived>::check(StrandContext const& ctx) const
}
}
return static_cast<TDerived const*>(this)->check(ctx, sleSrc.rawSle());
return static_cast<TDerived const*>(this)->check(ctx, sleSrc);
}
//------------------------------------------------------------------------------
+2 -3
View File
@@ -6,7 +6,6 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -866,7 +865,7 @@ MPTEndpointStep<TDerived>::check(StrandContext const& ctx) const
return temBAD_PATH;
}
auto const sleSrc = AccountRootEntryR(src_, ctx.view);
auto const sleSrc = ctx.view.read(keylet::account(src_));
if (!sleSrc)
{
JLOG(j_.warn()) << "MPTEndpointStep: can't receive MPT from non-existent issuer: " << src_;
@@ -929,7 +928,7 @@ MPTEndpointStep<TDerived>::check(StrandContext const& ctx) const
return temBAD_PATH;
}
return static_cast<TDerived const*>(this)->check(ctx, sleSrc.rawSle());
return static_cast<TDerived const*>(this)->check(ctx, sleSrc);
}
template <class TDerived>
+1 -2
View File
@@ -4,7 +4,6 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -343,7 +342,7 @@ XRPEndpointStep<TDerived>::check(StrandContext const& ctx) const
return temBAD_PATH;
}
auto sleAcc = AccountRootEntryR(acc_, ctx.view);
auto sleAcc = ctx.view.read(keylet::account(acc_));
if (!sleAcc)
{
JLOG(j_.warn()) << "XRPEndpointStep: can't send or receive XRP from "
@@ -9,7 +9,6 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
@@ -225,7 +224,7 @@ AccountDelete::preclaim(PreclaimContext const& ctx)
AccountID const account{ctx.tx[sfAccount]};
AccountID const dst{ctx.tx[sfDestination]};
auto sleDst = AccountRootEntryR(dst, ctx.view);
auto sleDst = ctx.view.read(keylet::account(dst));
if (!sleDst)
return tecNO_DST;
@@ -251,7 +250,7 @@ AccountDelete::preclaim(PreclaimContext const& ctx)
}
}
auto sleAccount = AccountRootEntryR(account, ctx.view);
auto sleAccount = ctx.view.read(keylet::account(account));
XRPL_ASSERT(sleAccount, "xrpl::AccountDelete::preclaim : non-null account");
if (!sleAccount)
return terNO_ACCOUNT;
@@ -354,11 +353,11 @@ AccountDelete::preclaim(PreclaimContext const& ctx)
TER
AccountDelete::doApply()
{
auto src = AccountRootEntryW(accountID_, view());
auto src = view().peek(keylet::account(accountID_));
XRPL_ASSERT(src, "xrpl::AccountDelete::doApply : non-null source account");
auto const dstID = ctx_.tx[sfDestination];
auto dst = AccountRootEntryW(dstID, view());
auto dst = view().peek(keylet::account(dstID));
XRPL_ASSERT(dst, "xrpl::AccountDelete::doApply : non-null destination account");
if (!src || !dst)
@@ -366,8 +365,8 @@ AccountDelete::doApply()
if (ctx_.tx.isFieldPresent(sfCredentialIDs))
{
if (auto err = verifyDepositPreauth(
ctx_.tx, ctx_.view(), accountID_, dstID, dst.rawSle(), ctx_.journal);
if (auto err =
verifyDepositPreauth(ctx_.tx, ctx_.view(), accountID_, dstID, dst, ctx_.journal);
!isTesSuccess(err))
return err;
}
@@ -408,7 +407,7 @@ AccountDelete::doApply()
if (src->isFieldPresent(sfSponsor))
{
auto const sponsorID = src->getAccountID(sfSponsor);
auto sponsorSle = AccountRootEntryW(sponsorID, view());
auto sponsorSle = view().peek(keylet::account(sponsorID));
if (!sponsorSle)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -426,7 +425,7 @@ AccountDelete::doApply()
return tefINTERNAL; // LCOV_EXCL_LINE
}
sponsorSle->at(sfSponsoringAccountCount) = sponsoringAccountCount - 1;
sponsorSle.update();
view().update(sponsorSle);
// Following line might look redundant, but without it, sfSponsor
// would end up remaining in after-ltAccountRoot during the
@@ -449,8 +448,8 @@ AccountDelete::doApply()
if (remainingBalance > XRPAmount(0) && dst->isFlag(lsfPasswordSpent))
dst->clearFlag(lsfPasswordSpent);
dst.update();
src.erase();
view().update(dst);
view().erase(src);
return tesSUCCESS;
}
@@ -6,7 +6,6 @@
#include <xrpl/basics/base_uint.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -171,7 +170,7 @@ AccountSet::preclaim(PreclaimContext const& ctx)
{
auto const id = ctx.tx[sfAccount];
auto const sle = AccountRootEntryR(id, ctx.view);
auto const sle = ctx.view.read(keylet::account(id));
if (!sle)
return terNO_ACCOUNT;
@@ -225,7 +224,7 @@ AccountSet::preclaim(PreclaimContext const& ctx)
TER
AccountSet::doApply()
{
auto sle = AccountRootEntryW(accountID_, view());
auto const sle = view().peek(keylet::account(accountID_));
if (!sle)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -583,7 +582,7 @@ AccountSet::doApply()
if (uFlagsIn != uFlagsOut)
sle->setFieldU32(sfFlags, uFlagsOut);
sle.update();
ctx_.view().update(sle);
return tesSUCCESS;
}
@@ -3,7 +3,6 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/PublicKey.h>
@@ -26,7 +25,7 @@ SetRegularKey::calculateBaseFee(ReadView const& view, STTx const& tx)
{
if (calcAccountID(PublicKey(makeSlice(spk))) == id)
{
auto const sle = AccountRootEntryR(id, view);
auto const sle = view.read(keylet::account(id));
if (sle && !sle->isFlag(lsfPasswordSpent))
{
@@ -54,7 +53,7 @@ SetRegularKey::preflight(PreflightContext const& ctx)
TER
SetRegularKey::doApply()
{
auto sle = AccountRootEntryW(accountID_, view());
auto const sle = view().peek(keylet::account(accountID_));
if (!sle)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -74,7 +73,7 @@ SetRegularKey::doApply()
sle->makeFieldAbsent(sfRegularKey);
}
sle.update();
ctx_.view().update(sle);
return tesSUCCESS;
}
@@ -6,7 +6,6 @@
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/SponsorHelpers.h>
@@ -214,9 +213,8 @@ removeSignersFromLedger(
// LCOV_EXCL_STOP
}
AccountRootEntryW accountSle(accountKeylet, view);
decreaseOwnerCountForObject(
view, accountSle, signers, removeFromOwnerCount, registry.getJournal("View"));
view, view.peek(accountKeylet), signers, removeFromOwnerCount, registry.getJournal("View"));
view.erase(signers);
@@ -311,7 +309,7 @@ SignerListSet::replaceSignerList()
ctx_.registry, view(), accountKeylet, ownerDirKeylet, signerListKeylet, j_))
return ter;
auto sle = AccountRootEntryW(accountKeylet, view(), ctx_.journal);
auto const sle = view().peek(accountKeylet);
if (!sle)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -321,8 +319,12 @@ SignerListSet::replaceSignerList()
// We check the reserve against the starting balance because we want to
// allow dipping into the reserve to pay fees. This behavior is consistent
// with TicketCreate.
if (auto const ret = sle.checkReserve(
ctx_.getApplyViewContext(), preFeeBalance_, {.ownerCountDelta = kAddedOwnerCount});
if (auto const ret = checkReserve(
ctx_.getApplyViewContext(),
sle,
preFeeBalance_,
{.ownerCountDelta = kAddedOwnerCount},
ctx_.journal);
!isTesSuccess(ret))
return ret;
@@ -331,6 +333,7 @@ SignerListSet::replaceSignerList()
view().insert(signerList);
writeSignersToSLE(signerList, flags);
auto viewJ = ctx_.registry.get().getJournal("View");
// Add the signer list to the account's directory.
auto const page =
ctx_.view().dirInsert(ownerDirKeylet, signerListKeylet, describeOwnerDir(accountID_));
@@ -345,7 +348,7 @@ SignerListSet::replaceSignerList()
// If we succeeded, the new entry counts against the
// creator's reserve.
sle.increaseOwnerCount(ctx_.getApplyViewContext(), kAddedOwnerCount);
increaseOwnerCount(ctx_.getApplyViewContext(), sle, kAddedOwnerCount, viewJ);
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), signerList);
return tesSUCCESS;
}
@@ -356,7 +359,7 @@ SignerListSet::destroySignerList()
auto const accountKeylet = keylet::account(accountID_);
// Destroying the signer list is only allowed if either the master key
// is enabled or there is a regular key.
auto const ledgerEntry = AccountRootEntryW(accountKeylet, view());
SLE::pointer const ledgerEntry = view().peek(accountKeylet);
if (!ledgerEntry)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -10,7 +10,6 @@
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/RawView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -126,7 +125,8 @@ checkAttestationPublicKey(
AccountID const accountFromPK = calcAccountID(pk);
if (auto const sleAttestationSigningAccount = AccountRootEntryR(attestationSignerAccount, view))
if (auto const sleAttestationSigningAccount =
view.read(keylet::account(attestationSignerAccount)))
{
if (accountFromPK == attestationSignerAccount)
{
@@ -404,7 +404,7 @@ transferHelper(
return tesSUCCESS;
auto const dstK = keylet::account(dst);
if (auto sleDst = AccountRootEntryR(dstK, psb))
if (auto sleDst = psb.read(dstK))
{
// Check dst tag and deposit auth
@@ -430,13 +430,13 @@ transferHelper(
if (amt.native())
{
auto sleSrc = AccountRootEntryW(src, psb, j);
auto const sleSrc = psb.peek(keylet::account(src));
XRPL_ASSERT(sleSrc, "xrpl::transferHelper : non-null source account");
if (!sleSrc)
return tecINTERNAL; // LCOV_EXCL_LINE
{
auto const reserve = sleSrc.reserve();
auto const reserve = accountReserve(psb, sleSrc, j);
auto const availableBalance = [&]() -> STAmount {
STAmount curBal = (*sleSrc)[sfBalance];
@@ -455,7 +455,7 @@ transferHelper(
}
}
auto sleDst = AccountRootEntryW(dstK, psb);
auto sleDst = psb.peek(dstK);
if (!sleDst)
{
if (canCreate == CanCreateDstPolicy::No)
@@ -470,17 +470,17 @@ transferHelper(
}
// Create the account.
sleDst.newSLE();
sleDst = std::make_shared<SLE>(dstK);
sleDst->setAccountID(sfAccount, dst);
sleDst->setFieldU32(sfSequence, psb.seq());
sleDst.insert();
psb.insert(sleDst);
}
(*sleSrc)[sfBalance] = (*sleSrc)[sfBalance] - amt;
(*sleDst)[sfBalance] = (*sleDst)[sfBalance] + amt;
sleSrc.update();
sleDst.update();
psb.update(sleSrc);
psb.update(sleDst);
return tesSUCCESS;
}
@@ -724,7 +724,7 @@ finalizeClaimHelper(
auto const cidOwner = (*sleClaimID)[sfAccount];
{
// Remove the claim id
auto sleOwner = AccountRootEntryW(cidOwner, outerSb);
auto const sleOwner = outerSb.peek(keylet::account(cidOwner));
auto const page = (*sleClaimID)[sfOwnerNode];
if (!outerSb.dirRemove(keylet::ownerDir(cidOwner), page, sleClaimID->key(), true))
{
@@ -759,7 +759,7 @@ getSignersListAndQuorum(ReadView const& view, SLE const& sleBridge, beast::Journ
std::uint32_t q = std::numeric_limits<std::uint32_t>::max();
AccountID const thisDoor = sleBridge[sfAccount];
auto const sleDoor = [&] { return AccountRootEntryR(thisDoor, view); }();
auto const sleDoor = [&] { return view.read(keylet::account(thisDoor)); }();
if (!sleDoor)
{
@@ -1036,7 +1036,7 @@ applyCreateAccountAttestations(
// Check reserve
auto const balance = (*sleDoor)[sfBalance];
auto const reserve = AccountRootEntryR(sleDoor, psb, j).reserve({.ownerCountDelta = 1});
auto const reserve = accountReserve(psb, sleDoor, j, {.ownerCountDelta = 1});
if (balance < reserve)
return std::unexpected(tecINSUFFICIENT_RESERVE);
@@ -1145,9 +1145,7 @@ applyCreateAccountAttestations(
return tecINTERNAL; // LCOV_EXCL_LINE
// Reserve was already checked
AccountRootEntryW doorSle(doorK, psb, j);
std::optional<AccountRootEntryW> noSponsor;
doorSle.increaseOwnerCount(noSponsor, 1);
increaseOwnerCount(psb, sleDoor, {}, 1, j);
psb.insert(createdSleClaimID);
psb.update(sleDoor);
}
@@ -1431,7 +1429,7 @@ XChainCreateBridge::preclaim(PreclaimContext const& ctx)
if (!isXRP(bridgeSpec.issue(chainType)))
{
auto const sleIssuer = AccountRootEntryR(bridgeSpec.issue(chainType).account, ctx.view);
auto const sleIssuer = ctx.view.read(keylet::account(bridgeSpec.issue(chainType).account));
if (!sleIssuer)
return tecNO_ISSUER;
@@ -1444,12 +1442,12 @@ XChainCreateBridge::preclaim(PreclaimContext const& ctx)
{
// Check reserve
auto const sleAcc = AccountRootEntryR(account, ctx.view, ctx.j);
auto const sleAcc = ctx.view.read(keylet::account(account));
if (!sleAcc)
return terNO_ACCOUNT;
auto const balance = (*sleAcc)[sfBalance];
auto const reserve = sleAcc.reserve({.ownerCountDelta = 1});
auto const reserve = accountReserve(ctx.view, sleAcc, ctx.j, {.ownerCountDelta = 1});
if (balance < reserve)
return tecINSUFFICIENT_RESERVE;
@@ -1466,7 +1464,7 @@ XChainCreateBridge::doApply()
auto const reward = ctx_.tx[sfSignatureReward];
auto const minAccountCreate = ctx_.tx[~sfMinAccountCreateAmount];
auto sleAcct = AccountRootEntryW(account, ctx_.view(), ctx_.journal);
auto const sleAcct = ctx_.view().peek(keylet::account(account));
if (!sleAcct)
return tecINTERNAL; // LCOV_EXCL_LINE
@@ -1494,11 +1492,10 @@ XChainCreateBridge::doApply()
(*sleBridge)[sfOwnerNode] = *page;
}
std::optional<AccountRootEntryW> noSponsor;
sleAcct.increaseOwnerCount(noSponsor, 1);
increaseOwnerCount(ctx_.view(), sleAcct, {}, 1, ctx_.journal);
ctx_.view().insert(sleBridge);
sleAcct.update();
ctx_.view().update(sleAcct);
return tesSUCCESS;
}
@@ -1578,7 +1575,7 @@ BridgeModify::doApply()
auto const minAccountCreate = ctx_.tx[~sfMinAccountCreateAmount];
bool const clearAccountCreate = ctx_.tx.isFlag(tfClearAccountCreateAmount);
auto const sleAcct = AccountRootEntryW(account, ctx_.view());
auto const sleAcct = ctx_.view().peek(keylet::account(account));
if (!sleAcct)
return tecINTERNAL; // LCOV_EXCL_LINE
@@ -1636,7 +1633,7 @@ XChainClaim::preclaim(PreclaimContext const& ctx)
return tecNO_ENTRY;
}
if (!AccountRootEntryR(ctx.tx[sfDestination], ctx.view))
if (!ctx.view.read(keylet::account(ctx.tx[sfDestination])))
{
return tecNO_DST;
}
@@ -1741,7 +1738,7 @@ XChainClaim::doApply()
// `finalizeClaimHelper`. Since `finalizeClaimHelper` can create child
// views, it's important that the sle's lifetime doesn't overlap.
auto const sleAcct = AccountRootEntryW(account, psb);
auto const sleAcct = psb.peek(keylet::account(account));
auto const sleBridge = peekBridge(psb, bridgeSpec);
auto const sleClaimID = psb.peek(claimIDKeylet);
@@ -1922,7 +1919,7 @@ XChainCommit::doApply()
auto const amount = ctx_.tx[sfAmount];
auto const bridgeSpec = ctx_.tx[sfXChainBridge];
auto const sleAccount = AccountRootEntryR(account, psb);
auto const sleAccount = psb.read(keylet::account(account));
if (!sleAccount)
return tecINTERNAL; // LCOV_EXCL_LINE
@@ -1993,12 +1990,12 @@ XChainCreateClaimID::preclaim(PreclaimContext const& ctx)
{
// Check reserve
auto const sleAcc = AccountRootEntryR(account, ctx.view, ctx.j);
auto const sleAcc = ctx.view.read(keylet::account(account));
if (!sleAcc)
return terNO_ACCOUNT;
auto const balance = (*sleAcc)[sfBalance];
auto const reserve = sleAcc.reserve({.ownerCountDelta = 1});
auto const reserve = accountReserve(ctx.view, sleAcc, ctx.j, {.ownerCountDelta = 1});
if (balance < reserve)
return tecINSUFFICIENT_RESERVE;
}
@@ -2014,7 +2011,7 @@ XChainCreateClaimID::doApply()
auto const reward = ctx_.tx[sfSignatureReward];
auto const otherChainSrc = ctx_.tx[sfOtherChainSource];
auto sleAcct = AccountRootEntryW(account, ctx_.view(), ctx_.journal);
auto const sleAcct = ctx_.view().peek(keylet::account(account));
if (!sleAcct)
return tecINTERNAL; // LCOV_EXCL_LINE
@@ -2056,12 +2053,11 @@ XChainCreateClaimID::doApply()
(*sleClaimID)[sfOwnerNode] = *page;
}
std::optional<AccountRootEntryW> noSponsor;
sleAcct.increaseOwnerCount(noSponsor, 1);
increaseOwnerCount(ctx_.view(), sleAcct, {}, 1, ctx_.journal);
ctx_.view().insert(sleClaimID);
ctx_.view().update(sleBridge);
sleAcct.update();
ctx_.view().update(sleAcct);
return tesSUCCESS;
}
@@ -2199,7 +2195,7 @@ XChainCreateAccountCommit::doApply()
STAmount const reward = ctx_.tx[sfSignatureReward];
STXChainBridge const bridge = ctx_.tx[sfXChainBridge];
auto const sle = AccountRootEntryW(account, psb);
auto const sle = psb.peek(keylet::account(account));
if (!sle)
return tecINTERNAL; // LCOV_EXCL_LINE
@@ -3,7 +3,9 @@
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/CheckEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
@@ -30,7 +32,7 @@ CheckCancel::preflight(PreflightContext const& ctx)
TER
CheckCancel::preclaim(PreclaimContext const& ctx)
{
auto const sleCheck = ctx.view.read(keylet::check(ctx.tx[sfCheckID]));
CheckEntryR const sleCheck(ctx.tx[sfCheckID], ctx.view);
if (!sleCheck)
{
JLOG(ctx.j.warn()) << "Check does not exist.";
@@ -59,7 +61,7 @@ CheckCancel::preclaim(PreclaimContext const& ctx)
TER
CheckCancel::doApply()
{
auto const sleCheck = view().peek(keylet::check(ctx_.tx[sfCheckID]));
CheckEntryW sleCheck(ctx_.tx[sfCheckID], view(), j_);
if (!sleCheck)
{
// Error should have been caught in preclaim.
@@ -96,10 +98,10 @@ CheckCancel::doApply()
}
// If we succeeded, update the check owner's reserve.
decreaseOwnerCountForObject(view(), srcId, sleCheck, 1, viewJ);
decreaseOwnerCountForObject(view(), srcId, sleCheck.mutableRawSle(), 1, viewJ);
// Remove check from ledger.
view().erase(sleCheck);
sleCheck.erase();
return tesSUCCESS;
}
+36 -34
View File
@@ -7,7 +7,7 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/entries/CheckEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
@@ -88,7 +88,7 @@ CheckCash::preflight(PreflightContext const& ctx)
TER
CheckCash::preclaim(PreclaimContext const& ctx)
{
auto const sleCheck = ctx.view.read(keylet::check(ctx.tx[sfCheckID]));
CheckEntryR const sleCheck(ctx.tx[sfCheckID], ctx.view);
if (!sleCheck)
{
JLOG(ctx.j.warn()) << "Check does not exist.";
@@ -113,8 +113,8 @@ CheckCash::preclaim(PreclaimContext const& ctx)
// LCOV_EXCL_STOP
}
{
auto const sleSrc = AccountRootEntryR(srcId, ctx.view);
auto const sleDst = AccountRootEntryR(dstId, ctx.view);
auto const sleSrc = ctx.view.read(keylet::account(srcId));
auto const sleDst = ctx.view.read(keylet::account(dstId));
if (!sleSrc || !sleDst)
{
// If the check exists this should never occur.
@@ -202,7 +202,7 @@ CheckCash::preclaim(PreclaimContext const& ctx)
auto const sleTrustLine =
ctx.view.read(keylet::trustLine(dstId, issuerId, currency));
auto const sleIssuer = AccountRootEntryR(issuerId, ctx.view);
auto const sleIssuer = ctx.view.read(keylet::account(issuerId));
if (!sleIssuer)
{
JLOG(ctx.j.warn()) << "Can't receive IOUs from "
@@ -254,7 +254,7 @@ CheckCash::preclaim(PreclaimContext const& ctx)
return tesSUCCESS;
},
[&](MPTIssue const& issue) -> TER {
auto const sleIssuer = AccountRootEntryR(issuerId, ctx.view);
auto const sleIssuer = ctx.view.read(keylet::account(issuerId));
if (!sleIssuer)
{
JLOG(ctx.j.warn()) << "Can't receive MPTs from "
@@ -297,8 +297,9 @@ CheckCash::doApply()
// directly on a View.
PaymentSandbox psb(&ctx_.view());
auto sleCheck = psb.peek(keylet::check(ctx_.tx[sfCheckID]));
if (!sleCheck)
std::optional<CheckEntryW> sleCheck;
sleCheck.emplace(ctx_.tx[sfCheckID], psb, j_);
if (!*sleCheck)
{
// LCOV_EXCL_START
JLOG(j_.fatal()) << "Precheck did not verify check's existence.";
@@ -306,7 +307,7 @@ CheckCash::doApply()
// LCOV_EXCL_STOP
}
AccountID const srcId{sleCheck->getAccountID(sfAccount)};
AccountID const srcId{(*sleCheck)->getAccountID(sfAccount)};
if (!psb.exists(keylet::account(srcId)) || !psb.exists(keylet::account(accountID_)))
{
// LCOV_EXCL_START
@@ -315,7 +316,7 @@ CheckCash::doApply()
// LCOV_EXCL_STOP
}
auto const sponsorCheckSle = getLedgerEntryReserveSponsor(psb, sleCheck);
auto const sponsorCheckSle = getLedgerEntryReserveSponsor(psb, sleCheck->rawSle());
// Preclaim already checked that source has at least the requested
// funds.
@@ -332,7 +333,7 @@ CheckCash::doApply()
if (srcId != accountID_)
{
STAmount const sendMax = sleCheck->at(sfSendMax);
STAmount const sendMax = (*sleCheck)->at(sfSendMax);
// Flow() doesn't do XRP to XRP transfers.
if (sendMax.native())
@@ -407,18 +408,23 @@ CheckCash::doApply()
optDeliverMin ? maxDeliverMin() : ctx_.tx.getFieldAmount(sfAmount)};
auto applyViewContext = ApplyViewContext({.view = psb, .tx = ctx_.tx});
auto sponsorSle = getTxReserveSponsor(applyViewContext);
auto const sponsorSle = getTxReserveSponsor(applyViewContext);
if (!sponsorSle)
return sponsorSle.error(); // LCOV_EXCL_LINE
// Check reserve. Return destination account SLE if enough reserve,
// otherwise return nullptr.
auto checkDstReserve = [&]() -> SLE::pointer {
auto sleDst = AccountRootEntryW(accountID_, psb, j_);
auto sleDst = psb.peek(keylet::account(accountID_));
// Can the account cover the trust line's or MPT reserve?
if (auto const ret = sleDst.checkReserve(
applyViewContext, preFeeBalance_, *sponsorSle, {.ownerCountDelta = 1});
if (auto const ret = checkReserve(
applyViewContext,
sleDst,
preFeeBalance_,
*sponsorSle,
{.ownerCountDelta = 1},
j_);
!isTesSuccess(ret))
{
JLOG(j_.trace()) << "Trust line does not exist. "
@@ -426,7 +432,7 @@ CheckCash::doApply()
return nullptr;
}
return sleDst.mutableRawSle();
return sleDst;
};
std::optional<Keylet> trustLineKey;
@@ -482,10 +488,8 @@ CheckCash::doApply()
Issue(currency, accountID_), // limit of zero
0, // quality in
0, // quality out
sponsorSle->has_value() // sponsor
? (*sponsorSle)->mutableRawSle()
: SLE::pointer{},
viewJ); // journal
*sponsorSle, // sponsor
viewJ); // journal
!isTesSuccess(ter))
{
return ter;
@@ -531,14 +535,8 @@ CheckCash::doApply()
if (sleDst == nullptr)
return tecINSUFFICIENT_RESERVE;
if (auto const err = checkCreateMPT(
psb,
mptID,
accountID_,
sponsorSle->has_value() ? (*sponsorSle)->mutableRawSle()
: SLE::pointer{},
0,
j_);
if (auto const err =
checkCreateMPT(psb, mptID, accountID_, *sponsorSle, 0, j_);
!isTesSuccess(err))
{
return err;
@@ -573,7 +571,7 @@ CheckCash::doApply()
true, // owner pays transfer fee
OfferCrossing::No,
std::nullopt,
sleCheck->getFieldAmount(sfSendMax),
(*sleCheck)->getFieldAmount(sfSendMax),
std::nullopt, // check does not support domain
viewJ);
@@ -598,7 +596,7 @@ CheckCash::doApply()
// for DeliverMin.
ctx_.deliver(result.actualAmountOut);
sleCheck = psb.peek(keylet::check(ctx_.tx[sfCheckID]));
sleCheck.emplace(ctx_.tx[sfCheckID], psb, j_);
}
}
@@ -606,7 +604,10 @@ CheckCash::doApply()
// check link from destination directory.
if (srcId != accountID_ &&
!psb.dirRemove(
keylet::ownerDir(accountID_), sleCheck->at(sfDestinationNode), sleCheck->key(), true))
keylet::ownerDir(accountID_),
(*sleCheck)->at(sfDestinationNode),
(*sleCheck)->key(),
true))
{
// LCOV_EXCL_START
JLOG(j_.fatal()) << "Unable to delete check from destination.";
@@ -615,7 +616,8 @@ CheckCash::doApply()
}
// Remove check from check owner's directory.
if (!psb.dirRemove(keylet::ownerDir(srcId), sleCheck->at(sfOwnerNode), sleCheck->key(), true))
if (!psb.dirRemove(
keylet::ownerDir(srcId), (*sleCheck)->at(sfOwnerNode), (*sleCheck)->key(), true))
{
// LCOV_EXCL_START
JLOG(j_.fatal()) << "Unable to delete check from owner.";
@@ -624,10 +626,10 @@ CheckCash::doApply()
}
// If we succeeded, update the check owner's reserve.
decreaseOwnerCountForObject(psb, srcId, sleCheck, 1, viewJ);
decreaseOwnerCountForObject(psb, srcId, sleCheck->mutableRawSle(), 1, viewJ);
// Remove check from ledger.
psb.erase(sleCheck);
sleCheck->erase();
psb.apply(ctx_.rawView());
return tesSUCCESS;
@@ -4,7 +4,7 @@
#include <xrpl/basics/base_uint.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/entries/CheckEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
@@ -26,7 +26,6 @@
#include <xrpl/protocol/XRPAmount.h>
#include <xrpl/tx/Transactor.h>
#include <memory>
#include <optional>
namespace xrpl {
@@ -80,7 +79,7 @@ CheckCreate::preclaim(PreclaimContext const& ctx)
{
AccountID const dstId{ctx.tx[sfDestination]};
AccountID const srcId{ctx.tx[sfAccount]};
auto const sleDst = AccountRootEntryR(dstId, ctx.view);
auto const sleDst = ctx.view.read(keylet::account(dstId));
if (!sleDst)
{
JLOG(ctx.j.warn()) << "Destination account does not exist.";
@@ -188,22 +187,23 @@ CheckCreate::preclaim(PreclaimContext const& ctx)
TER
CheckCreate::doApply()
{
auto sle = AccountRootEntryW(accountID_, view(), ctx_.journal);
auto const sle = view().peek(keylet::account(accountID_));
if (!sle)
return tefINTERNAL; // LCOV_EXCL_LINE
// A check counts against the reserve of the issuing account, but we
// check the starting balance because we want to allow dipping into the
// reserve to pay fees.
if (auto const ret =
sle.checkReserve(ctx_.getApplyViewContext(), preFeeBalance_, {.ownerCountDelta = 1});
if (auto const ret = checkReserve(
ctx_.getApplyViewContext(), sle, preFeeBalance_, {.ownerCountDelta = 1}, ctx_.journal);
!isTesSuccess(ret))
return ret;
// Note that we use the value from the sequence or ticket as the
// Check sequence. For more explanation see comments in SeqProxy.h.
auto const seq = ctx_.tx.getSeqProxy();
Keylet const checkKeylet = keylet::check(accountID_, seq);
auto sleCheck = std::make_shared<SLE>(checkKeylet);
CheckEntryW sleCheck(accountID_, seq, view(), j_);
Keylet const checkKeylet = sleCheck.keylet();
sleCheck.newSLE();
sleCheck->setAccountID(sfAccount, accountID_);
AccountID const dstAccountId = ctx_.tx[sfDestination];
@@ -219,8 +219,9 @@ CheckCreate::doApply()
if (auto const expiry = ctx_.tx[~sfExpiration])
sleCheck->setFieldU32(sfExpiration, *expiry);
view().insert(sleCheck);
sleCheck.insert();
auto viewJ = ctx_.registry.get().getJournal("View");
// If it's not a self-send (and it shouldn't be), add Check to the
// destination's owner directory.
if (dstAccountId != accountID_)
@@ -251,8 +252,8 @@ CheckCreate::doApply()
}
// If we succeeded, the new entry counts against the creator's reserve.
sle.increaseOwnerCount(ctx_.getApplyViewContext(), 1);
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCheck);
increaseOwnerCount(ctx_.getApplyViewContext(), sle, 1, viewJ);
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCheck.mutableRawSle());
return tesSUCCESS;
}
@@ -2,7 +2,6 @@
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/SponsorHelpers.h>
@@ -88,8 +87,8 @@ CredentialAccept::doApply()
AccountID const issuer{ctx_.tx[sfIssuer]};
// Both exist as credential object exist itself (checked in preclaim)
auto sleSubject = AccountRootEntryW(accountID_, view(), j_);
auto sleIssuer = AccountRootEntryW(issuer, view());
auto const sleSubject = view().peek(keylet::account(accountID_));
auto const sleIssuer = view().peek(keylet::account(issuer));
if (!sleSubject || !sleIssuer)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -98,8 +97,13 @@ CredentialAccept::doApply()
if (!txSponsorSle)
return txSponsorSle.error(); // LCOV_EXCL_LINE
if (auto const ret = sleSubject.checkReserve(
ctx_.getApplyViewContext(), preFeeBalance_, *txSponsorSle, {.ownerCountDelta = 1});
if (auto const ret = checkReserve(
ctx_.getApplyViewContext(),
sleSubject,
preFeeBalance_,
*txSponsorSle,
{.ownerCountDelta = 1},
j_);
!isTesSuccess(ret))
return ret;
@@ -126,7 +130,7 @@ CredentialAccept::doApply()
removeSponsorFromLedgerEntry(sleCred);
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCred);
sleSubject.increaseOwnerCount(ctx_.getApplyViewContext(), 1);
increaseOwnerCount(ctx_.getApplyViewContext(), sleSubject, 1, j_);
view().update(sleCred);
return tesSUCCESS;
@@ -4,7 +4,6 @@
#include <xrpl/basics/base_uint.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h> // IWYU pragma: keep
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -85,7 +84,7 @@ CredentialCreate::preclaim(PreclaimContext const& ctx)
auto const credType(ctx.tx[sfCredentialType]);
auto const subject = ctx.tx[sfSubject];
auto const subjectSle = AccountRootEntryR(subject, ctx.view);
auto const subjectSle = ctx.view.read(keylet::account(subject));
if (!subjectSle)
{
@@ -135,12 +134,12 @@ CredentialCreate::doApply()
sleCred->setFieldU32(sfExpiration, *optExp);
}
auto sleIssuer = AccountRootEntryW(accountID_, view(), j_);
auto const sleIssuer = view().peek(keylet::account(accountID_));
if (!sleIssuer)
return tefINTERNAL; // LCOV_EXCL_LINE
if (auto const ret = sleIssuer.checkReserve(
ctx_.getApplyViewContext(), preFeeBalance_, {.ownerCountDelta = 1});
if (auto const ret = checkReserve(
ctx_.getApplyViewContext(), sleIssuer, preFeeBalance_, {.ownerCountDelta = 1}, j_);
!isTesSuccess(ret))
return ret;
@@ -160,7 +159,7 @@ CredentialCreate::doApply()
return tecDIR_FULL;
sleCred->setFieldU64(sfIssuerNode, *page);
sleIssuer.increaseOwnerCount(ctx_.getApplyViewContext(), 1);
increaseOwnerCount(ctx_.getApplyViewContext(), sleIssuer, 1, j_);
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCred);
}
@@ -3,7 +3,6 @@
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/SponsorHelpers.h>
@@ -53,7 +52,7 @@ DelegateSet::preclaim(PreclaimContext const& ctx)
if (!ctx.view.exists(keylet::account(ctx.tx[sfAccount])))
return terNO_ACCOUNT; // LCOV_EXCL_LINE
auto const sleAuthorize = AccountRootEntryR(ctx.tx[sfAuthorize], ctx.view);
auto const sleAuthorize = ctx.view.read(keylet::account(ctx.tx[sfAuthorize]));
if (!sleAuthorize)
return tecNO_TARGET;
@@ -73,7 +72,7 @@ DelegateSet::preclaim(PreclaimContext const& ctx)
TER
DelegateSet::doApply()
{
auto sleOwner = AccountRootEntryW(accountID_, ctx_.view(), ctx_.journal);
auto const sleOwner = ctx_.view().peek(keylet::account(accountID_));
if (!sleOwner)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -99,8 +98,12 @@ DelegateSet::doApply()
if (permissions.empty())
return tecINTERNAL; // LCOV_EXCL_LINE
if (auto const ret = sleOwner.checkReserve(
ctx_.getApplyViewContext(), preFeeBalance_, {.ownerCountDelta = 1});
if (auto const ret = checkReserve(
ctx_.getApplyViewContext(),
sleOwner,
preFeeBalance_,
{.ownerCountDelta = 1},
ctx_.journal);
!isTesSuccess(ret))
return ret;
@@ -130,7 +133,7 @@ DelegateSet::doApply()
(*sle)[sfDestinationNode] = *destPage;
ctx_.view().insert(sle);
sleOwner.increaseOwnerCount(ctx_.getApplyViewContext(), 1);
increaseOwnerCount(ctx_.getApplyViewContext(), sleOwner, 1, ctx_.journal);
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sle);
return tesSUCCESS;
@@ -167,7 +170,7 @@ DelegateSet::deleteDelegate(ApplyView& view, SLE::Ref sle, beast::Journal j)
}
// Only the delegating account's owner count was incremented on creation
auto sleOwner = AccountRootEntryW(delegator, view);
auto const sleOwner = view.peek(keylet::account(delegator));
if (!sleOwner)
return tecINTERNAL; // LCOV_EXCL_LINE
+2 -3
View File
@@ -5,7 +5,6 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AMMHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
@@ -120,7 +119,7 @@ AMMBid::preclaim(PreclaimContext const& ctx)
{
for (auto const& account : ctx.tx.getFieldArray(sfAuthAccounts))
{
if (!AccountRootEntryR(account[sfAccount], ctx.view))
if (!ctx.view.read(keylet::account(account[sfAccount])))
{
JLOG(ctx.j.debug()) << "AMM Bid: Invalid Account.";
return terNO_ACCOUNT;
@@ -209,7 +208,7 @@ applyBid(ApplyContext& ctx, Sandbox& sb, AccountID const& account, beast::Journa
auto validOwner = [&](AccountID const& account) {
// Valid range is 0-19 but the tailing slot pays MinSlotPrice
// and doesn't refund so the check is < instead of <= to optimize.
return timeSlot && *timeSlot < kTailingSlot && AccountRootEntryR(account, sb);
return timeSlot && *timeSlot < kTailingSlot && sb.read(keylet::account(account));
};
auto updateSlot = [&](std::uint32_t fee, Number const& minPrice, Number const& burn) -> TER {
@@ -5,7 +5,6 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AMMHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -103,11 +102,11 @@ AMMClawback::preclaim(PreclaimContext const& ctx)
{
auto const asset = ctx.tx[sfAsset];
auto const asset2 = ctx.tx[sfAsset2];
auto const sleIssuer = AccountRootEntryR(ctx.tx[sfAccount], ctx.view);
auto const sleIssuer = ctx.view.read(keylet::account(ctx.tx[sfAccount]));
if (!sleIssuer)
return terNO_ACCOUNT; // LCOV_EXCL_LINE
if (!AccountRootEntryR(ctx.tx[sfHolder], ctx.view))
if (!ctx.view.read(keylet::account(ctx.tx[sfHolder])))
return terNO_ACCOUNT;
auto const ammSle = ctx.view.read(keylet::amm(asset, asset2));
@@ -179,7 +178,7 @@ AMMClawback::applyGuts(Sandbox& sb)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const ammAccount = (*ammSle)[sfAccount];
auto const accountSle = AccountRootEntryR(ammAccount, sb);
auto const accountSle = sb.read(keylet::account(ammAccount));
if (!accountSle)
return tecINTERNAL; // LCOV_EXCL_LINE
+3 -4
View File
@@ -5,7 +5,6 @@
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AMMHelpers.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
@@ -134,7 +133,7 @@ AMMCreate::preclaim(PreclaimContext const& ctx)
if (asset.holds<MPTIssue>() || isXRP(asset))
return false;
if (auto const issuerAccount = AccountRootEntryR(asset.getIssuer(), view))
if (auto const issuerAccount = view.read(keylet::account(asset.getIssuer())))
return !issuerAccount->isFlag(lsfDefaultRipple);
return false;
@@ -174,7 +173,7 @@ AMMCreate::preclaim(PreclaimContext const& ctx)
}
auto isLPToken = [&](STAmount const& amount) -> bool {
if (auto const sle = AccountRootEntryR(amount.asset().getIssuer(), ctx.view))
if (auto const sle = ctx.view.read(keylet::account(amount.asset().getIssuer())))
return sle->isFieldPresent(sfAMMID);
return false;
};
@@ -238,7 +237,7 @@ AMMCreate::preclaim(PreclaimContext const& ctx)
[&](Issue const& issue) -> TER {
if (isXRP(issue))
return tesSUCCESS;
auto const sle = AccountRootEntryR(issue.account, ctx.view);
auto const sle = ctx.view.read(keylet::account(issue.account));
if (!sle)
return tecINTERNAL; // LCOV_EXCL_LINE
if (sle->isFlag(lsfAllowTrustLineClawback))
@@ -6,8 +6,8 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AMMHelpers.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
@@ -344,7 +344,7 @@ AMMWithdraw::applyGuts(Sandbox& sb)
if (!ammSle)
return {tecINTERNAL, false}; // LCOV_EXCL_LINE
auto const ammAccountID = (*ammSle)[sfAccount];
auto const accountSle = AccountRootEntryR(ammAccountID, sb);
auto const accountSle = sb.read(keylet::account(ammAccountID));
if (!accountSle)
return {tecINTERNAL, false}; // LCOV_EXCL_LINE
auto const lpTokens = ammLPHolds(ctx_.view(), *ammSle, ctx_.tx[sfAccount], ctx_.journal);
@@ -691,15 +691,16 @@ AMMWithdraw::withdraw(
reserveHandling == ReserveHandling::IgnoreReserve)
return tesSUCCESS;
auto sleAccount = AccountRootEntryW(account, view, journal);
auto sleAccount = view.peek(keylet::account(account));
if (!sleAccount)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const balance = (*sleAccount)[sfBalance]->xrp();
// See also TrustSet::doApply() and MPTokenAuthorize::authorize()
XRPAmount const reserve(
(sleAccount.ownerCount() < 2) ? XRPAmount(beast::kZero)
: sleAccount.reserve({.ownerCountDelta = 1}));
(ownerCount(sleAccount, journal) < 2)
? XRPAmount(beast::kZero)
: accountReserve(view, sleAccount, journal, {.ownerCountDelta = 1}));
auto const balanceAdj = std::max(priorBalance, balance);
if (balanceAdj < reserve)
@@ -1,8 +1,6 @@
#include <xrpl/tx/transactors/dex/OfferCancel.h>
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/OfferHelpers.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
@@ -35,7 +33,7 @@ OfferCancel::preclaim(PreclaimContext const& ctx)
auto const id = ctx.tx[sfAccount];
auto const offerSequence = ctx.tx[sfOfferSequence];
auto const sle = AccountRootEntryR(id, ctx.view);
auto const sle = ctx.view.read(keylet::account(id));
if (!sle)
return terNO_ACCOUNT;
@@ -56,7 +54,7 @@ OfferCancel::doApply()
{
auto const offerSequence = ctx_.tx[sfOfferSequence];
auto const sle = AccountRootEntryW(accountID_, view());
auto const sle = view().read(keylet::account(accountID_));
if (!sle)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -9,7 +9,7 @@
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/AccountRootEntry.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>
@@ -181,7 +181,7 @@ OfferCreate::preclaim(PreclaimContext const& ctx)
auto const cancelSequence = ctx.tx[~sfOfferSequence];
auto const sleCreator = AccountRootEntryR(id, ctx.view);
auto const sleCreator = ctx.view.read(keylet::account(id));
if (!sleCreator)
return terNO_ACCOUNT;
@@ -288,7 +288,7 @@ OfferCreate::checkAcceptAsset(
// Only valid for custom currencies
XRPL_ASSERT(!isXRP(asset), "xrpl::OfferCreate::checkAcceptAsset : input is not XRP");
auto const issuerAccount = AccountRootEntryR(asset.getIssuer(), view);
auto const issuerAccount = view.read(keylet::account(asset.getIssuer()));
if (!issuerAccount)
{
@@ -707,14 +707,14 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
// Not XRP or MPT
if (!saTakerPays.integral())
{
auto const sle = AccountRootEntryR(uPaysIssuerID, sb);
auto const sle = sb.read(keylet::account(uPaysIssuerID));
if (sle && sle->isFieldPresent(sfTickSize))
uTickSize = std::min(uTickSize, (*sle)[sfTickSize]);
}
// Not XRP or MPT
if (!saTakerGets.integral())
{
auto const sle = AccountRootEntryR(uGetsIssuerID, sb);
auto const sle = sb.read(keylet::account(uGetsIssuerID));
if (sle && sle->isFieldPresent(sfTickSize))
uTickSize = std::min(uTickSize, (*sle)[sfTickSize]);
}
@@ -884,12 +884,12 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
return {tesSUCCESS, true};
}
auto sleCreator = AccountRootEntryW(accountID_, sb, viewJ);
auto const sleCreator = sb.peek(keylet::account(accountID_));
if (!sleCreator)
return {tefINTERNAL, false};
{
XRPAmount const reserve = sleCreator.reserve({.ownerCountDelta = 1});
XRPAmount const reserve = accountReserve(sb, sleCreator, viewJ, {.ownerCountDelta = 1});
if (preFeeBalance_ < reserve)
{
// If we are here, the signing account had an insufficient reserve
@@ -923,8 +923,7 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
}
// Update owner count.
std::optional<AccountRootEntryW> noSponsor;
sleCreator.increaseOwnerCount(noSponsor, 1);
increaseOwnerCount(sb, sleCreator, {}, 1, viewJ);
JLOG(j_.trace()) << "adding to book: " << to_string(saTakerPays.asset()) << " : "
<< to_string(saTakerGets.asset())
+1 -2
View File
@@ -4,7 +4,6 @@
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
@@ -47,7 +46,7 @@ DIDDelete::deleteSLE(ApplyView& view, SLE::pointer sle, AccountID const owner, b
// LCOV_EXCL_STOP
}
auto sleOwner = AccountRootEntryW(owner, view);
auto const sleOwner = view.peek(keylet::account(owner));
if (!sleOwner)
return tecINTERNAL; // LCOV_EXCL_LINE
+6 -7
View File
@@ -3,7 +3,7 @@
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/AccountRootEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
@@ -20,7 +20,6 @@
#include <cstddef>
#include <memory>
#include <optional>
namespace xrpl {
@@ -66,14 +65,15 @@ DIDSet::preflight(PreflightContext const& ctx)
static TER
addSLE(ApplyContext& ctx, SLE::Ref sle, AccountID const& owner)
{
auto sleAccount = AccountRootEntryW(owner, ctx.view(), ctx.journal);
auto const sleAccount = ctx.view().peek(keylet::account(owner));
if (!sleAccount)
return tefINTERNAL; // LCOV_EXCL_LINE
// Check reserve availability for new object creation
{
auto const balance = STAmount((*sleAccount)[sfBalance]).xrp();
auto const reserve = sleAccount.reserve({.ownerCountDelta = 1});
auto const reserve =
accountReserve(ctx.view(), sleAccount, ctx.journal, {.ownerCountDelta = 1});
if (balance < reserve)
return tecINSUFFICIENT_RESERVE;
@@ -90,9 +90,8 @@ addSLE(ApplyContext& ctx, SLE::Ref sle, AccountID const& owner)
return tecDIR_FULL; // LCOV_EXCL_LINE
(*sle)[sfOwnerNode] = *page;
}
std::optional<AccountRootEntryW> noSponsor;
sleAccount.increaseOwnerCount(noSponsor, 1);
sleAccount.update();
increaseOwnerCount(ctx.view(), sleAccount, {}, 1, ctx.journal);
ctx.view().update(sleAccount);
return tesSUCCESS;
}
Loaded 100 of 211 files, more files were not shown because too many files have changed in this diff. Show more