Compare commits

..

42 Commits

Author SHA1 Message Date
Ed Hennis
81e06a9ba8 Merge remote-tracking branch 'XRPLF/develop' into ximinez/directory
* XRPLF/develop:
  fix: Update PermissionedDEX invariant domain tracking for valid offer replacement (7387)
  feat: Check default fields are not default when serializing (6267)
  test: Migrate csf and xrpld-consensus Beast non-JTx tests to GTest (7046)
  test: Modularize Peerfinder component and migrate Peerfinder tests from Beast to GTest and GMock (7054)
  test: Add an RAII class to manage the env.parseFailureExpected flag (7669)
  build: Use custom libc in a devshell by default (7852)
  feat: Add fixCleanup3_4_0 amendment (no functionality yet) (7854)
  ci: Add llvm-tools-preview to rust toolchain (7853)
  ci: Update CI image (7850)
  ci: Update XRPLF/actions (7849)
  chore: Clean up grammar in PR template (7846)
  build: Create versioned compiler/tooling symlinks in nix environments (7844)
  ci: Use rust-overlay to bring Rust into nix (7837)
2026-07-23 21:03:45 -04:00
Ed Hennis
b3141d91fa Merge branch 'develop' into ximinez/directory 2026-07-21 19:29:00 -04:00
Ed Hennis
1b1cd4c260 Merge remote-tracking branch 'XRPLF/develop' into ximinez/directory
* XRPLF/develop: (21 commits)
  fix: Re-store nodes missing from both backends during online_delete rotation (7763)
  fix: Add amendment sponsor for AccountRootsDeletedClean (7801)
  fix: Update base_uint and test changes released in 3.1.3 (7570)
  fix: Handle rounding just above kMaxRep more accurately (7389)
  fix: Document and assert "after" is never null in invariants (7354)
  ci: Run full matrix only on `Ready to merge` or `Full CI build` labeled PRs (7689)
  fix: Strengthen Clawback invariant checks for MPT balances (7285)
  test: Add unit tests for IP address related functions (7744)
  ci: Add Rust to Nix docker image (7571)
  docs: Add more information about pre-commit hooks and how to set them up (7802)
  test: Add JSON array size tests (7592)
  chore: Enable most readability checks (7772)
  ci: Do not run conflict checker when label is applied (7774)
  chore: Run clang_tidy_check with `pass_filenames: false` from pre-commit (7800)
  feat: Add delegate filter param for account_tx RPC (6126)
  refactor: Move `jss.h` `include` out of `Indexes.h` (7799)
  test: Add tests for check doxygen style (7795)
  style: Add pre-commit hook to check doxygen style (7794)
  style: Unify style for all Doxygen comments (7776)
  fix: Improve Number addition/subtraction rounding (7369)
  ...
2026-07-14 20:37:19 -04:00
Ed Hennis
a482d6aced Merge branch 'develop' into ximinez/directory 2026-07-09 19:50:00 -04:00
Ed Hennis
299627298f Merge remote-tracking branch 'XRPLF/develop' into ximinez/directory
* XRPLF/develop:
  chore: Enable most cppcoreguidelines checks (7660)
  test: Migrate basics Beast tests to GTest (7136)
  test: Migrate resource, shamap Beast tests to GTest (7133)
  chore: Enable most misc checks (7663)
  chore: Fix unity build (7730)
  chore: Enable most modernize checks (7664)
  chore: Delete dead code (7718)
  chore: Enable modernize-use-constraints (7715)
  chore: Enable modernize-avoid-bind (7711)
  chore: Enable modernize-use-auto (7707)
  build: Add protobuf dependencies to Nix (7706)
  feat: Enable ConfidentialTransfer and BatchV1_1 (7698)
  chore: Enable modernize-unary-static-assert (7705)
  chore: Make clang-tidy happy on macOS (7701)
  chore: Improve pre-commit hooks (7702)
  refactor: Retire DisallowIncomingV1 fix (7364)
  build: Add verify-headers target to cleanup headers (7670)
2026-07-07 18:17:50 -04:00
Ed Hennis
640798696b Merge remote-tracking branch 'XRPLF/develop' into ximinez/directory
* XRPLF/develop:
  refactor: Retire InnerObjTemplate fix (7368)
  fix: Disable AMM creation with Vault shares (7666)
  test: Add tests for TMProofPathResponse and TMReplayDeltaResponse invalid hash/key sizes (7593)
  ci: [DEPENDABOT] bump actions/setup-python from 6.2.0 to 6.3.0 (7657)
  build: Don't reuse binaries between different C++ versions (7681)
  chore: Update pre-commit hooks && actions (7686)
  feat: Add an invariant to ensure object deletion also deletes its pseudo-account (7445)
  feat: Add Batch (XLS-56) V1_1 (6446)
  feat: Introduce lending 1.1 amendment and add `MemoData` field to `VaultDelete` transaction (6324)
2026-07-01 16:10:38 -04:00
Ed Hennis
47512afad5 Merge remote-tracking branch 'XRPLF/develop' into ximinez/directory
* XRPLF/develop: (69 commits)
  chore: Use std::ranges where possible (7634)
  ci: Use macOS 26 Tahoe with apple-clang 21 (7601)
  build: Mark sec256k1 and mpt-crypto as transitive headers (7658)
  chore: Add a script to nicely format clang-tidy output (7650)
  chore: Enable most bugprone checks (7643)
  feat: Confidential Transfer for MPT (5860)
  fix: Use trustline balance direction to validate IOU PaymentMint/PaymentBurn (7584)
  fix: Unify freeze checks for pseudo-account deposit/withdraw (7382)
  fix: Block delegate tx from being queued (7640)
  chore: Enable groups of clang-tidy checks by default (7637)
  ci: Better determine when we need to run full clang-tidy (7635)
  refactor: Retire NFTokenReserve fix (7367)
  refactor: Retire Clawback amendment (7353)
  refactor: Rename (mostly keylet) functions to more closely match the docs (7059)
  build: Switch to a new conan XRPLF remote, again (7638)
  chore: Revert "build: Switch to a new conan XRPLF remote (7622)" (7623)
  build: Switch to a new conan XRPLF remote (7622)
  build: Align xrpld RPM packaging with DEB package (7529)
  chore: Use clang-tidy v22 new features (7427)
  build: Patch nix binaries in CMake (7539)
  ...
2026-06-30 17:16:29 -04:00
Ed Hennis
ff3708a757 Merge remote-tracking branch 'XRPLF/develop' into ximinez/directory
* XRPLF/develop: (48 commits)
  test: Add null check unit test for `Oracle::aggregatePrice` (7306)
  ci: Patch conan recipe for Nix to be able to use on macOS (7532)
  ci: Run sanitizers on release builds too (7527)
  fix: Correct hybrid offer deletion on credential expiry (6843)
  ci: Make sanitizer flags lists in the profile, not a string (7449)
  ci: Make configurations launch on certain event types (7447)
  fix: Add [[maybe_unused]] to fix320Enabled for assert=OFF builds (7446)
  ci: Add `gh` and `file` to nix packages (7444)
  fix: Disable transaction invariants (7409)
  perf: Dispatch "hasInvalidAmount()" on type tag instead of dynamic_cast (7402)
  refactor: Retire fixUniversalNumber amendment (5962)
  test: Do not create data directory for memory databases (7323)
  ci: Launch upload-conan-deps on profile change (7442)
  fix: Fix Number comparison operator (7406)
  feat: Use C++ 23 standard (7431)
  refactor: Introduce XRPL_ASSERT_IF for amendment-gated assertions (7378)
  refactor: Change config section and key string literals into constants (7095)
  refactor: Use `std::move` and `std::string_view` where possible (7424)
  refactor: Use const function arguments where possible (7423)
  ci: Use XRPLF/actions build-multiarch-image workflow (7428)
  ...
2026-06-12 11:50:43 -04:00
Ed Hennis
391a1e442c Merge remote-tracking branch 'XRPLF/develop' into ximinez/directory
* XRPLF/develop: (41 commits)
  release: Bump version to 3.2.0-rc2 (7348)
  refactor: Enable support for `fixCleanup3_2_0` amendment (7347)
  release: Bump version to 3.2.0-rc1 (7335)
  fix: Fix a rounding error at the `Number::maxRep` cusp (7051)
  ci: Only push docker images in XRPLF/rippled (7330)
  ci: [DEPENDABOT] bump docker/setup-buildx-action from 4.0.0 to 4.1.0 (7322)
  ci: [DEPENDABOT] bump codecov/codecov-action from 6.0.0 to 6.0.1 (7321)
  ci: [DEPENDABOT] bump docker/build-push-action from 7.1.0 to 7.2.0 (7320)
  ci: [DEPENDABOT] bump docker/metadata-action from 6.0.0 to 6.1.0 (7319)
  ci: [DEPENDABOT] bump docker/login-action from 4.1.0 to 4.2.0 (7318)
  fix: Update `clang-tidy` to include `src/tests` directory header check (7307)
  chore: Pin Python packages for codegen using uv (7329)
  style: Use shfmt instead of bashate (7326)
  fix: Fix edge-case where vault-depositor may get stuck (7139)
  fix: Fix `VaultInvariant` and `VaultDeposit` precision bugs at IOU scale boundaries (7272)
  ci: Add clang to nix images (7308)
  fix: Include management-fee delta in doOverpayment assertion (7039)
  fix: Fix clang-tidy pre-commit hook to locate compile_commands.json from repo root (7325)
  fix: Use consistent scale for `debtTotal` (7093)
  fix: Skip deleted book directories and non-root modifications in `ValidBookDirectory` invariant (7312)
  ...
2026-05-27 15:33:45 -04:00
Ed Hennis
9e77212900 Merge branch 'develop' into ximinez/directory 2026-05-19 16:53:55 -04:00
Ed Hennis
93f5a0e217 Merge branch 'develop' into ximinez/directory 2026-05-19 10:15:35 -04:00
Ed Hennis
71367f361c Merge branch 'develop' into ximinez/directory 2026-05-19 05:16:12 -04:00
Ed Hennis
931d21b2a7 Merge remote-tracking branch 'XRPLF/develop' into ximinez/directory
* XRPLF/develop:
  refactor: Clean up comments post-clang-tidy changes (7283)
  release: Set version to 3.3.0-b0 (7280)
  refactor: Rename static constants (7120)
  refactor: Use `isFlag` where possible instead of bitwise math (7278)
  ci: Update XRPLF/actions (7281)
2026-05-16 09:49:20 -04:00
Ed Hennis
c99feb82e7 Merge branch 'develop' into ximinez/directory 2026-05-14 20:39:26 -04:00
Ed Hennis
7b53a5e0c5 Merge remote-tracking branch 'XRPLF/develop' into ximinez/directory
* XRPLF/develop:
  chore: Consolidate fix amendments (7134)
  ci: Add Conan retry (7147)
  fix: Backport Permissioned Domains fixes (7016)
  refactor: Move unhex lookup table out of function (7104)
  refactor: Improve Forwarded header field parsing (7126)
  fix: Check network ID in `transactionSignFor` (7102)
  feat: Implement nix-based Dockerfile for CI (7083)
2026-05-14 10:46:04 -04:00
Ed Hennis
4a02518497 Merge branch 'develop' into ximinez/directory 2026-05-13 12:03:59 -04:00
Ed Hennis
0b6c3630cc Merge branch 'develop' into ximinez/directory 2026-05-12 19:19:05 -04:00
Ed Hennis
4d04ba5be5 Merge branch 'develop' into ximinez/directory 2026-05-12 16:26:28 -04:00
Ed Hennis
ed53557d41 Merge branch 'develop' into ximinez/directory 2026-05-11 13:34:31 -04:00
Ed Hennis
e4d10393f3 Merge branch 'develop' into ximinez/directory 2026-05-07 18:10:21 -04:00
Ed Hennis
fcc7f57e82 Merge branch 'develop' into ximinez/directory 2026-05-07 14:18:48 -04:00
Ed Hennis
a25229f154 Merge branch 'develop' into ximinez/directory 2026-05-07 13:28:50 -04:00
Ed Hennis
eb6eaf2532 Merge branch 'develop' into ximinez/directory 2026-05-06 22:34:41 -04:00
Ed Hennis
ff987fc7c6 Merge branch 'develop' into ximinez/directory 2026-05-06 14:18:20 -04:00
Ed Hennis
d21137c4c1 Merge remote-tracking branch 'XRPLF/develop' into ximinez/directory
* XRPLF/develop:
  fix: Fix regressions in `server_definitions` (7008)
  chore: Do not duplicate sanitizer flags (7058)
  ci: Run pre-commit on diff in clang-tidy workflow (7078)
  ci: Use XRPLF/create-issue (7076)
  ci: Rewrite clang-tidy workflow(s) in a reusable manner (7062)
  chore: Ignore identifier-naming update in git blame (7066)
  refactor: Enable clang-tidy `readability-identifier-naming` check (6571)
2026-05-05 16:45:19 -04:00
Ed Hennis
ac7db2e621 Remove orphaned code that was introduced by a bad merge or rebase 2026-05-05 15:48:00 -04:00
Ed Hennis
42005a8080 Merge branch 'develop' into ximinez/directory 2026-05-01 13:59:22 -04:00
Ed Hennis
1f7b1b3a78 Merge remote-tracking branch 'XRPLF/develop' into ximinez/directory
* XRPLF/develop:
  feat: Create new transaction testing framework `TxTest` (6537)
  feat: Add cleanup amendment for 3.2.0 (7037)
  fix: Fix ubsan flagged issues (6151)
2026-04-28 15:28:15 -05:00
Ed Hennis
80b90544c5 Merge branch 'develop' into ximinez/directory 2026-04-25 14:46:02 -04:00
Ed Hennis
00b9a8cd67 Merge branch 'develop' into ximinez/directory 2026-04-23 15:56:20 -04:00
Ed Hennis
3be49f814a Merge branch 'develop' into ximinez/directory 2026-04-22 23:40:54 -04:00
Ed Hennis
1674fabe81 Merge branch 'develop' into ximinez/directory 2026-04-22 14:49:21 -04:00
Ed Hennis
6dfa47ce7a Merge branch 'develop' into ximinez/directory 2026-04-22 13:10:52 -04:00
Ed Hennis
bef095be65 Merge branch 'develop' into ximinez/directory 2026-04-21 18:58:08 -04:00
Ed Hennis
8e5d774c36 Merge branch 'develop' into ximinez/directory 2026-04-20 17:49:55 -04:00
Ed Hennis
fb8fb30f6c Merge branch 'develop' into ximinez/directory 2026-04-20 15:45:12 -04:00
Ed Hennis
a553001125 Merge branch 'develop' into ximinez/directory 2026-04-20 11:39:16 -04:00
Ed Hennis
57782e84ee Merge branch 'develop' into ximinez/directory 2026-04-17 18:14:35 -04:00
Ed Hennis
9d5076c8a9 Merge branch 'develop' into ximinez/directory 2026-04-16 13:44:45 -04:00
Ed Hennis
1af379e09f Merge branch 'develop' into ximinez/directory 2026-04-15 19:06:37 -04:00
Ed Hennis
1ced0875ae Merge branch 'develop' into ximinez/directory 2026-04-15 14:29:04 -04:00
Ed Hennis
53e6d7580a rabbit hole: refactor dirAdd to find gaps in "full" directories.
- This would potentially be very expensive to implement, so don't.
- However, it might be a good start for a ledger fix option.
2026-04-13 19:50:28 -04:00
207 changed files with 3489 additions and 12752 deletions

View File

@@ -75,8 +75,6 @@ Checks: "-*,
# readability-static-accessed-through-instance, # this check is probably unnecessary. It makes the code less readable
# ---
FormatStyle: file
CheckOptions:
bugprone-unsafe-functions.ReportMoreUnsafeFunctions: true
bugprone-unused-return-value.CheckedReturnTypes: ::std::error_code;::std::error_condition;::std::errc

View File

@@ -174,6 +174,7 @@ words:
- MPTAMM
- MPTDEX
- Merkle
- Metafuncton
- misprediction
- missingok
- mptbalance

View File

@@ -15,7 +15,3 @@ updates:
commit-message:
prefix: "ci: [DEPENDABOT] "
target-branch: develop
groups:
github-actions:
patterns:
- "*"

View File

@@ -130,9 +130,12 @@ test.ledger > xrpl.json
test.ledger > xrpl.ledger
test.ledger > xrpl.protocol
test.nodestore > test.jtx
test.nodestore > test.unit_test
test.nodestore > xrpl.basics
test.nodestore > xrpl.config
test.nodestore > xrpld.core
test.nodestore > xrpl.nodestore
test.nodestore > xrpl.protocol
test.nodestore > xrpl.rdb
test.overlay > test.jtx
test.overlay > test.unit_test

View File

@@ -46,6 +46,9 @@ for DIRECTORY in "${DIRECTORIES[@]}"; do
done
done
# Special case for NuDBFactory that has ripple twice in the test suite name.
${SED_COMMAND} -i -E 's/(BEAST_DEFINE_TESTSUITE.+)ripple(.+)/\1xrpl\2/g' src/test/nodestore/NuDBFactory_test.cpp
DIRECTORY=$1
find "${DIRECTORY}" -type f -name "*.md" | while read -r FILE; do
echo "Processing file: ${FILE}"

View File

@@ -1,22 +1,13 @@
{
"image_tag": "sha-fecfc0c",
"image_tag": "sha-3122de8",
"configs": {
"ubuntu": [
{
"compiler": ["gcc"],
"build_type": ["Debug"],
"arch": ["amd64"],
"minimal": true,
"suffix": "coverage",
"extra_cmake_args": "-DUNIT_TEST_REFERENCE_FEE=500 -Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0"
},
{
"compiler": ["clang"],
"build_type": ["Release"],
"arch": ["amd64"],
"minimal": true
},
{
"compiler": ["gcc"],
"build_type": ["Release"],
@@ -38,6 +29,14 @@
"sanitizers": ["address", "undefinedbehavior"]
},
{
"compiler": ["gcc"],
"build_type": ["Debug"],
"arch": ["amd64"],
"minimal": true,
"suffix": "coverage",
"extra_cmake_args": "-DUNIT_TEST_REFERENCE_FEE=500 -Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0"
},
{
"compiler": ["clang"],
"build_type": ["Debug"],

View File

@@ -13,7 +13,6 @@ on:
- "!nix/docker/README.md"
- "!nix/devshell.nix"
- "bin/check-tools.sh"
- "bin/default-loader-path.sh"
- "bin/install-sanitizer-libs.sh"
pull_request:
paths:
@@ -25,7 +24,6 @@ on:
- "!nix/docker/README.md"
- "!nix/devshell.nix"
- "bin/check-tools.sh"
- "bin/default-loader-path.sh"
- "bin/install-sanitizer-libs.sh"
workflow_dispatch:

View File

@@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Write PR body to file
env:

View File

@@ -1,114 +0,0 @@
# Verifies the committed snapshots of `bin/check-tools.sh` output for each Nix
# environment (see nix/check-tools/). If the environment changes — a new image
# tag, an updated flake.lock, a different tool list — without the matching
# snapshot being regenerated and committed, this workflow fails so the drift is
# caught in review.
#
# To regenerate the snapshots, see nix/check-tools/README.md.
name: Check tools
on:
pull_request:
paths:
- ".github/workflows/check-tools.yml"
- ".github/scripts/strategy-matrix/linux.json"
- "bin/check-tools.sh"
- "nix/**"
- "flake.nix"
- "flake.lock"
- "rust-toolchain.toml"
push:
branches:
- "develop"
paths:
- ".github/workflows/check-tools.yml"
- ".github/scripts/strategy-matrix/linux.json"
- "bin/check-tools.sh"
- "nix/**"
- "flake.nix"
- "flake.lock"
- "rust-toolchain.toml"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
jobs:
# The nix-nixos image tag is pinned alongside the build matrix in linux.json,
# so snapshots are checked against the exact image CI builds against.
linux-image-tag:
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.tag.outputs.tag }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Read nix image tag
id: tag
run: echo "tag=$(jq -r .image_tag .github/scripts/strategy-matrix/linux.json)" >>"${GITHUB_OUTPUT}"
# One job for all environments; they differ only in whether the tools come
# from the nix-nixos container (Linux) or `nix develop` (macOS).
check-tools:
needs: linux-image-tag
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-latest
snapshot: nix/check-tools/nix-ubuntu-amd64.txt
nix_develop: false
- runner: ubuntu-24.04-arm
snapshot: nix/check-tools/nix-ubuntu-arm64.txt
nix_develop: false
- runner: macos-26-apple-clang-21
snapshot: nix/check-tools/macos.txt
nix_develop: true
runs-on: ${{ matrix.runner }}
# Linux runs inside the pinned nix-nixos image; macOS runs natively and uses
# the flake's dev shell instead (see the run step below).
container: ${{ !matrix.nix_develop && format('ghcr.io/xrplf/xrpld/nix-ubuntu:{0}', needs.linux-image-tag.outputs.tag) || null }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@c00c22ada3bd6bcda48fcb0d62fbbab49fec8a0f
with:
enable_ccache: false
- name: Regenerate snapshot
env:
CHECK_TOOLS_SKIP_CLONE: "1"
# check-tools.sh skips some macOS tools when CI is set; the snapshots
# capture the full `nix develop` environment, so unset it here.
CI: ""
run: |
if [ "${{ matrix.nix_develop }}" = "true" ]; then
# `nix develop` prints the dev-shell greeting first; keep only the
# check-tools.sh output (from the "Detected OS:" line onward).
nix --extra-experimental-features "nix-command flakes" develop \
-c bash bin/check-tools.sh | sed -n '/^Detected OS:/,$p' >"${{ matrix.snapshot }}"
else
bash bin/check-tools.sh >"${{ matrix.snapshot }}"
fi
- name: Verify snapshot is up to date
run: |
if ! git diff --exit-code -- "${{ matrix.snapshot }}"; then
echo "::error::${{ matrix.snapshot }} is out of date. Regenerate it (see nix/check-tools/README.md) and commit the result."
exit 1
fi
- name: Upload regenerated snapshot
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: check-tools-${{ runner.os }}-${{ runner.arch }}
path: ${{ matrix.snapshot }}

View File

@@ -52,7 +52,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Determine changed files
# This step checks whether any files have changed that should
# cause the next jobs to run. We do it this way rather than
@@ -90,7 +90,6 @@ jobs:
.clang-tidy
.codecov.yml
bin/check-tools.sh
bin/default-loader-path.sh
cfg/**
cmake/**
conan/**

View File

@@ -28,7 +28,6 @@ on:
- ".clang-tidy"
- ".codecov.yml"
- "bin/check-tools.sh"
- "bin/default-loader-path.sh"
- "cfg/**"
- "cmake/**"
- "conan/**"

View File

@@ -41,13 +41,13 @@ env:
jobs:
build:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-fecfc0c
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3122de8
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@c00c22ada3bd6bcda48fcb0d62fbbab49fec8a0f
uses: XRPLF/actions/prepare-runner@e4b6449d55a61c002d7c3fdfa6c20f721ede0606
with:
enable_ccache: false

View File

@@ -110,10 +110,10 @@ jobs:
uses: XRPLF/actions/cleanup-workspace@c7d9ce5ebb03c752a354889ecd870cadfc2b1cd4
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@c00c22ada3bd6bcda48fcb0d62fbbab49fec8a0f
uses: XRPLF/actions/prepare-runner@e4b6449d55a61c002d7c3fdfa6c20f721ede0606
with:
enable_ccache: ${{ inputs.ccache_enabled }}
@@ -266,7 +266,7 @@ jobs:
./xrpld --definitions | python3 -m json.tool >server_definitions.json
- name: Upload server definitions
if: ${{ github.event.repository.visibility == 'public' && inputs.config_name == 'ubuntu-gcc-debug-amd64-coverage' }}
if: ${{ github.event.repository.visibility == 'public' && inputs.config_name == 'debian-gcc-release-amd64' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: server-definitions

View File

@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Check levelization
run: python .github/scripts/levelization/generate.py
- name: Check for differences

View File

@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Check definitions
run: .github/scripts/rename/definitions.sh .
- name: Check copyright notices

View File

@@ -34,16 +34,16 @@ 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-fecfc0c"
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-3122de8"
permissions:
contents: read
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@c00c22ada3bd6bcda48fcb0d62fbbab49fec8a0f
uses: XRPLF/actions/prepare-runner@e4b6449d55a61c002d7c3fdfa6c20f721ede0606
with:
enable_ccache: false
@@ -95,7 +95,7 @@ jobs:
TARGETS: ${{ needs.determine-files.outputs.need_full_run != 'true' && needs.determine-files.outputs.cpp_changed_files || 'include src tests' }}
run: |
set -o pipefail
run-clang-tidy -j ${{ steps.nproc.outputs.nproc }} -p "${BUILD_DIR}" -quiet -fix -format -allow-no-checks ${TARGETS} 2>&1 | tee "${OUTPUT_FILE}"
run-clang-tidy -j ${{ steps.nproc.outputs.nproc }} -p "${BUILD_DIR}" -quiet -fix -allow-no-checks ${TARGETS} 2>&1 | tee "${OUTPUT_FILE}"
- name: Print filtered clang-tidy errors
if: ${{ steps.run_clang_tidy.outcome != 'success' }}

View File

@@ -27,7 +27,7 @@ jobs:
matrix: ${{ steps.generate.outputs.matrix }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
@@ -54,7 +54,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Download pre-built binary
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1

View File

@@ -23,7 +23,7 @@ jobs:
matrix: ${{ steps.generate.outputs.matrix }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0

View File

@@ -40,14 +40,14 @@ defaults:
jobs:
upload:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-fecfc0c
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3122de8
env:
REMOTE_NAME: ${{ inputs.remote_name }}
CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.remote_username }}
CONAN_PASSWORD_XRPLF: ${{ secrets.remote_password }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Generate build version number
id: version

View File

@@ -65,10 +65,10 @@ jobs:
uses: XRPLF/actions/cleanup-workspace@c7d9ce5ebb03c752a354889ecd870cadfc2b1cd4
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@c00c22ada3bd6bcda48fcb0d62fbbab49fec8a0f
uses: XRPLF/actions/prepare-runner@e4b6449d55a61c002d7c3fdfa6c20f721ede0606
with:
enable_ccache: false

View File

@@ -348,14 +348,12 @@ run-clang-tidy -p build -allow-no-checks src tests
```
This will check all source files in the `src`, `include` and `tests` directories using the compile commands from your `build` directory.
If you wish to automatically fix whatever clang-tidy finds _and_ is capable of fixing, add `-fix -format` to the above command:
If you wish to automatically fix whatever clang-tidy finds _and_ is capable of fixing, add `-fix` to the above command:
```
run-clang-tidy -p build -quiet -fix -format -allow-no-checks src tests
run-clang-tidy -p build -quiet -fix -allow-no-checks src tests
```
`-format` reformats the fixed code with [`.clang-format`](./.clang-format); without it the fixes are inserted in LLVM style and the `clang-format` hook rewrites them afterwards.
## Contracts and instrumentation
We are using [Antithesis](https://antithesis.com/) for continuous fuzzing,

View File

@@ -30,10 +30,8 @@ missing=()
checked=0
# check <name> [probe-command...]
# Runs the probe (default: "<name> --version"), capturing both stdout and
# stderr, and prints one aligned line: the status, the name, and the first
# non-blank line of the probe output (its version). Records <name> as missing
# if the command is not found or exits non-zero.
# Runs the probe (default: "<name> --version") quietly. Records <name> as
# missing if the command is not found or exits non-zero.
check() {
local name="$1"
shift
@@ -42,11 +40,10 @@ check() {
probe=("${name}" --version)
fi
echo "Checking ${name}..."
checked=$((checked + 1))
local output version
if output="$("${probe[@]}" 2>&1)"; then
version="$(printf '%s\n' "${output}" | grep -m1 '[^[:space:]]' || true)"
printf ' [ ok ] %-20s %s\n' "${name}" "${version}"
if "${probe[@]}" | head -n 1; then
printf ' [ ok ] %s\n' "${name}"
else
printf ' [MISS] %s\n' "${name}"
missing+=("${name}")
@@ -88,14 +85,12 @@ if [ "${os}" = "linux" ] || [ "${os}" = "macos" ]; then
check file
check less
check make
# net-tools netstat reports "net-tools X.Y"; macOS ships BSD netstat with no
# version flag, so fall back to a presence marker there.
check netstat sh -c 'command -v netstat >/dev/null && { netstat --version 2>&1 | grep -m1 -oE "net-tools [0-9.]+" || echo present; }'
check netstat which netstat
check ninja
check perl perl -e 'print "$^V\n"'
check perl
check pkg-config
check vim
check zip bash -c 'zip --version 2>&1 | grep -m1 -oE "Zip [0-9.]+"'
check zip
# These tools are present in our Linux CI images and in local development
# setups, but not in the macOS CI environment. So check them everywhere

View File

@@ -144,11 +144,7 @@ def main():
+ files
)
canonicalize_fix_paths(Path(fixes_dir))
# `FormatStyle` in .clang-tidy does not reach this path,
# so ask for the repository style here.
applied = subprocess.run(
[clang_apply_replacements, "--format", "--style=file", fixes_dir]
)
applied = subprocess.run([clang_apply_replacements, fixes_dir])
return result.returncode or applied.returncode

View File

@@ -29,27 +29,6 @@ if(CMAKE_GENERATOR STREQUAL "Xcode")
set(is_xcode TRUE)
endif()
# --------------------------------------------------------------------
# Nix toolchain detection
# --------------------------------------------------------------------
# True when the C++ compiler resolves into the Nix store. CMAKE_CXX_COMPILER may
# be referenced through a symlink outside the store (a Nix profile, a /usr/bin
# alternative, ...), so resolve the real path before matching.
set(is_nix_compiler FALSE)
get_filename_component(_cxx_real "${CMAKE_CXX_COMPILER}" REALPATH)
if(_cxx_real MATCHES "^/nix/store/")
set(is_nix_compiler TRUE)
endif()
unset(_cxx_real)
# True inside the Nix CI Docker image, identified by the /nix/ci-env tree it
# ships (see nix/docker/Dockerfile). The dev shell and bare systems don't have
# it, so it distinguishes the CI image from other Nix-compiler environments.
set(is_ci_image FALSE)
if(EXISTS "/nix/ci-env/bin")
set(is_ci_image TRUE)
endif()
# --------------------------------------------------------------------
# Operating system detection
# --------------------------------------------------------------------

View File

@@ -1,37 +1,26 @@
#[===================================================================[
Patch executables to run in non-Nix environments.
The Nix toolchain links binaries against an ELF interpreter (loader)
that lives in the Nix store, so the resulting binaries don't run elsewhere.
`patch_nix_binary` adds a POST_BUILD step that resets the interpreter
to the system default loader and drops the rpath.
The Nix-based CI image links binaries against an ELF interpreter (loader)
that lives in the Nix store, so the resulting binaries don't run elsewhere
(including once installed from the .deb package). `patch_nix_binary` adds a
POST_BUILD step that resets the interpreter to the system default loader and
drops the rpath.
This runs by default for Nix-toolchain builds (determined by whether the compiler resolves under /nix/store/).
Those builds are where binaries get a Nix-store loader.
It is opted out of by setting the XRPLD_NO_PATCH_NIX_BINARY environment variable
the plain Nix dev shells set it, since their binaries link a newer glibc
and must not be retargeted to the system loader.
Non-Nix builds (a system compiler, already using the system loader) and sanitizer builds
(runtime libraries resolved through the rpath) are skipped too.
Everywhere else `patch_nix_binary` is a no-op.
The default loader is resolved by bin/default-loader-path.sh.
This is only active inside the Nix-based image, detected by the presence of
/tmp/loader-path.sh (shipped by that image, resolves the default loader). It
is skipped for sanitizer builds, whose runtime libraries are resolved through
the rpath. Everywhere else `patch_nix_binary` is a no-op.
#]===================================================================]
include_guard(GLOBAL)
include(CompilationEnv)
# Resolves the system default ELF loader path for the current architecture.
set(_loader_path_script "${CMAKE_SOURCE_DIR}/bin/default-loader-path.sh")
# Provided by the Nix-based CI image; prints the system default ELF loader path.
set(_loader_path_script "/tmp/loader-path.sh")
if(
is_linux
AND NOT SANITIZERS_ENABLED
AND is_nix_compiler
AND NOT DEFINED ENV{XRPLD_NO_PATCH_NIX_BINARY}
)
if(is_linux AND NOT SANITIZERS_ENABLED AND EXISTS "${_loader_path_script}")
execute_process(
COMMAND "${_loader_path_script}"
OUTPUT_VARIABLE DEFAULT_LOADER_PATH

View File

@@ -1,5 +1,3 @@
include_guard()
include(isolate_headers)
# Define a benchmark executable for the module `name`.

View File

@@ -171,8 +171,9 @@ else()
# Clang wrapper supplies those paths itself (via -nostdinc++), so at compile time the
# flag is unused -> Clang errors under our -Werror. At link time the flag IS consumed
# (it selects the C++ runtime), so we move it there instead of dropping it entirely.
get_filename_component(_cxx_real "${CMAKE_CXX_COMPILER}" REALPATH)
if(
is_nix_compiler
_cxx_real MATCHES "^/nix/store/"
AND is_linux
AND is_clang
AND CMAKE_CXX_FLAGS MATCHES "stdlib=libstdc"

View File

@@ -36,19 +36,6 @@ elseif(is_gcc)
endif()
endif()
# A Nix compiler is only meant to be used from a managed environment: the xrpld
# dev shell (which exports XRPL_DEVSHELL) or the CI image. Using one from a bare
# shell usually means a leaked toolchain (picked up via PATH or a Conan profile)
# and leads to confusing breakage, so fail early with guidance.
if(is_nix_compiler AND NOT is_ci_image AND NOT DEFINED ENV{XRPL_DEVSHELL})
message(
FATAL_ERROR
"A Nix compiler (${CMAKE_CXX_COMPILER}) is being used outside the xrpld "
"dev shell. Enter it with `nix develop` (see docs/build/nix.md) before "
"configuring the build."
)
endif()
# check for in-source build and fail
if("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
message(

8
docs/build/nix.md vendored
View File

@@ -154,14 +154,6 @@ conan install .. --output-folder . --build '*' --settings build_type=Release
To update `flake.lock` to the latest revision use `nix flake update` command.
## Tooling snapshots
The tool versions in each Nix environment are recorded in
[`nix/check-tools/`](../../nix/check-tools) and verified by CI. If you change the
environment (bump the CI image tag, update `flake.lock`, or edit the tool list in
`bin/check-tools.sh`), CI fails until you regenerate and commit the affected
snapshot — see [`nix/check-tools/README.md`](../../nix/check-tools/README.md).
## Troubleshooting
See [Troubleshooting Nix problems](./nix_troubleshooting.md) for common issues,

View File

@@ -11,7 +11,6 @@
#include <limits>
#include <stdexcept>
#include <string>
#include <string_view>
#include <type_traits>
#include <vector>
@@ -252,11 +251,4 @@ makeSlice(std::basic_string<char, Traits, Alloc> const& s)
return Slice(s.data(), s.size());
}
template <class Traits>
Slice
makeSlice(std::basic_string_view<char, Traits> s)
{
return Slice(s.data(), s.size());
}
} // namespace xrpl

View File

@@ -58,7 +58,7 @@ struct LexicalCast<Out, std::string_view>
"beast::LexicalCast can only be used with integral types");
template <class Integral = Out>
constexpr bool
bool
operator()(Integral& out, std::string_view in) const
requires(std::is_integral_v<Integral> && !std::is_same_v<Integral, bool>)
{
@@ -110,7 +110,7 @@ struct LexicalCast<Out, boost::core::basic_string_view<char>>
{
explicit LexicalCast() = default;
constexpr bool
bool
operator()(Out& out, boost::core::basic_string_view<char> in) const
{
return LexicalCast<Out, std::string_view>()(out, in);
@@ -123,7 +123,7 @@ struct LexicalCast<Out, std::string>
{
explicit LexicalCast() = default;
constexpr bool
bool
operator()(Out& out, std::string in) const
{
return LexicalCast<Out, std::string_view>()(out, in);
@@ -136,7 +136,7 @@ struct LexicalCast<Out, char const*>
{
explicit LexicalCast() = default;
constexpr bool
bool
operator()(Out& out, char const* in) const
{
XRPL_ASSERT(in, "beast::detail::LexicalCast(char const*) : non-null input");
@@ -151,7 +151,7 @@ struct LexicalCast<Out, char*>
{
explicit LexicalCast() = default;
constexpr bool
bool
operator()(Out& out, char* in) const
{
XRPL_ASSERT(in, "beast::detail::LexicalCast(char*) : non-null input");
@@ -177,7 +177,7 @@ struct BadLexicalCast : public std::bad_cast
* @return `false` if there was a parsing or range error
*/
template <class Out, class In>
constexpr bool
bool
lexicalCastChecked(Out& out, In in)
{
return detail::LexicalCast<Out, In>()(out, in);
@@ -191,7 +191,7 @@ lexicalCastChecked(Out& out, In in)
* @return The new type.
*/
template <class Out, class In>
constexpr Out
Out
lexicalCastThrow(In in)
{
if (Out out; lexicalCastChecked(out, in))
@@ -207,7 +207,7 @@ lexicalCastThrow(In in)
* @return The new type.
*/
template <class Out, class In>
constexpr Out
Out
lexicalCast(In in, Out defaultValue = Out())
{
if (Out out; lexicalCastChecked(out, in))

View File

@@ -17,14 +17,14 @@ namespace beast {
class SemanticVersion
{
public:
using IdentifierList = std::vector<std::string>;
using identifier_list = std::vector<std::string>;
int majorVersion;
int minorVersion;
int patchVersion;
IdentifierList preReleaseIdentifiers;
IdentifierList metaData;
identifier_list preReleaseIdentifiers;
identifier_list metaData;
SemanticVersion();

View File

@@ -15,9 +15,9 @@
namespace xrpl {
// Forward declarations
namespace node_store {
namespace NodeStore {
class Database;
} // namespace node_store
} // namespace NodeStore
namespace Resource {
class Manager;
} // namespace Resource
@@ -164,7 +164,7 @@ public:
getResourceManager() = 0;
// Storage services
virtual node_store::Database&
virtual NodeStore::Database&
getNodeStore() = 0;
virtual SHAMapStore&

View File

@@ -2,9 +2,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
@@ -27,291 +25,6 @@
namespace xrpl {
/**
* Validate that @p account may lock @p amount of a token for later delivery
* to @p dest.
*
* 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
escrowLockPreclaimHelper<Issue>(
ReadView const& view,
AccountID const& account,
AccountID const& dest,
STAmount const& amount,
beast::Journal j)
{
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;
}
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, mptIssue))
return tecLOCKED;
// If the issuer has frozen the destination, return tecLOCKED
if (isFrozen(view, dest, mptIssue))
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, mptIssue))
return tecLOCKED;
return tesSUCCESS;
}
//------------------------------------------------------------------------------
template <ValidIssueType T>
TER
escrowUnlockApplyHelper(
@@ -340,6 +53,9 @@ 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;
@@ -349,10 +65,6 @@ 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?

View File

@@ -286,77 +286,6 @@ computeFullPaymentInterest(
std::uint32_t startDate,
TenthBips32 closeInterestRate);
// Deltas applied to Vault.AssetsTotal and LoanBroker.DebtTotal at a single
// accounting touch point (origination, payment, impair/unimpair/default).
struct AccountingDeltas
{
Number assetsTotalDelta;
Number debtTotalDelta;
};
// Whole-life (pre-LendingProtocolV1_1) recognition model: interest is
// recognized into AssetsTotal/DebtTotal up front, at origination.
namespace Accrual {
// LoanSet origination: what's added to Vault.AssetsTotal and LoanBroker.DebtTotal
AccountingDeltas
loanOriginationDeltas(Number const& principalRequested, Number const& interestDue);
// LoanSet origination: would recognizing this loan's interest push
// Vault.AssetsTotal past Vault.AssetsMaximum?
bool
loanOriginationExceedsVaultMaximum(
Number const& vaultMaximum,
Number const& vaultTotal,
Number const& interestDue);
// LoanManage impair/unimpair/default: the vault's exposure to this loan
Number
loanVaultExposure(SLE::const_ref loanSle);
// LoanPay: what's added to Vault.AssetsTotal and subtracted from LoanBroker.DebtTotal for a payment
AccountingDeltas
loanPaymentDeltas(LoanPaymentParts const& parts);
} // namespace Accrual
// Cash-basis (LendingProtocolV1_1) recognition model: AssetsTotal/DebtTotal
// are principal-only, interest is recognized only as it's actually paid.
namespace CashBasis {
AccountingDeltas
loanOriginationDeltas(Number const& principalRequested);
Number
loanVaultExposure(SLE::const_ref loanSle);
AccountingDeltas
loanPaymentDeltas(LoanPaymentParts const& parts);
} // namespace CashBasis
// Public dispatchers: pick CashBasis:: if featureLendingProtocolV1_1 is
// enabled AND the Vault's LEVersion (VaultHelpers::getVaultVersion) is
// VaultVersion::CashBasis, else Accrual::. These are the only entry points
// transactors call.
AccountingDeltas
loanOriginationDeltas(
SLE::const_ref vaultSle,
Number const& principalRequested,
Number const& interestDue);
bool
loanOriginationExceedsVaultMaximum(
SLE::const_ref vaultSle,
Number const& vaultTotal,
Number const& interestDue);
Number
loanVaultExposure(SLE::const_ref vaultSle, SLE::const_ref loanSle);
AccountingDeltas
loanPaymentDeltas(SLE::const_ref vaultSle, LoanPaymentParts const& parts);
namespace detail {
// These classes and functions should only be accessed by LendingHelper
// functions and unit tests

View File

@@ -2,85 +2,28 @@
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Concepts.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/MPTAmount.h>
#include <xrpl/protocol/MPTIssue.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/Rules.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/UintTypes.h>
#include <cstdint>
#include <optional>
namespace xrpl {
/**
* Validate the token amount of a PaymentChannelCreate or PaymentChannelFund
* transaction during preflight.
*
* @param rules The current ledger rules used to check amendment status.
* @param amount The channel or funding amount from the transaction.
* @return tesSUCCESS if the amount is valid; temBAD_AMOUNT, temBAD_CURRENCY,
* or temDISABLED otherwise.
*/
template <ValidIssueType T>
NotTEC
payChanAmountPreflightHelper(Rules const& rules, STAmount const& amount);
template <>
inline NotTEC
payChanAmountPreflightHelper<Issue>(Rules const&, STAmount const& amount)
{
if (amount.native() || amount <= beast::kZero)
return temBAD_AMOUNT;
if (badCurrency() == amount.get<Issue>().currency)
return temBAD_CURRENCY;
return tesSUCCESS;
}
template <>
inline NotTEC
payChanAmountPreflightHelper<MPTIssue>(Rules const& rules, STAmount const& amount)
{
if (!rules.enabled(fixCleanup3_2_0) && !rules.enabled(featureMPTokensV1))
return temDISABLED;
if (amount.native() || amount.mpt() > MPTAmount{kMaxMpTokenAmount} || amount <= beast::kZero)
return temBAD_AMOUNT;
return tesSUCCESS;
}
/**
* Close a payment channel and return its remaining funds to the channel owner.
*
* @param slep The SLE for the PayChannel object to close.
* @param ctx The apply view context (view and transaction) in which ledger
* state modifications are made.
* @param key The ledger key identifying the PayChannel entry.
* @param txAccount The account submitting the transaction that closes the
* channel.
* @param j Journal used for fatal-level diagnostic messages.
* @return tesSUCCESS on success; tefBAD_LEDGER if a directory removal
* fails; tefINTERNAL if the source account SLE cannot be found.
* @param slep The SLE for the PayChannel object to close.
* @param view The apply view in which ledger state modifications are made.
* @param key The ledger key identifying the PayChannel entry.
* @param j Journal used for fatal-level diagnostic messages.
* @return tesSUCCESS on success; tefBAD_LEDGER if a directory removal
* fails; tefINTERNAL if the source account SLE cannot be found.
*/
TER
closeChannel(
SLE::ref slep,
ApplyViewContext ctx,
uint256 const& key,
AccountID const& txAccount,
beast::Journal j);
closeChannel(SLE::ref slep, ApplyView& view, uint256 const& key, beast::Journal j);
/**
* Add two uint32_t values with saturation at UINT32_MAX.

View File

@@ -2,7 +2,6 @@
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STLedgerEntry.h>
@@ -108,19 +107,4 @@ sharesToAssetsWithdraw(
[[nodiscard]] bool
isSoleShareholder(ReadView const& view, AccountID const& account, SLE::const_ref issuance);
/**
* Resolves a Vault's LEVersion, the single point every accounting touch
* point should call to determine which recognition model (accrual vs.
* cash-basis) a Vault uses. Vaults created before featureLendingProtocolV1_1
* activated never have sfLEVersion set, which resolves here to
* VaultVersion::Legacy.
*
* @param vault The vault SLE.
*
* @return The Vault's LEVersion, or VaultVersion::Legacy if the field is
* absent.
*/
[[nodiscard]] VaultVersion
getVaultVersion(SLE::const_ref vault);
} // namespace xrpl

View File

@@ -13,7 +13,7 @@
#include <stdexcept>
#include <string>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
/**
* A backend used for the NodeStore.
@@ -163,4 +163,4 @@ public:
fdRequired() const = 0;
};
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -25,7 +25,7 @@ namespace xrpl {
class Section;
} // namespace xrpl
namespace xrpl::node_store {
namespace xrpl::NodeStore {
/**
* Persistency layer for NodeObject
@@ -248,7 +248,7 @@ protected:
void
storeStats(std::uint64_t count, std::uint64_t sz)
{
XRPL_ASSERT(count <= sz, "xrpl::node_store::Database::storeStats : valid inputs");
XRPL_ASSERT(count <= sz, "xrpl::NodeStore::Database::storeStats : valid inputs");
storeCount_ += count;
storeSz_ += sz;
}
@@ -308,4 +308,4 @@ private:
threadEntry();
};
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -9,7 +9,7 @@
#include <memory>
#include <string>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
/* This class has two key-value store Backend objects for persisting SHAMap
* records. This facilitates online deletion of data. New backends are
@@ -38,7 +38,7 @@ public:
*/
virtual void
rotate(
std::unique_ptr<node_store::Backend>&& newBackend,
std::unique_ptr<NodeStore::Backend>&& newBackend,
std::function<void(std::string const& writableName, std::string const& archiveName)> const&
f) = 0;
@@ -56,4 +56,4 @@ public:
setRotationInFlight(bool inFlight) = 0;
};
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -3,7 +3,7 @@
#include <xrpl/nodestore/Scheduler.h>
#include <xrpl/nodestore/Task.h>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
/**
* Simple NodeStore Scheduler that just performs the tasks synchronously.
@@ -21,4 +21,4 @@ public:
onBatchWrite(BatchWriteReport const& report) override;
};
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -14,7 +14,7 @@ namespace xrpl {
class Section;
} // namespace xrpl
namespace xrpl::node_store {
namespace xrpl::NodeStore {
/**
* Base class for backend factories.
@@ -70,4 +70,4 @@ public:
}
};
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -10,7 +10,7 @@
#include <memory>
#include <string>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
/**
* Singleton for managing NodeStore factories and back ends.
@@ -98,4 +98,4 @@ public:
beast::Journal journal) = 0;
};
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -8,7 +8,7 @@
#include <cstdint>
#include <memory>
// VFALCO NOTE Intentionally not in the node_store namespace
// VFALCO NOTE Intentionally not in the NodeStore namespace
namespace xrpl {

View File

@@ -4,7 +4,7 @@
#include <chrono>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
enum class FetchType { Synchronous, Async };
@@ -71,4 +71,4 @@ public:
onBatchWrite(BatchWriteReport const& report) = 0;
};
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -1,6 +1,6 @@
#pragma once
namespace xrpl::node_store {
namespace xrpl::NodeStore {
/**
* Derived classes perform scheduled tasks.
@@ -17,4 +17,4 @@ struct Task
performScheduledTask() = 0;
};
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -5,7 +5,7 @@
#include <memory>
#include <vector>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
// This is only used to pre-allocate the array for
// batch objects and does not affect the amount written.
@@ -36,4 +36,4 @@ enum class Status {
*/
using Batch = std::vector<std::shared_ptr<NodeObject>>;
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -9,7 +9,7 @@
#include <memory>
#include <mutex>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
/**
* Batch-writing assist logic.
@@ -86,4 +86,4 @@ private:
Batch writeSet_;
};
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -22,7 +22,7 @@
#include <stdexcept>
#include <utility>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
class DatabaseNodeImp : public Database
{
@@ -68,7 +68,7 @@ public:
XRPL_ASSERT(
backend_,
"xrpl::node_store::DatabaseNodeImp::DatabaseNodeImp : non-null "
"xrpl::NodeStore::DatabaseNodeImp::DatabaseNodeImp : non-null "
"backend");
}
@@ -138,4 +138,4 @@ private:
}
};
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -16,7 +16,7 @@
#include <mutex>
#include <string>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
class DatabaseRotatingImp : public DatabaseRotating
{
@@ -41,7 +41,7 @@ public:
void
rotate(
std::unique_ptr<node_store::Backend>&& newBackend,
std::unique_ptr<NodeStore::Backend>&& newBackend,
std::function<void(std::string const& writableName, std::string const& archiveName)> const&
f) override;
@@ -94,4 +94,4 @@ private:
forEach(std::function<void(std::shared_ptr<NodeObject>)> f) override;
};
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -4,7 +4,7 @@
#include <memory>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
/**
* Parsed key/value blob into NodeObject components.
@@ -49,4 +49,4 @@ private:
int dataBytes_;
};
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -12,7 +12,7 @@
#include <memory>
#include <stdexcept>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
/**
* Convert a NodeObject from in-memory to database format.
@@ -68,7 +68,7 @@ class EncodedBlob
public:
explicit EncodedBlob(std::shared_ptr<NodeObject> const& obj)
: size_([&obj]() {
XRPL_ASSERT(obj, "xrpl::node_store::EncodedBlob::EncodedBlob : non-null input");
XRPL_ASSERT(obj, "xrpl::NodeStore::EncodedBlob::EncodedBlob : non-null input");
if (!obj)
throw std::runtime_error("EncodedBlob: unseated std::shared_ptr used.");
@@ -88,7 +88,7 @@ public:
XRPL_ASSERT(
((ptr_ == payload_.data()) && (size_ <= payload_.size())) ||
((ptr_ != payload_.data()) && (size_ > payload_.size())),
"xrpl::node_store::EncodedBlob::~EncodedBlob : valid payload "
"xrpl::NodeStore::EncodedBlob::~EncodedBlob : valid payload "
"pointer");
if (ptr_ != payload_.data())
@@ -114,4 +114,4 @@ public:
}
};
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -13,7 +13,7 @@
#include <string>
#include <vector>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
class ManagerImp : public Manager
{
@@ -57,4 +57,4 @@ public:
beast::Journal journal) override;
};
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -10,7 +10,7 @@
#include <xrpl/basics/contract.h>
#include <xrpl/basics/safe_cast.h>
#include <xrpl/nodestore/NodeObject.h>
#include <xrpl/nodestore/detail/Varint.h>
#include <xrpl/nodestore/detail/varint.h>
#include <xrpl/protocol/HashPrefix.h>
#include <nudb/detail/field.hpp>
@@ -21,7 +21,7 @@
#include <cstring>
#include <string>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
template <class BufferFactory>
std::pair<void const*, std::size_t>
@@ -59,7 +59,7 @@ lz4Compress(void const* in, std::size_t inSize, BufferFactory&& bf)
using std::runtime_error;
using namespace nudb::detail;
std::pair<void const*, std::size_t> result;
std::array<std::uint8_t, VarintTraits<std::size_t>::kMax> vi{};
std::array<std::uint8_t, varint_traits<std::size_t>::kMax> vi{};
auto const n = writeVarint(vi.data(), inSize);
auto const outMax = LZ4_compressBound(inSize);
auto* out = reinterpret_cast<std::uint8_t*>(bf(n + outMax));
@@ -240,7 +240,7 @@ nodeobjectCompress(void const* in, std::size_t inSize, BufferFactory&& bf)
auto* out = reinterpret_cast<std::uint8_t*>(bf(result.second));
result.first = out;
ostream os(out, result.second);
write<Varint>(os, type);
write<varint>(os, type);
write<std::uint16_t>(os, mask);
write(os, vh.data(), n * 32);
return result;
@@ -252,13 +252,13 @@ nodeobjectCompress(void const* in, std::size_t inSize, BufferFactory&& bf)
auto* out = reinterpret_cast<std::uint8_t*>(bf(result.second));
result.first = out;
ostream os(out, result.second);
write<Varint>(os, type);
write<varint>(os, type);
write(os, vh.data(), n * 32);
return result;
}
}
std::array<std::uint8_t, VarintTraits<std::size_t>::kMax> vi{};
std::array<std::uint8_t, varint_traits<std::size_t>::kMax> vi{};
static constexpr std::size_t kCodecType = 1;
auto const vn = writeVarint(vi.data(), kCodecType);
@@ -269,7 +269,7 @@ nodeobjectCompress(void const* in, std::size_t inSize, BufferFactory&& bf)
case 1: // lz4
{
std::uint8_t* p = nullptr;
auto const lzr = node_store::lz4Compress(in, inSize, [&p, &vn, &bf](std::size_t n) {
auto const lzr = NodeStore::lz4Compress(in, inSize, [&p, &vn, &bf](std::size_t n) {
p = reinterpret_cast<std::uint8_t*>(bf(vn + n));
return p + vn;
});
@@ -316,4 +316,4 @@ filterInner(void* in, std::size_t inSize)
}
}
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -6,25 +6,25 @@
#include <cstdint>
#include <type_traits>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
// This is a variant of the base128 varint format from
// google protocol buffers:
// https://developers.google.com/protocol-buffers/docs/encoding#varints
// field tag
struct Varint;
struct varint;
// Metafunction to return largest
// Metafuncton to return largest
// possible size of T represented as varint.
// T must be unsigned
template <class T, bool = std::is_unsigned_v<T>>
struct VarintTraits;
struct varint_traits;
template <class T>
struct VarintTraits<T, true>
struct varint_traits<T, true>
{
explicit VarintTraits() = default;
explicit varint_traits() = default;
static constexpr std::size_t kMax = ((8 * sizeof(T)) + 6) / 7;
};
@@ -104,7 +104,7 @@ writeVarint(void* p0, std::size_t v)
template <class T>
void
read(nudb::detail::istream& is, std::size_t& u)
requires(std::is_same_v<T, Varint>)
requires(std::is_same_v<T, varint>)
{
auto p0 = is(1);
auto p1 = p0;
@@ -118,9 +118,9 @@ read(nudb::detail::istream& is, std::size_t& u)
template <class T>
void
write(nudb::detail::ostream& os, std::size_t t)
requires(std::is_same_v<T, Varint>)
requires(std::is_same_v<T, varint>)
{
writeVarint(os.data(sizeVarint(t)), t);
}
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -246,15 +246,7 @@ message TMGetObjectByHash {
message TMLedgerNode {
required bytes nodedata = 1;
// Used when protocol version <2.3. Not set for ledger base data.
optional bytes nodeid = 2;
// Used when protocol version >=2.3. Neither value is set for ledger base data.
oneof reference {
bytes id = 3; // Set for inner nodes.
uint32 depth = 4; // Set for leaf nodes.
}
optional bytes nodeid = 2; // missing for ledger base data
}
enum TMLedgerInfoType {

View File

@@ -1,20 +1,10 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/HashPrefix.h>
#include <xrpl/protocol/IOUAmount.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/MPTAmount.h>
#include <xrpl/protocol/MPTIssue.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/Serializer.h>
#include <xrpl/protocol/UintTypes.h>
#include <xrpl/protocol/XRPAmount.h>
#include <cstdint>
namespace xrpl {
inline void
@@ -25,70 +15,4 @@ serializePayChanAuthorization(Serializer& msg, uint256 const& key, XRPAmount con
msg.add64(amt.drops());
}
inline void
serializePayChanAuthorization(
Serializer& msg,
uint256 const& key,
IOUAmount const& amt,
Currency const& cur,
AccountID const& iss)
{
msg.add32(HashPrefix::PaymentChannelClaim);
msg.addBitString(key);
if (amt == beast::kZero)
{
msg.add64(STAmount::kIssuedCurrency);
}
else if (amt.signum() == -1)
{ // 512 = not native; the sign is encoded by omitting the 256 flag, so
// the mantissa must be serialized as its absolute value
msg.add64(
static_cast<std::uint64_t>(-amt.mantissa()) |
(static_cast<std::uint64_t>(amt.exponent() + 512 + 97) << (64 - 10)));
}
else
{ // 256 = positive
msg.add64(
amt.mantissa() |
(static_cast<std::uint64_t>(amt.exponent() + 512 + 256 + 97) << (64 - 10)));
}
msg.addBitString(cur);
msg.addBitString(iss);
}
inline void
serializePayChanAuthorization(
Serializer& msg,
uint256 const& key,
MPTAmount const& amt,
MPTID const& mptID,
AccountID const& iss)
{
msg.add32(HashPrefix::PaymentChannelClaim);
msg.addBitString(key);
msg.add64(amt.value());
msg.addBitString(mptID);
msg.addBitString(iss);
}
inline void
serializePayChanAuthorization(Serializer& msg, uint256 const& key, STAmount const& amt)
{
if (amt.native())
{
serializePayChanAuthorization(msg, key, amt.xrp());
}
else if (amt.holds<Issue>())
{
serializePayChanAuthorization(
msg, key, amt.iou(), amt.get<Issue>().currency, amt.get<Issue>().account);
}
else if (amt.holds<MPTIssue>())
{
auto const& mpt = amt.get<MPTIssue>();
auto const& mptID = mpt.getMptID();
serializePayChanAuthorization(msg, key, amt.mpt(), mptID, amt.getIssuer());
}
}
} // namespace xrpl

View File

@@ -316,17 +316,6 @@ constexpr std::uint8_t kVaultDefaultIouScale = 6;
*/
constexpr std::uint8_t kVaultMaximumIouScale = 18;
/**
* Vault ledger-entry schema versions. Assigned to newly created
* Vaults once featureLendingProtocolV1_1 is enabled. Vaults created before
* activation are left without LEVersion (implicit legacy version 0,
* accrual-basis accounting).
*/
enum class VaultVersion : uint8_t {
Legacy = 0,
CashBasis,
};
/**
* Maximum recursion depth for vault shares being put as an asset inside
* another vault; counted from 0

View File

@@ -15,8 +15,8 @@
// Add new amendments to the top of this list.
// Keep it sorted in reverse chronological order.
XRPL_FEATURE(DefragDirectories, Supported::No, VoteBehavior::DefaultNo)
XRPL_FIX (Cleanup3_4_0, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(TokenPaychan, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(Sponsor, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(BatchV1_1, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(LendingProtocolV1_1, Supported::No, VoteBehavior::DefaultNo)

View File

@@ -369,8 +369,6 @@ LEDGER_ENTRY(ltPAYCHAN, 0x0078, PayChannel, payment_channel, ({
{sfPreviousTxnID, SoeRequired},
{sfPreviousTxnLgrSeq, SoeRequired},
{sfDestinationNode, SoeOptional},
{sfTransferRate, SoeOptional},
{sfIssuerNode, SoeOptional},
}))
/** The ledger object which tracks the AMM.
@@ -507,7 +505,6 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
{sfShareMPTID, SoeRequired},
{sfWithdrawalPolicy, SoeRequired},
{sfScale, SoeDefault},
{sfLEVersion, SoeDefault},
// no SharesTotal ever (use MPTIssuance.sfOutstandingAmount)
// no PermissionedDomainID ever (use MPTIssuance.sfDomainID)
}))

View File

@@ -18,7 +18,6 @@ TYPED_SFIELD(sfMethod, UINT8, 2)
TYPED_SFIELD(sfTransactionResult, UINT8, 3)
TYPED_SFIELD(sfScale, UINT8, 4)
TYPED_SFIELD(sfAssetScale, UINT8, 5)
TYPED_SFIELD(sfLEVersion, UINT8, 6)
// 8-bit integers (uncommon)
TYPED_SFIELD(sfTickSize, UINT8, 16)

View File

@@ -191,7 +191,7 @@ TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate,
NoPriv,
({
{sfDestination, SoeRequired},
{sfAmount, SoeRequired, SoeMptSupported},
{sfAmount, SoeRequired},
{sfSettleDelay, SoeRequired},
{sfPublicKey, SoeRequired},
{sfCancelAfter, SoeOptional},
@@ -208,7 +208,7 @@ TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund,
NoPriv,
({
{sfChannel, SoeRequired},
{sfAmount, SoeRequired, SoeMptSupported},
{sfAmount, SoeRequired},
{sfExpiration, SoeOptional},
}))
@@ -222,8 +222,8 @@ TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim,
NoPriv,
({
{sfChannel, SoeRequired},
{sfAmount, SoeOptional, SoeMptSupported},
{sfBalance, SoeOptional, SoeMptSupported},
{sfAmount, SoeOptional},
{sfBalance, SoeOptional},
{sfSignature, SoeOptional},
{sfPublicKey, SoeOptional},
{sfCredentialIDs, SoeOptional},

View File

@@ -287,54 +287,6 @@ public:
{
return this->sle_->isFieldPresent(sfDestinationNode);
}
/**
* @brief Get sfTransferRate (SoeOptional)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT32::type::value_type>
getTransferRate() const
{
if (hasTransferRate())
return this->sle_->at(sfTransferRate);
return std::nullopt;
}
/**
* @brief Check if sfTransferRate is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasTransferRate() const
{
return this->sle_->isFieldPresent(sfTransferRate);
}
/**
* @brief Get sfIssuerNode (SoeOptional)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT64::type::value_type>
getIssuerNode() const
{
if (hasIssuerNode())
return this->sle_->at(sfIssuerNode);
return std::nullopt;
}
/**
* @brief Check if sfIssuerNode is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasIssuerNode() const
{
return this->sle_->isFieldPresent(sfIssuerNode);
}
};
/**
@@ -556,28 +508,6 @@ public:
return *this;
}
/**
* @brief Set sfTransferRate (SoeOptional)
* @return Reference to this builder for method chaining.
*/
PayChannelBuilder&
setTransferRate(std::decay_t<typename SF_UINT32::type::value_type> const& value)
{
object_[sfTransferRate] = value;
return *this;
}
/**
* @brief Set sfIssuerNode (SoeOptional)
* @return Reference to this builder for method chaining.
*/
PayChannelBuilder&
setIssuerNode(std::decay_t<typename SF_UINT64::type::value_type> const& value)
{
object_[sfIssuerNode] = value;
return *this;
}
/**
* @brief Build and return the completed PayChannel wrapper.
* @param index The ledger entry index.

View File

@@ -287,30 +287,6 @@ public:
{
return this->sle_->isFieldPresent(sfScale);
}
/**
* @brief Get sfLEVersion (SoeDefault)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT8::type::value_type>
getLEVersion() const
{
if (hasLEVersion())
return this->sle_->at(sfLEVersion);
return std::nullopt;
}
/**
* @brief Check if sfLEVersion is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasLEVersion() const
{
return this->sle_->isFieldPresent(sfLEVersion);
}
};
/**
@@ -532,17 +508,6 @@ public:
return *this;
}
/**
* @brief Set sfLEVersion (SoeDefault)
* @return Reference to this builder for method chaining.
*/
VaultBuilder&
setLEVersion(std::decay_t<typename SF_UINT8::type::value_type> const& value)
{
object_[sfLEVersion] = value;
return *this;
}
/**
* @brief Build and return the completed Vault wrapper.
* @param index The ledger entry index.

View File

@@ -60,7 +60,6 @@ public:
/**
* @brief Get sfAmount (SoeOptional)
* @note This field supports MPT (Multi-Purpose Token) amounts.
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
@@ -87,7 +86,6 @@ public:
/**
* @brief Get sfBalance (SoeOptional)
* @note This field supports MPT (Multi-Purpose Token) amounts.
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
@@ -248,7 +246,6 @@ public:
/**
* @brief Set sfAmount (SoeOptional)
* @note This field supports MPT (Multi-Purpose Token) amounts.
* @return Reference to this builder for method chaining.
*/
PaymentChannelClaimBuilder&
@@ -260,7 +257,6 @@ public:
/**
* @brief Set sfBalance (SoeOptional)
* @note This field supports MPT (Multi-Purpose Token) amounts.
* @return Reference to this builder for method chaining.
*/
PaymentChannelClaimBuilder&

View File

@@ -60,7 +60,6 @@ public:
/**
* @brief Get sfAmount (SoeRequired)
* @note This field supports MPT (Multi-Purpose Token) amounts.
* @return The field value.
*/
[[nodiscard]]
@@ -208,7 +207,6 @@ public:
/**
* @brief Set sfAmount (SoeRequired)
* @note This field supports MPT (Multi-Purpose Token) amounts.
* @return Reference to this builder for method chaining.
*/
PaymentChannelCreateBuilder&

View File

@@ -60,7 +60,6 @@ public:
/**
* @brief Get sfAmount (SoeRequired)
* @note This field supports MPT (Multi-Purpose Token) amounts.
* @return The field value.
*/
[[nodiscard]]
@@ -156,7 +155,6 @@ public:
/**
* @brief Set sfAmount (SoeRequired)
* @note This field supports MPT (Multi-Purpose Token) amounts.
* @return Reference to this builder for method chaining.
*/
PaymentChannelFundBuilder&

View File

@@ -26,10 +26,10 @@ public:
explicit Family() = default;
virtual ~Family() = default;
virtual node_store::Database&
virtual NodeStore::Database&
db() = 0;
[[nodiscard]] virtual node_store::Database const&
[[nodiscard]] virtual NodeStore::Database const&
db() const = 0;
virtual beast::Journal const&

View File

@@ -3,6 +3,7 @@
#include <xrpl/basics/Blob.h>
#include <xrpl/basics/IntrusivePointer.h>
#include <xrpl/basics/SHAMapHash.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/instrumentation.h>
@@ -94,21 +95,6 @@ enum class SHAMapState {
*
* See https://en.wikipedia.org/wiki/Merkle_tree
*/
/**
* Holds a SHAMap node's identity, leaf status, and serialized data. Used by
* getNodeFat to return node data for peer synchronization.
*/
struct SHAMapNodeData
{
SHAMapNodeID nodeID;
// The `data` field (a Blob, 8-byte aligned) needs 4 bytes of padding after the `nodeID` field
// (36 bytes, 4-byte aligned) regardless of what comes between them, so `isLeaf` costs nothing
// extra here. Moving it after `data` would add 8 bytes to the size of this struct instead.
bool isLeaf;
Blob data;
};
class SHAMap
{
private:
@@ -303,10 +289,10 @@ public:
std::vector<std::pair<SHAMapNodeID, uint256>>
getMissingNodes(int maxNodes, SHAMapSyncFilter const* filter);
[[nodiscard]] bool
bool
getNodeFat(
SHAMapNodeID const& wanted,
std::vector<SHAMapNodeData>& data,
std::vector<std::pair<SHAMapNodeID, Blob>>& data,
bool fatLeaves,
std::uint32_t depth) const;
@@ -335,45 +321,10 @@ public:
void
serializeRoot(Serializer& s) const;
/**
* Add a root node to the SHAMap during synchronization.
*
* This function is used when receiving the root node of a SHAMap from a peer during ledger
* synchronization. The node must already have been deserialized.
*
* @param hash The expected hash of the root node.
* @param rootNode A deserialized root node to add.
* @param filter Optional sync filter to track received nodes.
* @return Status indicating whether the node was useful, duplicate, or invalid.
*
* @note This function expects the rootNode to be a valid, deserialized SHAMapTreeNode. The
* caller is responsible for deserialization and basic validation before calling this
* function.
*/
SHAMapAddNode
addRootNode(SHAMapHash const& hash, SHAMapTreeNodePtr rootNode, SHAMapSyncFilter const* filter);
/**
* Add a known node at a specific position in the SHAMap during synchronization.
*
* This function is used when receiving nodes from peers during ledger synchronization. The node
* is inserted at the position specified by nodeID. The node must already have been
* deserialized.
*
* @param nodeID The position in the tree where this node belongs.
* @param treeNode A deserialized tree node to add.
* @param filter Optional sync filter to track received nodes.
* @return Status indicating whether the node was useful, duplicate, or invalid.
*
* @note This function expects the treeNode to be a valid, deserialized SHAMapTreeNode. The
* caller is responsible for deserialization and basic validation before calling this
* function. This also means that the nodeID must be consistent with the node's content.
*/
addRootNode(SHAMapHash const& hash, Slice const& rootNode, SHAMapSyncFilter const* filter);
SHAMapAddNode
addKnownNode(
SHAMapNodeID const& nodeID,
SHAMapTreeNodePtr treeNode,
SHAMapSyncFilter const* filter);
addKnownNode(SHAMapNodeID const& nodeID, Slice const& rawNode, SHAMapSyncFilter const* filter);
// status functions
void

View File

@@ -1,9 +1,6 @@
#pragma once
#include <xrpl/basics/SHAMapHash.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/safe_cast.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/shamap/SHAMapItem.h>
#include <xrpl/shamap/SHAMapNodeID.h>
#include <xrpl/shamap/SHAMapTreeNode.h>
@@ -63,16 +60,4 @@ public:
getString(SHAMapNodeID const&) const final;
};
/**
* Return the key of the item held by a SHAMap leaf node.
*
* @param node a node known to be a leaf (see SHAMapTreeNode::isLeaf).
*/
inline uint256 const&
leafKey(SHAMapTreeNode const& node)
{
XRPL_ASSERT(node.isLeaf(), "xrpl::leafKey : node is a leaf");
return safeDowncast<SHAMapLeafNode const&>(node).peekItem()->key();
}
} // namespace xrpl

View File

@@ -23,9 +23,6 @@ public:
static TxConsequences
makeTxConsequences(PreflightContext const& ctx);
static bool
checkExtraFeatures(PreflightContext const& ctx);
static NotTEC
preflight(PreflightContext const& ctx);

View File

@@ -23,15 +23,9 @@ public:
static TxConsequences
makeTxConsequences(PreflightContext const& ctx);
static bool
checkExtraFeatures(PreflightContext const& ctx);
static NotTEC
preflight(PreflightContext const& ctx);
static TER
preclaim(PreclaimContext const& ctx);
TER
doApply() override;

View File

@@ -1,49 +0,0 @@
# check-tools snapshots
These files capture the output of [`bin/check-tools.sh`](../../bin/check-tools.sh)
— the versions of the development tooling — in each Nix environment:
| File | Environment |
| ---------------------- | ------------------------------------ |
| `nix-ubuntu-amd64.txt` | `nix-ubuntu` CI image, `linux/amd64` |
| `nix-ubuntu-arm64.txt` | `nix-ubuntu` CI image, `linux/arm64` |
| `macos.txt` | macOS, inside `nix develop` |
The [`check-tools`](../../.github/workflows/check-tools.yml) workflow regenerates
each snapshot in its environment and fails if it differs from the committed file.
So if you change the environment (bump the image tag in
[`linux.json`](../../.github/scripts/strategy-matrix/linux.json), update
`flake.lock`, change the tool list in `check-tools.sh`, …) you must regenerate
and commit the affected snapshots.
Each snapshot is `check-tools.sh` stdout with the git-clone connectivity check
skipped (`CHECK_TOOLS_SKIP_CLONE=1`), so it contains only deterministic version
data. On macOS the dev-shell greeting that `nix develop` prints first is dropped
with `sed -n '/^Detected OS:/,$p'`.
## Regenerating
The two Linux snapshots come from the `nix-ubuntu` image (Docker or a compatible
runtime such as Apple `container`). The image tag is pinned in `linux.json`:
```bash
img="ghcr.io/xrplf/xrpld/nix-ubuntu:$(jq -r .image_tag .github/scripts/strategy-matrix/linux.json)"
for arch in amd64 arm64; do
container run --rm -i -e CHECK_TOOLS_SKIP_CLONE=1 -a "${arch}" --entrypoint bash "${img}" -s \
<bin/check-tools.sh >"nix/check-tools/nix-ubuntu-${arch}.txt"
done
```
(With Docker, replace `container run … -a "${arch}"` with
`docker run … --platform "linux/${arch}"`.)
The macOS snapshot is generated locally. `CI=` is unset so `check-tools.sh`
checks the full dev-shell tool set (it otherwise skips some tools when `CI` is
set):
```bash
CI= nix develop -c bash -c 'CHECK_TOOLS_SKIP_CLONE=1 bash bin/check-tools.sh' |
sed -n '/^Detected OS:/,$p' \
>nix/check-tools/macos.txt
```

View File

@@ -1,47 +0,0 @@
Detected OS: macos (Darwin arm64)
Core build tools:
[ ok ] cmake cmake version 4.1.2
[ ok ] conan Conan version 2.28.1
[ ok ] git git version 2.54.0
[ ok ] python3 Python 3.13.13
Development tooling:
[ ok ] ccache ccache version 4.13.6
[ ok ] clang clang version 22.1.7
[ ok ] clang++ clang version 22.1.7
[ ok ] ClangBuildAnalyzer ClangBuildAnalyzer 1.6.0
[ ok ] 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
[ ok ] file file-5.47
[ ok ] less less 692 (PCRE2 regular expressions)
[ ok ] make GNU Make 4.4.1
[ ok ] netstat present
[ ok ] ninja 1.13.2
[ ok ] perl v5.42.0
[ ok ] pkg-config 0.29.2
[ ok ] vim VIM - Vi IMproved 9.2 (2026 Feb 14, compiled Jan 01 1980 00:00:00)
[ ok ] zip Zip 3.0
[ ok ] clang-format clang-format version 22.1.7
[ ok ] dot dot - graphviz version 12.2.1 (0)
[ ok ] doxygen 1.16.1
[ ok ] gcovr gcovr 8.4
[ ok ] gh gh version 2.94.0 (nixpkgs)
[ ok ] git-cliff git-cliff 2.13.1
[ ok ] git-lfs git-lfs/3.7.1 (3.7.1; darwin arm64; go 1.26.3)
[ ok ] gpg gpg (GnuPG) 2.4.9
[ ok ] pre-commit pre-commit 4.5.1
[ ok ] run-clang-tidy usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
Rust toolchain:
[ ok ] cargo cargo 1.95.0 (f2d3ce0bd 2026-03-21)
[ ok ] cargo-audit cargo-audit-audit 0.22.1
[ ok ] cargo-llvm-cov cargo-llvm-cov 0.8.5
[ ok ] cargo-nextest cargo-nextest 0.9.137
[ ok ] clippy clippy 0.1.95 (59807616e1 2026-04-14)
[ ok ] rust-analyzer rust-analyzer 1.95.0 (59807616 2026-04-14)
[ ok ] rustc rustc 1.95.0 (59807616e 2026-04-14)
[ ok ] rustfmt rustfmt 1.9.0-stable (59807616e1 2026-04-14)
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
All 36 checked tools are present and runnable.

View File

@@ -1,55 +0,0 @@
Detected OS: linux (Linux x86_64)
Core build tools:
[ ok ] cmake cmake version 4.1.2
[ ok ] conan Conan version 2.28.1
[ ok ] git git version 2.54.0
[ ok ] python3 Python 3.13.13
Development tooling:
[ ok ] ccache ccache version 4.13.6
[ ok ] clang clang version 22.1.7
[ ok ] clang++ clang version 22.1.7
[ ok ] ClangBuildAnalyzer ClangBuildAnalyzer 1.6.0
[ ok ] 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
[ ok ] file file-5.47
[ ok ] less less 692 (PCRE2 regular expressions)
[ ok ] make GNU Make 4.4.1
[ ok ] netstat net-tools 2.10
[ ok ] ninja 1.13.2
[ ok ] perl v5.42.0
[ ok ] pkg-config 0.29.2
[ ok ] vim VIM - Vi IMproved 9.2 (2026 Feb 14, compiled Jan 01 1980 00:00:00)
[ ok ] zip Zip 3.0
[ ok ] clang-format clang-format version 22.1.7
[ ok ] dot dot - graphviz version 12.2.1 (0)
[ ok ] doxygen 1.16.1
[ ok ] gcovr gcovr 8.4
[ ok ] gh gh version 2.94.0 (nixpkgs)
[ ok ] git-cliff git-cliff 2.13.1
[ ok ] git-lfs git-lfs/3.7.1 (3.7.1; linux amd64; go 1.26.3)
[ ok ] gpg gpg (GnuPG) 2.4.9
[ ok ] pre-commit pre-commit 4.5.1
[ ok ] run-clang-tidy usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
Rust toolchain:
[ ok ] cargo cargo 1.95.0 (f2d3ce0bd 2026-03-21)
[ ok ] cargo-audit cargo-audit-audit 0.22.1
[ ok ] cargo-llvm-cov cargo-llvm-cov 0.8.5
[ ok ] cargo-nextest cargo-nextest 0.9.137
[ ok ] clippy clippy 0.1.95 (59807616e1 2026-04-14)
[ ok ] rust-analyzer rust-analyzer 1.95.0 (5980761 2026-04-14)
[ ok ] rustc rustc 1.95.0 (59807616e 2026-04-14)
[ ok ] rustfmt rustfmt 1.9.0-stable (59807616e1 2026-04-14)
GCC toolchain:
[ ok ] gcc gcc (GCC) 15.2.0
[ ok ] g++ g++ (GCC) 15.2.0
[ ok ] gcov gcov (GCC) 15.2.0
Mold:
[ ok ] mold mold 2.41.0 (compatible with GNU ld)
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
All 40 checked tools are present and runnable.

View File

@@ -1,55 +0,0 @@
Detected OS: linux (Linux aarch64)
Core build tools:
[ ok ] cmake cmake version 4.1.2
[ ok ] conan Conan version 2.28.1
[ ok ] git git version 2.54.0
[ ok ] python3 Python 3.13.13
Development tooling:
[ ok ] ccache ccache version 4.13.6
[ ok ] clang clang version 22.1.7
[ ok ] clang++ clang version 22.1.7
[ ok ] ClangBuildAnalyzer ClangBuildAnalyzer 1.6.0
[ ok ] 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
[ ok ] file file-5.47
[ ok ] less less 692 (PCRE2 regular expressions)
[ ok ] make GNU Make 4.4.1
[ ok ] netstat net-tools 2.10
[ ok ] ninja 1.13.2
[ ok ] perl v5.42.0
[ ok ] pkg-config 0.29.2
[ ok ] vim VIM - Vi IMproved 9.2 (2026 Feb 14, compiled Jan 01 1980 00:00:00)
[ ok ] zip Zip 3.0
[ ok ] clang-format clang-format version 22.1.7
[ ok ] dot dot - graphviz version 12.2.1 (0)
[ ok ] doxygen 1.16.1
[ ok ] gcovr gcovr 8.4
[ ok ] gh gh version 2.94.0 (nixpkgs)
[ ok ] git-cliff git-cliff 2.13.1
[ ok ] git-lfs git-lfs/3.7.1 (3.7.1; linux arm64; go 1.26.3)
[ ok ] gpg gpg (GnuPG) 2.4.9
[ ok ] pre-commit pre-commit 4.5.1
[ ok ] run-clang-tidy usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
Rust toolchain:
[ ok ] cargo cargo 1.95.0 (f2d3ce0bd 2026-03-21)
[ ok ] cargo-audit cargo-audit-audit 0.22.1
[ ok ] cargo-llvm-cov cargo-llvm-cov 0.8.5
[ ok ] cargo-nextest cargo-nextest 0.9.137
[ ok ] clippy clippy 0.1.95 (59807616e1 2026-04-14)
[ ok ] rust-analyzer rust-analyzer 1.95.0 (5980761 2026-04-14)
[ ok ] rustc rustc 1.95.0 (59807616e 2026-04-14)
[ ok ] rustfmt rustfmt 1.9.0-stable (59807616e1 2026-04-14)
GCC toolchain:
[ ok ] gcc gcc (GCC) 15.2.0
[ ok ] g++ g++ (GCC) 15.2.0
[ ok ] gcov gcov (GCC) 15.2.0
Mold:
[ ok ] mold mold 2.41.0 (compatible with GNU ld)
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
All 40 checked tools are present and runnable.

View File

@@ -50,17 +50,12 @@ let
# compilerName is the command used to print the version, or null for none.
makeShell =
{
shellName,
stdenv,
compilerName,
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,
}:
let
compilerVersionHook =
@@ -78,20 +73,14 @@ let
tools = versionedTools;
});
in
(pkgs.mkShell.override { inherit stdenv; }) (
{
packages = commonPackages ++ 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;
shellHook = ''
echo "Welcome to xrpld development shell";
${compilerVersionHook}
${warningHook}
'';
}
// pkgs.lib.optionalAttrs noPatchNixBinary { XRPLD_NO_PATCH_NIX_BINARY = "1"; }
);
(pkgs.mkShell.override { inherit stdenv; }) {
packages = commonPackages ++ versionedLinks ++ extraPackages;
shellHook = ''
echo "Welcome to xrpld development shell";
${compilerVersionHook}
${warningHook}
'';
};
in
rec {
# macOS: Nix Clang. Linux: Nix GCC.
@@ -100,7 +89,6 @@ rec {
# 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.
gcc = makeShell {
shellName = "gcc";
stdenv = customGccStdenv;
compilerName = "gcc";
version = gccVersion;
@@ -109,7 +97,6 @@ rec {
};
clang = makeShell {
shellName = "clang";
stdenv = customClangStdenv;
compilerName = "clang";
version = llvmVersion;
@@ -118,7 +105,6 @@ rec {
# Nix provides no compiler; use the one from your system (e.g. Apple Clang).
no-compiler = makeShell {
shellName = "no-compiler";
stdenv = pkgs.stdenvNoCC;
compilerName = null;
};
@@ -129,23 +115,19 @@ rec {
# makes `nix develop .#gcc-plain` fail there rather than silently aliasing gcc.
// pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
gcc-plain = makeShell {
shellName = "gcc-plain";
stdenv = plainGccStdenv;
compilerName = "gcc";
version = gccVersion;
versionedTools = gccVersionedTools;
extraPackages = [ plainGcov ];
warningHook = plainWarningHook;
noPatchNixBinary = true;
};
clang-plain = makeShell {
shellName = "clang-plain";
stdenv = plainClangStdenv;
compilerName = "clang";
version = llvmVersion;
versionedTools = clangVersionedTools;
warningHook = plainWarningHook;
noPatchNixBinary = true;
};
}

View File

@@ -58,7 +58,7 @@ ENV GIT_SSL_CAINFO="/nix/ci-env/etc/ssl/certs/ca-bundle.crt"
# Externally-built dynamically-linked ELF binaries hard-code the loader path
# (e.g. /lib64/ld-linux-x86-64.so.2) in their PT_INTERP header. Install it
# from the Nix store when the base image doesn't already provide one.
COPY bin/default-loader-path.sh /tmp/loader-path.sh
COPY nix/docker/loader-path.sh /tmp/loader-path.sh
RUN <<EOF
target="$(/tmp/loader-path.sh)"

View File

@@ -75,9 +75,8 @@ toolchain being present at runtime. Two pieces make that work:
- **An expected dynamic linker in the image.**
Binaries built in Nix environments reference a dynamic linker from Nix store paths, which won't be present in the base image. However,
[`bin/default-loader-path.sh`](../../bin/default-loader-path.sh) reports the
expected loader path for the current architecture, so we can patch the binaries
to use the correct loader.
[`loader-path.sh`](./loader-path.sh) reports the expected loader path for the
current architecture, so we can patch the binaries to use the correct loader.
The build then verifies all of this end to end, and the C++ and Rust programs
go through the same pipeline: each is compiled in `final`, has its `PT_INTERP`
@@ -94,8 +93,8 @@ whose resulting binary is patched and run like the others.
| File | Purpose |
| ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| [`./Dockerfile`](./Dockerfile) | Multi-stage build described above. |
| [`./loader-path.sh`](./loader-path.sh) | Print the dynamic-linker (`PT_INTERP`) path for the current architecture. |
| [`./test_files/cpp/`](./test_files/cpp) | C++ sanitizer smoke test: sources + compile/run scripts. |
| [`./test_files/rust/`](./test_files/rust) | Rust smoke test: rustc sources + a cargo proc-macro workspace + compile/run scripts. |
| [`/bin/check-tools.sh`](../../bin/check-tools.sh) | Verify every expected tools are present and runnable. |
| [`/bin/default-loader-path.sh`](../../bin/default-loader-path.sh) | Print the dynamic-linker (`PT_INTERP`) path for the current architecture. |
| [`/bin/install-sanitizer-libs.sh`](../../bin/install-sanitizer-libs.sh) | Install `libasan`/`libtsan`/`libubsan` runtimes on the supported base images. |

View File

@@ -16,23 +16,7 @@ let
exec ${pkgs.python3}/bin/python3 ${llvmPackages.clang-unwrapped}/bin/run-clang-tidy "$@"
'';
# rust-overlay's toolchain propagates the *default* stdenv.cc onto the PATH (so
# cargo has a linker). That default may be different from the clang we pin here,
# so it shadows our clang and the build can silently use a different compiler
# version. Drop that cc from every propagation channel instead of pinning a
# replacement: the toolchain then carries no compiler and cargo just uses the
# active shell's stdenv cc. Must cover all channels — rust-overlay uses both
# propagatedBuildInputs and depsHostHostPropagated.
rustToolchainBase = pkgs.rust-bin.fromRustupToolchainFile ../rust-toolchain.toml;
rustToolchain =
let
defaultCc = pkgs.stdenv.cc; # default compiler from nixpkgs stdenv
withoutDefaultCc = builtins.filter (dep: (dep.outPath or "") != defaultCc.outPath);
in
rustToolchainBase.overrideAttrs (old: {
propagatedBuildInputs = withoutDefaultCc (old.propagatedBuildInputs or [ ]);
depsHostHostPropagated = withoutDefaultCc (old.depsHostHostPropagated or [ ]);
});
rustToolchain = pkgs.rust-bin.fromRustupToolchainFile ../rust-toolchain.toml;
# Nix wraps its toolchain so that binaries are exposed only under unsuffixed
# names (gcc, g++, clang-tidy, ...). Several tools probe for a

View File

@@ -192,7 +192,6 @@ unsigned-integer-overflow:rpc/handlers/orderbook/GetAggregatePrice.cpp
# Test-only intentional overflow/underflow in fixture and unit-test arithmetic.
unsigned-integer-overflow:tests/libxrpl/basics/RangeSet.cpp
unsigned-integer-overflow:test/app/Batch_test.cpp
unsigned-integer-overflow:test/app/ConfidentialTransfer_test.cpp
unsigned-integer-overflow:test/app/Invariants_test.cpp
unsigned-integer-overflow:test/app/Loan_test.cpp
unsigned-integer-overflow:test/app/NFToken_test.cpp

View File

@@ -17,25 +17,24 @@
#include <utility>
#include <vector>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
namespace {
constexpr auto kPoolSizes = std::to_array<std::size_t>({1000, 10000, 100000});
constexpr auto kThreadCounts = std::to_array<std::size_t>({1, 4, 8});
constexpr std::size_t kPoolSizes[] = {1000, 10000, 100000};
constexpr int kThreadCounts[] = {1, 4, 8};
constexpr std::size_t kBatchSize = 256;
constexpr std::size_t kMissRatio = 5;
constexpr std::string_view kNamePrefix = "BM_Backend_";
constexpr std::string_view kNameSeparator = "/";
struct RunState
{
std::unique_ptr<BackendHarness> harness; ///< backend under test, rebuilt per run
Batch present; ///< prefix-1 objects, eligible to be stored
Batch recent; ///< prefix-1 objects in the "future" key space
std::vector<uint256> missing; ///< prefix-2 keys that are never stored
std::vector<std::size_t> shuffle; ///< [0, poolSize) permutation for random-like access
std::size_t avgPayload = 0; ///< mean getData().size() over `present`
std::unique_ptr<BackendHarness> harness;
Batch present; // prefix-1 objects, eligible to be stored
Batch recent; // prefix-1 objects in the "future" key space
std::vector<uint256> missing; // prefix-2 keys that are never stored
std::vector<std::size_t> shuffle; // [0, poolSize) permutation for random-like access
std::size_t avgPayload = 0; // mean getData().size() over `present`
void
release()
@@ -86,7 +85,7 @@ Workload const kInsert{
},
.iterate =
[](IterateContext const& ctx) {
auto const& [rs, backend, index, poolSize] = ctx;
auto& [rs, backend, index, poolSize] = ctx;
backend.store(rs.present[index % poolSize]);
},
.reportBytes = true,
@@ -105,7 +104,7 @@ Workload const kFetch{
},
.iterate =
[](IterateContext const& ctx) {
auto const& [rs, backend, index, poolSize] = ctx;
auto& [rs, backend, index, poolSize] = ctx;
std::shared_ptr<NodeObject> result;
backend.fetch(rs.present[index % poolSize]->getHash(), &result);
benchmark::DoNotOptimize(result);
@@ -119,7 +118,7 @@ Workload const kMissing{
.setup = [](SetupContext const& ctx) { ctx.rs.missing = makeMissingKeys(ctx.poolSize); },
.iterate =
[](IterateContext const& ctx) {
auto const& [rs, backend, index, poolSize] = ctx;
auto& [rs, backend, index, poolSize] = ctx;
std::shared_ptr<NodeObject> result;
backend.fetch(rs.missing[index % poolSize], &result);
benchmark::DoNotOptimize(result);
@@ -140,10 +139,10 @@ Workload const kMixed{
},
.iterate =
[](IterateContext const& ctx) {
auto const& [rs, backend, index, poolSize] = ctx;
auto& [rs, backend, index, poolSize] = ctx;
std::shared_ptr<NodeObject> result;
auto const pick = rs.shuffle[index % poolSize];
if (index % kMissRatio == 0)
if (index % 5 == 0)
{
backend.fetch(rs.missing[pick], &result);
}
@@ -171,7 +170,7 @@ Workload const kWork{
},
.iterate =
[](IterateContext const& ctx) {
auto const& [rs, backend, index, poolSize] = ctx;
auto& [rs, backend, index, poolSize] = ctx;
auto const slot = index % poolSize;
auto const pick = rs.shuffle[slot];
@@ -240,7 +239,7 @@ registerWorkload(BackendConfig const& bc, Workload const& w)
{
auto rs = std::make_shared<RunState>();
auto* b = benchmark::RegisterBenchmark(name, makeRunner(w, cfg, rs));
b->RangeMultiplier(10)->Range(kPoolSizes.front(), kPoolSizes.back());
b->RangeMultiplier(10)->Range(kPoolSizes[0], kPoolSizes[std::size(kPoolSizes) - 1]);
b->Threads(1)->Threads(4)->Threads(8)->UseRealTime();
return;
@@ -250,14 +249,14 @@ registerWorkload(BackendConfig const& bc, Workload const& w)
{
for (auto const threads : kThreadCounts)
{
if (poolSize % threads != 0)
if (poolSize % static_cast<std::size_t>(threads) != 0)
continue;
auto rs = std::make_shared<RunState>();
benchmark::RegisterBenchmark(name, makeRunner(w, cfg, rs))
->Arg(poolSize)
->Iterations(poolSize / threads)
->Threads(static_cast<int>(threads))
->Iterations(poolSize / static_cast<std::size_t>(threads))
->Threads(threads)
->UseRealTime();
}
}
@@ -290,7 +289,7 @@ registerStoreBatch(BackendConfig const& bc)
rs->harness = std::make_unique<BackendHarness>(cfg);
rs->present = makePool(1, poolSize);
rs->avgPayload = averagePayload(rs->present);
std::vector<Batch> const batches = sliceFixedBatches(rs->present, kBatchSize);
std::vector<Batch> const batches = sliceBatches(rs->present, kBatchSize);
if (batches.empty())
{
state.SkipWithError("pool smaller than one batch");
@@ -327,4 +326,4 @@ registerStoreBatch(BackendConfig const& bc)
}();
} // namespace
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -18,7 +18,7 @@
#include <utility>
#include <vector>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
namespace {
// Number of distinct objects pre-generated per run.
@@ -240,4 +240,4 @@ registerWorkload(BackendConfig const& bc, Workload const& w)
}();
} // namespace
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -26,14 +26,13 @@
#include <memory>
#include <numeric>
#include <random>
#include <ranges>
#include <string>
#include <utility>
#include <vector>
// Shared helpers for the NodeStore benchmarks.
//
namespace xrpl::node_store {
namespace xrpl::NodeStore {
// Fill `bytes` of memory at `buffer` with random bits drawn from `g`.
template <class Generator>
@@ -41,13 +40,18 @@ inline void
rngcpy(void* buffer, std::size_t bytes, Generator& g)
{
using result_type = typename Generator::result_type;
while (bytes > 0)
while (bytes >= sizeof(result_type))
{
auto const v = g();
auto const chunk = std::min(bytes, sizeof(result_type));
std::memcpy(buffer, &v, chunk);
buffer = reinterpret_cast<std::uint8_t*>(buffer) + chunk;
bytes -= chunk;
std::memcpy(buffer, &v, sizeof(v));
buffer = reinterpret_cast<std::uint8_t*>(buffer) + sizeof(v);
bytes -= sizeof(v);
}
if (bytes > 0)
{
auto const v = g();
std::memcpy(buffer, &v, bytes);
}
}
@@ -141,7 +145,7 @@ makePool(std::uint8_t prefix, std::size_t count, std::size_t start = 0)
Sequence seq(prefix);
Batch pool;
pool.reserve(count);
for (auto i = 0uz; i < count; ++i)
for (std::size_t i = 0; i < count; ++i)
pool.push_back(seq.obj(start + i));
return pool;
}
@@ -154,7 +158,7 @@ makeMissingKeys(std::size_t count)
Sequence seq(2);
std::vector<uint256> keys;
keys.reserve(count);
for (auto i = 0uz; i < count; ++i)
for (std::size_t i = 0; i < count; ++i)
keys.push_back(seq.key(i));
return keys;
}
@@ -202,16 +206,16 @@ inline std::vector<std::size_t>
makeShuffle(std::size_t size, std::uint64_t seed)
{
std::vector<std::size_t> v(size);
std::ranges::iota(v, 0uz);
std::iota(v.begin(), v.end(), std::size_t{0});
beast::xor_shift_engine gen(seed);
std::ranges::shuffle(v, gen);
std::shuffle(v.begin(), v.end(), gen);
return v;
}
// Partition a pool into fixed-size batches. Any trailing remainder shorter than
// `batchSize` is dropped, so every returned batch has exactly `batchSize`.
inline std::vector<Batch>
sliceFixedBatches(Batch const& pool, std::size_t batchSize)
sliceBatches(Batch const& pool, std::size_t batchSize)
{
std::vector<Batch> batches;
if (batchSize == 0)
@@ -224,10 +228,13 @@ sliceFixedBatches(Batch const& pool, std::size_t batchSize)
/**
* @brief RAII owner of a NodeStore Backend opened on a private temporary directory.
*
* Member declaration order matters: `tempDir` is declared first so it is
* destroyed last, after the backend has closed and released its files.
*/
struct BackendHarness
{
beast::TempDir tempDir; ///< Declared first so it is destroyed last
beast::TempDir tempDir;
DummyScheduler scheduler;
beast::Journal journal{beast::Journal::getNullSink()};
std::unique_ptr<Backend> backend;
@@ -308,4 +315,4 @@ backendConfigs()
return kConfigs;
}
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -15,7 +15,7 @@
namespace beast {
std::string
printIdentifiers(SemanticVersion::IdentifierList const& list)
printIdentifiers(SemanticVersion::identifier_list const& list)
{
std::string ret;
@@ -115,7 +115,7 @@ extractIdentifier(std::string& value, bool allowLeadingZeroes, std::string& inpu
bool
extractIdentifiers(
SemanticVersion::IdentifierList& identifiers,
SemanticVersion::identifier_list& identifiers,
bool allowLeadingZeroes,
std::string& input)
{

View File

@@ -26,6 +26,14 @@ namespace xrpl {
namespace directory {
struct Gap
{
uint64_t const page;
SLE::pointer node;
uint64_t const nextPage;
SLE::pointer next;
};
std::uint64_t
createRoot(
ApplyView& view,
@@ -126,7 +134,9 @@ insertPage(
if (page == 0)
return std::nullopt;
if (!view.rules().enabled(fixDirectoryLimit) && page >= kDirNodeMaxPages) // Old pages limit
{
return std::nullopt;
}
// We are about to create a new node; we'll link it to
// the chain first:
@@ -147,12 +157,8 @@ insertPage(
// Save some space by not specifying the value 0 since it's the default.
if (page != 1)
node->setFieldU64(sfIndexPrevious, page - 1);
XRPL_ASSERT_PARTS(!nextPage, "xrpl::directory::insertPage", "nextPage has default value");
/* Reserved for future use when directory pages may be inserted in
* between two other pages instead of only at the end of the chain.
if (nextPage)
node->setFieldU64(sfIndexNext, nextPage);
*/
describe(node);
view.insert(node);
@@ -168,7 +174,7 @@ ApplyView::dirAdd(
uint256 const& key,
std::function<void(SLE::ref)> const& describe)
{
auto root = peek(directory);
auto const root = peek(directory);
if (!root)
{
@@ -178,6 +184,43 @@ ApplyView::dirAdd(
auto [page, node, indexes] = directory::findPreviousPage(*this, directory, root);
if (rules().enabled(featureDefragDirectories))
{
// If there are more nodes than just the root, and there's no space in
// the last one, walk backwards to find one with space, or to find one
// missing.
std::optional<directory::Gap> gapPages;
while (page && indexes.size() >= kDIR_NODE_MAX_PAGES)
{
// Find a page with space, or a gap in pages.
auto [prevPage, prevNode, prevIndexes] =
directory::findPreviousPage(*this, directory, node);
if (!gapPages && prevPage != page - 1)
gapPages.emplace(prevPage, prevNode, page, node);
page = prevPage;
node = prevNode;
indexes = prevIndexes;
}
// We looped through all the pages back to the root.
if (!page)
{
// If we found a gap, use it.
if (gapPages)
{
return directory::insertPage(
*this,
gapPages->page,
gapPages->node,
gapPages->nextPage,
gapPages->next,
key,
directory,
describe);
}
std::tie(page, node, indexes) = directory::findPreviousPage(*this, directory, root);
}
}
// If there's space, we use it:
if (indexes.size() < kDirNodeMaxEntries)
{

View File

@@ -9,7 +9,6 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/VaultHelpers.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/LedgerFormats.h>
@@ -131,127 +130,6 @@ isRounded(Asset const& asset, Number const& value, std::int32_t scale)
roundToAsset(asset, value, scale, Number::RoundingMode::Upward);
}
namespace Accrual {
AccountingDeltas
loanOriginationDeltas(Number const& principalRequested, Number const& interestDue)
{
return {.assetsTotalDelta = interestDue, .debtTotalDelta = principalRequested + interestDue};
}
bool
loanOriginationExceedsVaultMaximum(
Number const& vaultMaximum,
Number const& vaultTotal,
Number const& interestDue)
{
return vaultMaximum != 0 && interestDue > vaultMaximum - vaultTotal;
}
/*
XLS-66 section 3.2.3.2, defines the default amount as
DefaultAmount = (Loan.PrincipalOutstanding + Loan.InterestOutstanding)
Which is equivalent to (Loan.TotalValueOutstanding - Loan.ManagementFeeOutstanding)
*/
Number
loanVaultExposure(SLE::const_ref loanSle)
{
return loanSle->at(sfTotalValueOutstanding) - loanSle->at(sfManagementFeeOutstanding);
}
AccountingDeltas
loanPaymentDeltas(LoanPaymentParts const& parts)
{
return {
.assetsTotalDelta = parts.valueChange,
.debtTotalDelta = (parts.principalPaid + parts.interestPaid) - parts.valueChange};
}
} // namespace Accrual
namespace CashBasis {
AccountingDeltas
loanOriginationDeltas(Number const& principalRequested)
{
return {.assetsTotalDelta = kNumZero, .debtTotalDelta = principalRequested};
}
/*
* Under CashBasis accounting, Loan default amount is:
*
* DefaultAmount = Loan.PrincipalOutstanding
*/
Number
loanVaultExposure(SLE::const_ref loanSle)
{
return loanSle->at(sfPrincipalOutstanding);
}
AccountingDeltas
loanPaymentDeltas(LoanPaymentParts const& parts)
{
return {.assetsTotalDelta = parts.interestPaid, .debtTotalDelta = parts.principalPaid};
}
} // namespace CashBasis
namespace {
// Cash-basis accounting applies only when featureLendingProtocolV1_1 is
// enabled AND the specific Vault was created under it (LEVersion ==
// VaultVersion::CashBasis). Vaults created before activation keep accrual-basis
// accounting forever, even after the amendment later turns on.
bool
cashBasisEnabled(SLE::const_ref vaultSle)
{
return getVaultVersion(vaultSle) == VaultVersion::CashBasis;
}
} // namespace
AccountingDeltas
loanOriginationDeltas(
SLE::const_ref vaultSle,
Number const& principalRequested,
Number const& interestDue)
{
return cashBasisEnabled(vaultSle)
? CashBasis::loanOriginationDeltas(principalRequested)
: Accrual::loanOriginationDeltas(principalRequested, interestDue);
}
bool
loanOriginationExceedsVaultMaximum(
SLE::const_ref vaultSle,
Number const& vaultTotal,
Number const& interestDue)
{
// Cash-basis origination doesn't recognize interest into AssetsTotal, so
// interest due can never push the vault past AssetsMaximum at origination.
if (cashBasisEnabled(vaultSle))
return false;
auto const vaultMaximum = vaultSle->at(sfAssetsMaximum);
return Accrual::loanOriginationExceedsVaultMaximum(vaultMaximum, vaultTotal, interestDue);
}
Number
loanVaultExposure(SLE::const_ref vaultSle, SLE::const_ref loanSle)
{
return cashBasisEnabled(vaultSle) ? CashBasis::loanVaultExposure(loanSle)
: Accrual::loanVaultExposure(loanSle);
}
AccountingDeltas
loanPaymentDeltas(SLE::const_ref vaultSle, LoanPaymentParts const& parts)
{
return cashBasisEnabled(vaultSle) ? CashBasis::loanPaymentDeltas(parts)
: Accrual::loanPaymentDeltas(parts);
}
namespace detail {
void

View File

@@ -3,19 +3,14 @@
#include <xrpl/basics/Log.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/EscrowHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Concepts.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Rate.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/TER.h>
@@ -23,19 +18,12 @@
#include <cstdint>
#include <limits>
#include <optional>
#include <variant>
namespace xrpl {
TER
closeChannel(
SLE::ref slep,
ApplyViewContext ctx,
uint256 const& key,
AccountID const& txAccount,
beast::Journal j)
closeChannel(SLE::ref slep, ApplyView& view, uint256 const& key, beast::Journal j)
{
ApplyView& view = ctx.view;
AccountID const src = (*slep)[sfAccount];
// Remove PayChan from owner directory
{
@@ -50,9 +38,9 @@ closeChannel(
}
// Remove PayChan from recipient's owner directory, if present.
AccountID const dst = (*slep)[sfDestination];
if (auto const page = (*slep)[~sfDestinationNode])
{
auto const dst = (*slep)[sfDestination];
if (!view.dirRemove(keylet::ownerDir(dst), *page, key, true))
{
// LCOV_EXCL_START
@@ -69,63 +57,7 @@ closeChannel(
XRPL_ASSERT(
(*slep)[sfAmount] >= (*slep)[sfBalance], "xrpl::closeChannel : minimum channel amount");
auto const reqDelta = (*slep)[sfAmount] - (*slep)[sfBalance];
auto const& issuer = reqDelta.getIssuer();
// Only update the balance if there is a positive delta.
if (reqDelta > beast::kZero)
{
if (isXRP(reqDelta))
{
(*sle)[sfBalance] = (*sle)[sfBalance] + reqDelta;
}
else
{
if (!view.rules().enabled(featureTokenPaychan))
return temDISABLED;
if (auto const ret = std::visit(
[&]<typename T>(T const&) {
return escrowUnlockPreclaimHelper<T>(view, src, reqDelta, false);
},
reqDelta.asset().value());
!isTesSuccess(ret))
return ret;
bool const createAsset = src == txAccount;
if (auto const ret = std::visit(
[&]<typename T>(T const&) {
return escrowUnlockApplyHelper<T>(
ctx,
kParityRate,
sle,
STAmount{(*sle)[sfBalance]}.xrp(),
reqDelta,
issuer,
src,
src,
createAsset,
j);
},
reqDelta.asset().value());
!isTesSuccess(ret))
return ret;
}
}
// Remove PayChan from issuer's owner directory, if present.
if (auto const optPage = (*slep)[~sfIssuerNode])
{
if (!view.dirRemove(keylet::ownerDir(issuer), *optPage, key, true))
{
// LCOV_EXCL_START
JLOG(j.fatal()) << "Could not remove paychan from issuer owner directory";
return tefBAD_LEDGER;
// LCOV_EXCL_STOP
}
}
(*sle)[sfBalance] = (*sle)[sfBalance] + (*slep)[sfAmount] - (*slep)[sfBalance];
decreaseOwnerCountForObject(view, sle, slep, 1, j);
view.update(sle);

View File

@@ -6,7 +6,6 @@
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h> // IWYU pragma: keep
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STLedgerEntry.h>
@@ -14,7 +13,6 @@
#include <cstdint>
#include <optional>
#include <utility>
namespace xrpl {
@@ -139,22 +137,4 @@ isSoleShareholder(ReadView const& view, AccountID const& account, SLE::const_ref
return sleToken->getFieldU64(sfMPTAmount) == outstanding;
}
[[nodiscard]] VaultVersion
getVaultVersion(SLE::const_ref vault)
{
XRPL_ASSERT(vault && vault->getType() == ltVAULT, "xrpl::getVaultVersion : valid Vault sle");
if (!vault->isFieldPresent(sfLEVersion))
return VaultVersion::Legacy;
auto const version = vault->at(sfLEVersion);
if (version > std::to_underlying(VaultVersion::CashBasis))
{
// LCOV_EXCL_START
UNREACHABLE("xrpl::getVaultVersion : invalid vault version");
return VaultVersion::Legacy;
// LCOV_EXCL_STOP
}
return static_cast<VaultVersion>(version);
}
} // namespace xrpl

View File

@@ -11,7 +11,7 @@
#include <mutex>
#include <vector>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
BatchWriter::BatchWriter(Callback& callback, Scheduler& scheduler)
: callback_(callback), scheduler_(scheduler)
@@ -72,7 +72,7 @@ BatchWriter::writeBatch()
writeSet_.swap(set);
XRPL_ASSERT(
writeSet_.empty(), "xrpl::node_store::BatchWriter::writeBatch : writes not set");
writeSet_.empty(), "xrpl::NodeStore::BatchWriter::writeBatch : writes not set");
writeLoad_ = set.size();
if (set.empty())
@@ -107,4 +107,4 @@ BatchWriter::waitForWriting()
writeCondition_.wait(sl);
}
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -30,7 +30,7 @@
#include <thread>
#include <utility>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
Database::Database(
Scheduler& scheduler,
@@ -43,7 +43,7 @@ Database::Database(
, requestBundle_(get<int>(config, Keys::kRqBundle, 4))
, readThreads_(std::max(1, readThreads))
{
XRPL_ASSERT(readThreads, "xrpl::node_store::Database::Database : nonzero threads input");
XRPL_ASSERT(readThreads, "xrpl::NodeStore::Database::Database : nonzero threads input");
if (earliestLedgerSeq_ < 1)
Throw<std::runtime_error>("Invalid earliest_seq");
@@ -89,7 +89,7 @@ Database::Database(
{
XRPL_ASSERT(
!it->second.empty(),
"xrpl::node_store::Database::Database : non-empty "
"xrpl::NodeStore::Database::Database : non-empty "
"data");
auto const& hash = it->first;
@@ -164,7 +164,7 @@ Database::stop()
{
XRPL_ASSERT(
steady_clock::now() - start < 30s,
"xrpl::node_store::Database::stop : maximum stop duration");
"xrpl::NodeStore::Database::stop : maximum stop duration");
std::this_thread::yield();
}
@@ -213,7 +213,7 @@ Database::importInternal(Backend& dstBackend, Database& srcDB)
};
srcDB.forEach([&](std::shared_ptr<NodeObject> nodeObject) {
XRPL_ASSERT(nodeObject, "xrpl::node_store::Database::importInternal : non-null node");
XRPL_ASSERT(nodeObject, "xrpl::NodeStore::Database::importInternal : non-null node");
if (!nodeObject) // This should never happen
return;
@@ -257,7 +257,7 @@ Database::fetchNodeObject(
void
Database::getCountsJson(json::Value& obj)
{
XRPL_ASSERT(obj.isObject(), "xrpl::node_store::Database::getCountsJson : valid input type");
XRPL_ASSERT(obj.isObject(), "xrpl::NodeStore::Database::getCountsJson : valid input type");
{
std::unique_lock<std::mutex> const lock(readLock_);
@@ -276,4 +276,4 @@ Database::getCountsJson(json::Value& obj)
obj[jss::node_reads_duration_us] = std::to_string(fetchDurationUs_);
}
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -15,7 +15,7 @@
#include <memory>
#include <utility>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
void
DatabaseNodeImp::store(NodeObjectType type, Blob&& data, uint256 const& hash, std::uint32_t)
@@ -125,4 +125,4 @@ DatabaseNodeImp::fetchNodeObject(
return nodeObject;
}
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -22,7 +22,7 @@
#include <string>
#include <utility>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
DatabaseRotatingImp::DatabaseRotatingImp(
Scheduler& scheduler,
@@ -43,7 +43,7 @@ DatabaseRotatingImp::DatabaseRotatingImp(
void
DatabaseRotatingImp::rotate(
std::unique_ptr<node_store::Backend>&& newBackend,
std::unique_ptr<NodeStore::Backend>&& newBackend,
std::function<void(std::string const& writableName, std::string const& archiveName)> const& f)
{
// Pass these two names to the callback function
@@ -52,7 +52,7 @@ DatabaseRotatingImp::rotate(
// Hold on to current archive backend pointer until after the
// callback finishes. Only then will the archive directory be
// deleted.
std::shared_ptr<node_store::Backend> oldArchiveBackend;
std::shared_ptr<NodeStore::Backend> oldArchiveBackend;
std::uint64_t copyForwards = 0;
{
std::scoped_lock const lock(mutex_);
@@ -232,4 +232,4 @@ DatabaseRotatingImp::forEach(std::function<void(std::shared_ptr<NodeObject>)> f)
archive->forEach(f);
}
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -10,7 +10,7 @@
#include <memory>
#include <utility>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
DecodedBlob::DecodedBlob(void const* key, void const* value, int valueBytes) : key_(key)
{
@@ -55,7 +55,7 @@ DecodedBlob::DecodedBlob(void const* key, void const* value, int valueBytes) : k
std::shared_ptr<NodeObject>
DecodedBlob::createObject()
{
XRPL_ASSERT(success_, "xrpl::node_store::DecodedBlob::createObject : valid object type");
XRPL_ASSERT(success_, "xrpl::NodeStore::DecodedBlob::createObject : valid object type");
std::shared_ptr<NodeObject> object;
@@ -69,4 +69,4 @@ DecodedBlob::createObject()
return object;
}
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -3,7 +3,7 @@
#include <xrpl/nodestore/Scheduler.h>
#include <xrpl/nodestore/Task.h>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
void
DummyScheduler::scheduleTask(Task& task)
@@ -22,4 +22,4 @@ DummyScheduler::onBatchWrite(BatchWriteReport const& report)
{
}
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -22,7 +22,7 @@
#include <string>
#include <utility>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
ManagerImp&
ManagerImp::instance()
@@ -112,7 +112,7 @@ ManagerImp::erase(Factory& factory)
std::scoped_lock const _(mutex_);
auto const iter =
std::ranges::find_if(list_, [&factory](Factory* other) { return other == &factory; });
XRPL_ASSERT(iter != list_.end(), "xrpl::node_store::ManagerImp::erase : valid input");
XRPL_ASSERT(iter != list_.end(), "xrpl::NodeStore::ManagerImp::erase : valid input");
list_.erase(iter);
}
@@ -135,4 +135,4 @@ Manager::instance()
return ManagerImp::instance();
}
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -24,7 +24,7 @@
#include <tuple>
#include <utility>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
struct MemoryDB
{
@@ -132,7 +132,7 @@ public:
Status
fetch(uint256 const& hash, std::shared_ptr<NodeObject>* pObject) override
{
XRPL_ASSERT(db_, "xrpl::node_store::MemoryBackend::fetch : non-null database");
XRPL_ASSERT(db_, "xrpl::NodeStore::MemoryBackend::fetch : non-null database");
std::scoped_lock const _(db_->mutex);
@@ -149,7 +149,7 @@ public:
void
store(std::shared_ptr<NodeObject> const& object) override
{
XRPL_ASSERT(db_, "xrpl::node_store::MemoryBackend::store : non-null database");
XRPL_ASSERT(db_, "xrpl::NodeStore::MemoryBackend::store : non-null database");
std::scoped_lock const _(db_->mutex);
db_->table.emplace(object->getHash(), object);
}
@@ -169,7 +169,7 @@ public:
void
forEach(std::function<void(std::shared_ptr<NodeObject>)> f) override
{
XRPL_ASSERT(db_, "xrpl::node_store::MemoryBackend::forEach : non-null database");
XRPL_ASSERT(db_, "xrpl::NodeStore::MemoryBackend::forEach : non-null database");
for (auto const& e : db_->table)
f(e.second);
}
@@ -216,4 +216,4 @@ MemoryFactory::createInstance(
return std::make_unique<MemoryBackend>(keyBytes, keyValues, journal);
}
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -44,7 +44,7 @@
#include <string>
#include <utility>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
class NuDBBackend : public Backend
{
@@ -136,7 +136,7 @@ public:
{
// LCOV_EXCL_START
UNREACHABLE(
"xrpl::node_store::NuDBBackend::open : database is already "
"xrpl::NodeStore::NuDBBackend::open : database is already "
"open");
JLOG(j.error()) << "database is already open";
return;
@@ -441,4 +441,4 @@ registerNuDBFactory(Manager& manager)
static NuDBFactory const kInstance{manager};
}
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

View File

@@ -13,7 +13,7 @@
#include <memory>
#include <string>
namespace xrpl::node_store {
namespace xrpl::NodeStore {
class NullBackend : public Backend
{
@@ -125,4 +125,4 @@ registerNullFactory(Manager& manager)
static NullFactory const kInstance{manager};
}
} // namespace xrpl::node_store
} // namespace xrpl::NodeStore

Some files were not shown because too many files have changed in this diff Show More