Compare commits

..

22 Commits

Author SHA1 Message Date
Mayukha Vadari
5a76baabb3 Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-08-17 22:02:17 -04:00
Mayukha Vadari
373952a62c Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-08-12 11:07:38 -04:00
Ayaz Salikhov
739ef8639a build: Respect lld linker if it gets auto-selected (#8011) 2026-08-12 14:03:37 +00:00
Vito Tumas
dc8973053e test: Fix LoanBatch broker cover rates and schedule overflow (#7967) 2026-08-12 13:42:55 +00:00
Timur Yalymov
d06a03baa6 test: Verify private-vault DEX permissions survive domain loss (#7937) 2026-08-12 13:42:02 +00:00
Timur Yalymov
050dbc628f refactor: Drop dead associateAsset calls from loan delete paths (#7986)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-12 13:41:30 +00:00
Mayukha Vadari
261b5201e0 fix: use lowercase rpc namespace after rename 2026-08-11 15:02:12 -04:00
Mayukha Vadari
890b2cfa17 Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-08-11 14:21:43 -04:00
Mayukha Vadari
f03f890511 Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-08-10 14:53:17 -04:00
Mayukha Vadari
553a36ac6f Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-07-27 15:39:37 -04:00
Mayukha Vadari
e6d849dd01 fix pre-commit 2026-07-27 15:39:18 -04:00
Mayukha Vadari
a1ac0a31de fix changelog 2026-07-21 18:41:28 -04:00
Mayukha Vadari
1368a1cdf1 fix clang-tidy 2026-07-21 18:40:38 -04:00
Mayukha Vadari
91724750fb fix build issues 2026-07-21 18:38:48 -04:00
Mayukha Vadari
8febef6777 Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-07-21 17:59:01 -04:00
copilot-swe-agent[bot]
3bc338211a Merge develop and resolve conflicts
- Updated Json::Value to json::Value (lowercase namespace)
- Updated safe_cast to safeCast
- Updated constant naming (e.g., defaultAutoFillFeeMultiplier to kDefaultAutoFillFeeMultiplier)
- Merged testAugmentedFields with testFailHardValidation in Submit_test.cpp
- Updated namespace from xrpl to xrpl::test for test files
- Updated beast::unit_test::suite to beast::unit_test::Suite

Co-authored-by: mvadari <8029314+mvadari@users.noreply.github.com>
2026-05-15 17:50:26 +00:00
Mayukha Vadari
1b05dba80b fix pre-commit issues 2026-04-03 11:00:23 -04:00
Mayukha Vadari
3595ad0928 fix issues 2026-04-03 10:56:04 -04:00
copilot-swe-agent[bot]
0af23e1466 Extract helper function to avoid code duplication and update API-CHANGELOG
Co-authored-by: mvadari <8029314+mvadari@users.noreply.github.com>
2026-04-03 10:55:42 -04:00
copilot-swe-agent[bot]
cfcf1d30e2 Fix includes in Submit_test.cpp
Co-authored-by: mvadari <8029314+mvadari@users.noreply.github.com>
2026-04-03 10:54:51 -04:00
copilot-swe-agent[bot]
6f8618b2f2 Fix test to properly construct transaction JSON for sign-and-submit
Co-authored-by: mvadari <8029314+mvadari@users.noreply.github.com>
2026-04-03 10:54:51 -04:00
copilot-swe-agent[bot]
361f3469b8 Add augmented fields to sign-and-submit mode and create test
Co-authored-by: mvadari <8029314+mvadari@users.noreply.github.com>
2026-04-03 10:54:51 -04:00
295 changed files with 11089 additions and 20251 deletions

View File

@@ -1,32 +1,10 @@
codecov:
require_ci_to_pass: true
# The C++ and Rust uploads land minutes apart; without this gate Codecov
# publishes a near-zero total from whichever one arrives first.
notify:
after_n_builds: 2
wait_for_ci: true
comment:
behavior: default
layout: reach,diff,flags,tree,reach
show_carryforward_flags: true
after_n_builds: 2
# C++ and Rust coverage upload from independent workflows under the `cpp` and
# `rust` flags; carryforward keeps one language's total when only the other reran.
flag_management:
default_rules:
carryforward: true
individual_flags:
- name: cpp
carryforward: true
paths:
- include/
- src/
- name: rust
carryforward: true
paths:
- crates/
show_carryforward_flags: false
coverage:
range: "70..85"

View File

@@ -69,7 +69,6 @@ words:
- Buildx
- canonicality
- canonicalised
- cctools
- changespq
- checkme
- choco
@@ -111,7 +110,6 @@ words:
- disablerepo
- distro
- doxyfile
- dsymutil
- dxrpl
- elgamal
- enabled
@@ -170,7 +168,6 @@ words:
- LOCALGOOD
- logwstream
- Lombrozo
- lresolv
- lseq
- lsmf
- ltype
@@ -224,7 +221,6 @@ words:
- Nyffenegger
- onlatest
- ostr
- otool
- oxalica
- pargs
- partitioner
@@ -254,15 +250,11 @@ words:
- Raphson
- rcflags
- replayer
- repodata
- repomd
- rerandomize
- rerandomization
- rerandomized
- rerandomizes
- rerere
- retargeted
- retargets
- retriable
- RIPD
- ripdtop
@@ -298,7 +290,6 @@ words:
- sles
- soci
- socidb
- Sonatype
- sponsee
- sponsees
- SRPMS
@@ -318,7 +309,6 @@ words:
- summands
- superpeer
- superpeers
- Swatinem
- takergets
- takerpays
- ters
@@ -374,7 +364,6 @@ words:
- wthread
- xbridge
- xchain
- xcrun
- ximinez
- XMACRO
- xored
@@ -384,5 +373,4 @@ words:
- xrplf
- xxhash
- xxhasher
- zstdio
- CGNAT

View File

@@ -1,39 +0,0 @@
name: Use cargo artifacts cache
description: >
Cache the cargo build artifacts with rust-cache. Never caches ~/.cargo/bin:
when saving the cache, rust-cache deletes all binaries that were already
present there, which on persistent self-hosted runners wipes the tools
installed by prepare-runner. Harmless on ephemeral runners, but kept
consistent everywhere.
inputs:
workspaces:
description: "Workspaces to cache, as 'workspace -> target' lines."
required: false
default: crates
key:
description: "Additional part of the cache key."
required: false
default: ""
cache-directories:
description: "Additional non-workspace directories to cache."
required: false
default: ""
save-if:
description: >
Condition for saving the cache after the job. Defaults to save only from develop branch
required: false
default: ${{ github.ref == 'refs/heads/develop' }}
runs:
using: composite
steps:
- name: Use cargo artifacts cache
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
cache-bin: "false"
cache-directories: ${{ inputs.cache-directories }}
key: ${{ inputs.key }}
save-if: ${{ inputs.save-if }}
workspaces: ${{ inputs.workspaces }}

View File

@@ -0,0 +1,44 @@
name: Generate build version number
description: "Generate build version number."
outputs:
version:
description: "The generated build version number."
value: ${{ steps.version.outputs.version }}
runs:
using: composite
steps:
# When a tag is pushed, the version is used as-is.
- name: Generate version for tag event
if: ${{ startsWith(github.ref, 'refs/tags/') }}
shell: bash
env:
VERSION: ${{ github.ref_name }}
run: echo "VERSION=${VERSION}" >>"${GITHUB_ENV}"
# When a tag is not pushed, then the version (e.g. 1.2.3-b0) is extracted
# from the BuildInfo.cpp file and the shortened commit hash appended to it.
# We use a plus sign instead of a hyphen because Conan recipe versions do
# not support two hyphens.
- name: Generate version for non-tag event
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
shell: bash
run: |
echo 'Extracting version from BuildInfo.cpp.'
VERSION="$(cat src/libxrpl/protocol/BuildInfo.cpp | grep "versionString =" | awk -F '"' '{print $2}')"
if [[ -z "${VERSION}" ]]; then
echo 'Unable to extract version from BuildInfo.cpp.'
exit 1
fi
echo 'Appending shortened commit hash to version.'
SHA='${{ github.sha }}'
VERSION="${VERSION}+${SHA:0:7}"
echo "VERSION=${VERSION}" >>"${GITHUB_ENV}"
- name: Output version
id: version
shell: bash
run: echo "version=${VERSION}" >>"${GITHUB_OUTPUT}"

View File

@@ -1,90 +0,0 @@
name: Release info
description: "Derive the version, release channel and package release number for this build."
outputs:
version:
description: "The build version number."
value: ${{ steps.version.outputs.version }}
channel:
description: "The release channel this build belongs to."
value: ${{ steps.channel.outputs.channel }}
pkg_release:
description: "The package release number: 1 for a tag, the run number otherwise."
value: ${{ steps.pkg_release.outputs.pkg_release }}
runs:
using: composite
steps:
# A tag names its own version. Anything else takes it from BuildInfo.cpp and
# appends the commit hash as build metadata, joined with a plus sign because a
# Conan version cannot contain two hyphens.
- name: Determine version
id: version
shell: bash
env:
IS_TAG: ${{ startsWith(github.ref, 'refs/tags/') }}
REF_NAME: ${{ github.ref_name }}
SHA: ${{ github.sha }}
run: |
if [[ "${IS_TAG}" == "true" ]]; then
version="${REF_NAME}"
else
version="$(awk -F'"' '/versionString =/ { print $2 }' src/libxrpl/protocol/BuildInfo.cpp)"
if [[ -z "${version}" ]]; then
echo "Unable to read versionString from BuildInfo.cpp." >&2
exit 1
fi
version="${version}+${SHA:0:7}"
fi
echo "version=${version}" | tee -a "${GITHUB_OUTPUT}"
# Only a tag says how mature a build is: a push is a develop build whatever
# its version, and a non-public codebase keeps its packages to itself.
- name: Determine release channel
id: channel
shell: bash
env:
IS_TAG: ${{ startsWith(github.ref, 'refs/tags/') }}
REF_NAME: ${{ github.ref_name }}
VISIBILITY: ${{ github.event.repository.visibility }}
run: |
pre_release=""
if [[ "${REF_NAME}" == *-* ]]; then
pre_release="${REF_NAME#*-}"
fi
if [[ "${VISIBILITY}" != "public" ]]; then
channel=private
elif [[ "${IS_TAG}" != "true" ]]; then
channel=develop
elif [[ -z "${pre_release}" ]]; then
channel=stable
elif [[ "${pre_release}" =~ ^rc[0-9]+(\+.*)?$ ]]; then
channel=unstable
elif [[ "${pre_release}" =~ ^b(0|[1-9][0-9]*)(\+.*)?$ ]]; then
channel=experimental
else
echo "Unsupported pre-release in tag '${REF_NAME}'. Use bN or rcN." >&2
exit 1
fi
echo "channel=${channel}" | tee -a "${GITHUB_OUTPUT}"
# A tag is packaged once, so its release number is fixed at 1. Develop builds
# repeat the same version, so the run number is what makes each push an
# upgrade rather than a reinstall.
- name: Determine package release
id: pkg_release
shell: bash
env:
IS_TAG: ${{ startsWith(github.ref, 'refs/tags/') }}
RUN_NUMBER: ${{ github.run_number }}
run: |
if [[ "${IS_TAG}" == "true" ]]; then
pkg_release=1
else
pkg_release="${RUN_NUMBER}"
fi
echo "pkg_release=${pkg_release}" | tee -a "${GITHUB_OUTPUT}"

View File

@@ -1,69 +0,0 @@
name: Setup Nix environment
description: "Build the flake's CI environment and put its tools on PATH."
# The environment from nix/ci-env.nix, the same one the Linux CI images bake in
# (see nix/docker). Exported onto PATH rather than entered with `nix develop`:
# the composite actions below run plain `bash` and would escape a dev shell.
runs:
using: composite
steps:
- name: Build the CI environment
id: build
shell: bash
env:
# --out-link doubles as a GC root for the length of the job.
OUT_LINK: ${{ runner.temp }}/xrpld-ci-env
run: |
# --extra-experimental-features: flakes may not be on in the runner's nix.conf.
nix --extra-experimental-features "nix-command flakes" \
build .#default --out-link "${OUT_LINK}" --print-build-logs
echo "path=$(readlink -f "${OUT_LINK}")" >>"${GITHUB_OUTPUT}"
- name: Export the environment
shell: bash
env:
ENV_PATH: ${{ steps.build.outputs.path }}
run: |
echo "${ENV_PATH}/bin" >>"${GITHUB_PATH}"
# Already KEY=VALUE per line. See `darwinEnv` in nix/ci-env.nix.
ENV_FILE="${ENV_PATH}/share/xrpld-ci-env/env"
if [ -f "${ENV_FILE}" ]; then
cat "${ENV_FILE}" >>"${GITHUB_ENV}"
fi
# XrplSanity.cmake otherwise rejects a Nix compiler as one that leaked.
echo "XRPL_DEVSHELL=ci-env" >>"${GITHUB_ENV}"
# Unlike the Linux nix images, macOS needs no SSL_CERT_FILE: it has its
# own trust store, and pinning would break TLS to hosts relying on it.
# Workspace-local, so `cleanup-workspace` clears it, but not the
# `.conan2` prepare-runner hands the system toolchain: that Conan is a
# different version, and the two would migrate each other's cache.
echo "CONAN_HOME=${{ github.workspace }}/.conan2-nix" >>"${GITHUB_ENV}"
# Config, profiles and remote, exactly as the dev shell sets them up on
# entry; the `setup-conan` action is skipped for this toolchain.
- name: Setup Conan
shell: bash
run: ./conan/init.sh
# `Check tools` runs later but swallows failures; a bad export would just
# build with the system toolchain.
- name: Verify the toolchain resolves into the Nix store
shell: bash
run: |
for tool in clang clang++ cmake ninja conan; do
path="$(command -v "${tool}" || true)"
echo "${tool} -> ${path:-<not found>}"
case "${path}" in
/nix/store/*) ;;
*)
echo "::error::${tool} does not resolve into the Nix store"
exit 1
;;
esac
done

View File

@@ -4,8 +4,7 @@ updates:
directories:
- /
- .github/actions/build-deps/
- .github/actions/cargo-cache/
- .github/actions/release-info/
- .github/actions/generate-version/
- .github/actions/set-compiler-env/
- .github/actions/setup-conan/
schedule:
@@ -20,19 +19,3 @@ updates:
github-actions:
patterns:
- "*"
- package-ecosystem: cargo
directory: /crates
schedule:
interval: weekly
day: monday
time: "04:00"
timezone: Etc/GMT
commit-message:
prefix: "chore: [DEPENDABOT] "
target-branch: develop
open-pull-requests-limit: 10
groups:
rust-dependencies:
patterns:
- "*"

View File

@@ -49,7 +49,7 @@ ${SED_COMMAND} -i -E 's@ripple/xrpld@XRPLF/rippled@g' BUILD.md
${SED_COMMAND} -i -E 's@XRPLF/xrpld@XRPLF/rippled@g' BUILD.md
${SED_COMMAND} -i -E 's@xrpld \(`xrpld`\)@xrpld@g' BUILD.md
${SED_COMMAND} -i -E 's@XRPLF/xrpld@XRPLF/rippled@g' CONTRIBUTING.md
${SED_COMMAND} -i -E 's@XRPLF/xrpld@XRPLF/rippled@g' docs/install.md
${SED_COMMAND} -i -E 's@XRPLF/xrpld@XRPLF/rippled@g' docs/build/install.md
popd
echo "Processing complete."

View File

@@ -77,8 +77,8 @@ ${SED_COMMAND} -i 's/Ripple integrators/XRPL developers/' README.md
${SED_COMMAND} -i 's/sanitizer-configuration-for-rippled/sanitizer-configuration-for-xrpld/' docs/build/sanitizers.md
${SED_COMMAND} -i 's/rippled/xrpld/g' .github/scripts/levelization/README.md
${SED_COMMAND} -i 's/rippled/xrpld/g' .github/scripts/strategy-matrix/generate.py
${SED_COMMAND} -i 's@/rippled@/xrpld@g' docs/install.md
${SED_COMMAND} -i 's@github.com/XRPLF/xrpld@github.com/XRPLF/rippled@g' docs/install.md
${SED_COMMAND} -i 's@/rippled@/xrpld@g' docs/build/install.md
${SED_COMMAND} -i 's@github.com/XRPLF/xrpld@github.com/XRPLF/rippled@g' docs/build/install.md
${SED_COMMAND} -i 's/rippled/xrpld/g' docs/Doxyfile
${SED_COMMAND} -i 's/ripple_basics/basics/' include/xrpl/basics/CountedObject.h
${SED_COMMAND} -i 's/<ripple/<xrpl/' include/xrpl/protocol/AccountID.h

View File

@@ -7,13 +7,7 @@ from pathlib import Path
THIS_DIR = Path(__file__).parent.resolve()
_BASE_CMAKE_ARGS = [
"-Dtests=ON",
"-Dwerr=ON",
"-Dxrpld=ON",
"-Dwextra=ON",
"-Drust=ON",
]
_BASE_CMAKE_ARGS = ["-Dtests=ON", "-Dwerr=ON", "-Dxrpld=ON", "-Dwextra=ON"]
# Maps sanitizer names (as used in cmake) to short config-name suffixes.
_SANITIZER_SUFFIX: dict[str, str] = {
@@ -94,9 +88,6 @@ class PlatformConfig:
build_only: bool = False # if true, skip tests (e.g. macos/Windows Debug)
benchmark: bool = False # if true, smoke-run the benchmarks after testing
extra_cmake_args: str = ""
# "" is the runner's system compiler, "nix" the flake's CI environment.
# macOS only: Linux always builds in a Nix image, Windows has no Nix.
toolchain: str = ""
def __post_init__(self) -> None:
if isinstance(self.build_type, str):
@@ -146,7 +137,6 @@ class MatrixEntry:
sanitizers: str
image: str = "" # container image; empty for macOS/Windows (runs natively)
compiler: str = "" # compiler name ("gcc" or "clang"); empty for macOS/Windows
toolchain: str = "" # "nix" for the flake's CI environment; see PlatformConfig
@dataclasses.dataclass
@@ -225,7 +215,7 @@ def expand_linux_matrix(linux: LinuxFile, minimal: bool) -> list[MatrixEntry]:
def expand_linux_packaging(linux: LinuxFile) -> list[PackagingEntry]:
"""Generate the packaging matrix from a LinuxFile's package_configs section.
Packaging uses vanilla distro images (debian:bookworm, almalinux:9) instead of
Packaging uses vanilla distro images (debian:bookworm, ubi9, …) instead of
the nix-based build images, because deb/rpm tooling (debhelper, rpm-build)
is taken from the distro's archive rather than from nixpkgs. Each config
entry carries its own 'image'.
@@ -263,12 +253,9 @@ def expand_platform_matrix(pf: PlatformFile, minimal: bool) -> list[MatrixEntry]
if minimal and not cfg.minimal:
continue
for build_type in cfg.build_type:
name = f"{platform_name}-{arch}-{build_type.lower()}"
if cfg.toolchain:
name += f"-{cfg.toolchain}"
entries.append(
MatrixEntry(
config_name=name,
config_name=f"{platform_name}-{arch}-{build_type.lower()}",
cmake_args=get_cmake_args(build_type, cfg.extra_cmake_args),
cmake_target="install" if is_windows else "all",
build_only=cfg.build_only,
@@ -276,7 +263,6 @@ def expand_platform_matrix(pf: PlatformFile, minimal: bool) -> list[MatrixEntry]
build_type=build_type,
architecture=Architecture(platform=pf.platform, runner=pf.runner),
sanitizers="",
toolchain=cfg.toolchain,
)
)
return entries

View File

@@ -92,7 +92,7 @@
"build_type": ["Release"],
"arch": ["amd64"],
"minimal": false,
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-a6983f8"
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-577d745"
}
],
@@ -102,7 +102,7 @@
"build_type": ["Release"],
"arch": ["amd64"],
"minimal": false,
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-a6983f8"
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-577d745"
}
]
}

View File

@@ -12,19 +12,6 @@
"extra_cmake_args": "-DCMAKE_POLICY_VERSION_MINIMUM=3.5",
"build_only": true,
"minimal": false
},
{
"build_type": "Release",
"extra_cmake_args": "-DCMAKE_POLICY_VERSION_MINIMUM=3.5",
"toolchain": "nix",
"minimal": false
},
{
"build_type": "Debug",
"extra_cmake_args": "-DCMAKE_POLICY_VERSION_MINIMUM=3.5",
"toolchain": "nix",
"build_only": true,
"minimal": false
}
]
}

View File

@@ -58,7 +58,7 @@ jobs:
base_image: debian:bookworm
- name: rhel
base_image: registry.access.redhat.com/ubi9/ubi:latest
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@65d5a0bd72be4ecea95cff0673a6e0672ab5243a
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@9e7e4e80af9e684c116b38369add8eea64451f32
with:
image_name: xrpld/nix-${{ matrix.distro.name }}
dockerfile: nix/docker/Dockerfile

View File

@@ -36,10 +36,9 @@ jobs:
distro:
- name: debian
base_image: debian:bookworm
# AlmaLinux rather than UBI9, which does not ship rpm-sign.
- name: rhel
base_image: almalinux:9
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@65d5a0bd72be4ecea95cff0673a6e0672ab5243a
base_image: registry.access.redhat.com/ubi9/ubi:latest
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@9e7e4e80af9e684c116b38369add8eea64451f32
with:
image_name: xrpld/packaging-${{ matrix.distro.name }}
dockerfile: package/Dockerfile

View File

@@ -30,7 +30,7 @@ jobs:
permissions:
contents: read
packages: write
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@65d5a0bd72be4ecea95cff0673a6e0672ab5243a
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@9e7e4e80af9e684c116b38369add8eea64451f32
with:
image_name: xrpld/pre-commit
dockerfile: bin/pre-commit/Dockerfile

View File

@@ -1,80 +0,0 @@
name: Cargo audit
on:
schedule:
# 06:32 UTC every Monday.
- cron: "32 6 * * 1"
push:
branches:
- "develop"
- "release/*"
paths:
- "crates/**/Cargo.toml"
- "crates/Cargo.lock"
- ".github/workflows/cargo-audit.yml"
pull_request:
paths:
- "crates/**/Cargo.toml"
- "crates/Cargo.lock"
- ".github/workflows/cargo-audit.yml"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
working-directory: crates
permissions:
contents: read
jobs:
audit:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-a0074f8
permissions:
contents: read
# Needed to open an issue on scheduled failures.
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Run cargo audit
id: audit
continue-on-error: true
run: |
set -o pipefail
cargo audit | tee /tmp/cargo-audit.txt
- name: Prepare issue body
if: ${{ steps.audit.outcome != 'success' && github.event_name == 'schedule' }}
run: |
{
echo "## \`cargo audit\` found advisories"
echo
echo '```'
cat /tmp/cargo-audit.txt
echo '```'
echo
echo "---"
echo "*This issue was automatically created by the cargo-audit workflow.*"
} >/tmp/cargo-audit-issue.md
- name: Create issue
if: ${{ steps.audit.outcome != 'success' && github.event_name == 'schedule' }}
uses: XRPLF/actions/create-issue@2b8bc36af85b88bca0dd7bfac2e2dc05f94ad712
with:
title: "cargo audit found vulnerabilities"
body_file: /tmp/cargo-audit-issue.md
labels: "Bug,Security"
- name: Fail if advisories were found
if: ${{ steps.audit.outcome != 'success' }}
run: |
echo "cargo audit found advisories!"
cat /tmp/cargo-audit.txt
exit 1

View File

@@ -79,7 +79,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@7bf7ceca5932114abdd0d43493c3c30c5a654e13
uses: XRPLF/actions/prepare-runner@c00c22ada3bd6bcda48fcb0d62fbbab49fec8a0f
with:
enable_ccache: false

View File

@@ -77,28 +77,24 @@ jobs:
# Keep the paths below in sync with those in `on-trigger.yml`.
.github/actions/build-deps/**
.github/actions/release-info/**
.github/actions/generate-version/**
.github/actions/setup-conan/**
.github/actions/setup-nix-env/**
.github/scripts/strategy-matrix/**
.github/workflows/reusable-build-test-config.yml
.github/workflows/reusable-build-test.yml
.github/workflows/reusable-check-autogen.yml
.github/workflows/reusable-clang-tidy.yml
.github/workflows/reusable-package.yml
.github/workflows/reusable-rust.yml
.github/workflows/reusable-strategy-matrix.yml
.github/workflows/reusable-test.yml
.github/workflows/reusable-upload-recipe.yml
.clang-tidy
.codecov.yml
bin/check-nix-store-refs.sh
bin/check-tools.sh
bin/default-loader-path.sh
cfg/**
cmake/**
conan/**
crates/**
external/**
include/**
src/**
@@ -106,9 +102,6 @@ jobs:
CMakeLists.txt
conanfile.py
conan.lock
flake.lock
flake.nix
nix/**
LICENSE.md
package/**
README.md
@@ -175,13 +168,6 @@ jobs:
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
rust:
needs: should-run
if: ${{ needs.should-run.outputs.go == 'true' }}
uses: ./.github/workflows/reusable-rust.yml
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
package:
needs: [should-run, build-test]
# Packaging consumes the debian/rhel release binaries, which are only built
@@ -225,7 +211,6 @@ jobs:
- check-rename
- clang-tidy
- build-test
- rust
- package
- upload-recipe
- notify-clio

View File

@@ -1,9 +1,5 @@
# When a versioned tag is pushed, this workflow:
#
# - uploads the libxrpl recipe to the Conan remote
# - builds and tests the release binaries
# - builds the DEB and RPM packages
# - publishes those packages to the XRPLF package repositories
# This workflow uploads the libxrpl recipe to the Conan remote and builds
# release packages when a versioned tag is pushed.
name: Tag
on:
@@ -28,7 +24,7 @@ jobs:
remote_password: ${{ secrets.NEXUS_REMOTE_PASSWORD }}
build-test:
if: ${{ github.repository_owner == 'XRPLF' }}
if: ${{ github.repository == 'XRPLF/rippled' }}
uses: ./.github/workflows/reusable-build-test.yml
strategy:
fail-fast: true
@@ -41,12 +37,6 @@ jobs:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
package:
if: ${{ github.repository_owner == 'XRPLF' }}
if: ${{ github.repository == 'XRPLF/rippled' }}
needs: build-test
uses: ./.github/workflows/reusable-package.yml
with:
publish: true
secrets:
remote_username: ${{ secrets.NEXUS_REMOTE_USERNAME }}
remote_password: ${{ secrets.NEXUS_REMOTE_PASSWORD }}
signing_key: ${{ secrets.NEXUS_PACKAGES_PRIVATE_KEY }}

View File

@@ -15,28 +15,24 @@ on:
# Keep the paths below in sync with those in `on-pr.yml`.
- ".github/actions/build-deps/**"
- ".github/actions/release-info/**"
- ".github/actions/generate-version/**"
- ".github/actions/setup-conan/**"
- ".github/actions/setup-nix-env/**"
- ".github/scripts/strategy-matrix/**"
- ".github/workflows/reusable-build-test-config.yml"
- ".github/workflows/reusable-build-test.yml"
- ".github/workflows/reusable-check-autogen.yml"
- ".github/workflows/reusable-clang-tidy.yml"
- ".github/workflows/reusable-package.yml"
- ".github/workflows/reusable-rust.yml"
- ".github/workflows/reusable-strategy-matrix.yml"
- ".github/workflows/reusable-test.yml"
- ".github/workflows/reusable-upload-recipe.yml"
- ".clang-tidy"
- ".codecov.yml"
- "bin/check-nix-store-refs.sh"
- "bin/check-tools.sh"
- "bin/default-loader-path.sh"
- "cfg/**"
- "cmake/**"
- "conan/**"
- "crates/**"
- "external/**"
- "include/**"
- "src/**"
@@ -44,9 +40,6 @@ on:
- "CMakeLists.txt"
- "conanfile.py"
- "conan.lock"
- "flake.lock"
- "flake.nix"
- "nix/**"
- "LICENSE.md"
- "package/**"
- "README.md"
@@ -103,11 +96,6 @@ jobs:
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
rust:
uses: ./.github/workflows/reusable-rust.yml
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
upload-recipe:
needs: build-test
# Only run when pushing to the develop branch.
@@ -120,11 +108,3 @@ jobs:
package:
needs: build-test
uses: ./.github/workflows/reusable-package.yml
with:
# Packages are built on every trigger; only develop pushes in XRPLF/rippled
# publish them, matching upload-recipe above.
publish: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' && github.ref == 'refs/heads/develop' }}
secrets:
remote_username: ${{ secrets.NEXUS_REMOTE_USERNAME }}
remote_password: ${{ secrets.NEXUS_REMOTE_PASSWORD }}
signing_key: ${{ secrets.NEXUS_PACKAGES_PRIVATE_KEY }}

View File

@@ -14,7 +14,7 @@ on:
jobs:
# Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks.
run-hooks:
uses: XRPLF/actions/.github/workflows/pre-commit.yml@f1952595d212e86169935135efc66294b4574131
uses: XRPLF/actions/.github/workflows/pre-commit.yml@3ba08d6ddf114092891d48491fc2e26c3ba15552
with:
runs_on: ubuntu-latest
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-f56b79f" }'

View File

@@ -47,7 +47,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@7bf7ceca5932114abdd0d43493c3c30c5a654e13
uses: XRPLF/actions/prepare-runner@c00c22ada3bd6bcda48fcb0d62fbbab49fec8a0f
with:
enable_ccache: false

View File

@@ -69,12 +69,6 @@ on:
type: string
default: ""
toolchain:
description: 'Where the toolchain comes from ("nix" to build the flake CI environment on the runner, empty for the system one). macOS only: Linux always builds in a Nix image, and Nix has no Windows support.'
required: false
type: string
default: ""
secrets:
CODECOV_TOKEN:
description: "The Codecov token to use for uploading coverage reports."
@@ -117,9 +111,6 @@ jobs:
VOIDSTAR_ENABLED: ${{ contains(inputs.cmake_args, '-Dvoidstar=ON') }}
VALIDATOR_KEYS_ENABLED: ${{ contains(inputs.cmake_args, '-Dvalidator_keys=ON') }}
SANITIZERS_ENABLED: ${{ inputs.sanitizers != '' }}
# The binaries reusable-package.yml consumes. A private repository skips
# them except on a tag push, which is what produces its release packages.
PACKAGING_ARTIFACTS_ENABLED: ${{ github.event.repository.visibility == 'public' || startsWith(github.ref, 'refs/tags/') }}
steps:
- name: Cleanup workspace (macOS and Windows)
if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }}
@@ -129,15 +120,10 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@7bf7ceca5932114abdd0d43493c3c30c5a654e13
uses: XRPLF/actions/prepare-runner@c00c22ada3bd6bcda48fcb0d62fbbab49fec8a0f
with:
enable_ccache: ${{ inputs.ccache_enabled }}
# Before any step that uses a build tool, composite actions included.
- name: Setup Nix environment
if: ${{ inputs.toolchain == 'nix' }}
uses: ./.github/actions/setup-nix-env
- name: Set ccache log file
if: ${{ inputs.ccache_enabled && runner.debug == '1' }}
run: echo "CCACHE_LOGFILE=${{ runner.temp }}/ccache.log" >>"${GITHUB_ENV}"
@@ -162,21 +148,7 @@ jobs:
with:
compiler: ${{ inputs.compiler }}
- name: Use cargo artifacts cache
uses: ./.github/actions/cargo-cache
with:
cache-directories: ${{ env.BUILD_DIR }}/corrosion
key: ${{ inputs.config_name }}
# two workspaces here because build artifacts are located in 2 places:
# - crates/target when cargo is called directly
# - build/cargo when cargo is called by cmake
workspaces: |
crates
crates -> ${{ runner.os == 'Windows' && format('../{0}/x64/{1}/cargo', env.BUILD_DIR, inputs.build_type) || format('../{0}/cargo', env.BUILD_DIR) }}
# `setup-nix-env` already did this for the Nix toolchain.
- name: Setup Conan
if: ${{ inputs.toolchain != 'nix' }}
env:
SANITIZERS: ${{ inputs.sanitizers }}
uses: ./.github/actions/setup-conan
@@ -240,24 +212,6 @@ jobs:
--target "${CMAKE_TARGET}" \
2>&1 | tee "${GITHUB_WORKSPACE}/build.log"
# Nothing may reference the store, so whole trees are checked - the Conan
# cache included, since what it holds is what gets uploaded and reused.
- name: Check the build output for Nix store references (Nix toolchain)
if: ${{ inputs.toolchain == 'nix' }}
run: ./bin/check-nix-store-refs.sh "${BUILD_DIR}"
- name: Check the Conan cache for Nix store references (Nix toolchain)
if: ${{ inputs.toolchain == 'nix' }}
run: ./bin/check-nix-store-refs.sh "${CONAN_HOME}"
# Only what PatchNixBinary.cmake retargets: the toolchain in the Linux
# images always references the store. Same condition it uses.
- name: Check for Nix store references (Linux)
if: ${{ runner.os == 'Linux' && env.SANITIZERS_ENABLED == 'false' }}
run: |
./bin/check-nix-store-refs.sh "${BUILD_DIR}/xrpld"
./bin/check-nix-store-refs.sh "${BUILD_DIR}/xrpl_tests"
- name: Show ccache statistics
if: ${{ inputs.ccache_enabled }}
run: |
@@ -268,7 +222,7 @@ jobs:
fi
- name: Upload the binary (Linux)
if: ${{ env.PACKAGING_ARTIFACTS_ENABLED == 'true' && runner.os == 'Linux' }}
if: ${{ github.event.repository.visibility == 'public' && runner.os == 'Linux' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: xrpld-${{ inputs.config_name }}
@@ -282,7 +236,7 @@ jobs:
run: ./validator-keys --unittest
- name: Upload the validator-keys binary
if: ${{ env.PACKAGING_ARTIFACTS_ENABLED == 'true' && env.VALIDATOR_KEYS_ENABLED == 'true' }}
if: ${{ github.event.repository.visibility == 'public' && env.VALIDATOR_KEYS_ENABLED == 'true' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: validator-keys-${{ inputs.config_name }}
@@ -369,11 +323,6 @@ jobs:
LD_PRELOAD="$PRELOAD" ./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee "${GITHUB_WORKSPACE}/unittest.log"
- name: Run Rust tests
if: ${{ !inputs.build_only }}
working-directory: crates
run: cargo nextest run --workspace --all-features --locked --no-tests=warn
# Smoke-run every benchmark module with a single repetition to confirm the
# benchmarks still build and execute. This is a correctness check, not a
# performance measurement, so there is nothing to gain from repeating it
@@ -445,7 +394,6 @@ jobs:
disable_telem: true
fail_ci_if_error: true
files: ${{ env.BUILD_DIR }}/coverage.xml
flags: cpp
plugins: noop
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true

View File

@@ -51,6 +51,5 @@ jobs:
config_name: ${{ matrix.config_name }}
sanitizers: ${{ matrix.sanitizers }}
compiler: ${{ matrix.compiler || '' }}
toolchain: ${{ matrix.toolchain || '' }}
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

View File

@@ -27,7 +27,7 @@ jobs:
determine-files:
permissions:
contents: read
uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@70145243b905dc3e040a61d39c00e178cfb96f71
uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@d041ac9f1fa9f07a4ba335eb4c1c82233fb3fef6
run-clang-tidy:
name: Run clang tidy
@@ -43,7 +43,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@7bf7ceca5932114abdd0d43493c3c30c5a654e13
uses: XRPLF/actions/prepare-runner@c00c22ada3bd6bcda48fcb0d62fbbab49fec8a0f
with:
enable_ccache: false
@@ -59,12 +59,6 @@ jobs:
with:
compiler: ${{ env.COMPILER }}
- name: Use cargo artifacts cache
uses: ./.github/actions/cargo-cache
with:
cache-directories: ${{ env.BUILD_DIR }}/corrosion
workspaces: crates -> ../${{ env.BUILD_DIR }}/cargo
- name: Setup Conan
uses: ./.github/actions/setup-conan
@@ -86,13 +80,13 @@ jobs:
-Dwerr=ON \
-Dxrpld=ON \
-Dverify_headers=ON \
-Drust=ON \
..
- name: Build clang-tidy prerequisites
# clang-tidy needs headers generated from proto files
- name: Build libxrpl.libpb
working-directory: ${{ env.BUILD_DIR }}
run: |
ninja -j ${{ steps.nproc.outputs.nproc }} tidy_prerequisites
ninja -j ${{ steps.nproc.outputs.nproc }} xrpl.libpb
- name: Run clang tidy
id: run_clang_tidy

View File

@@ -1,37 +1,17 @@
# Build Linux packages from the pre-built xrpld and validator-keys artifacts:
#
# - one job per distro, taken from "package_configs" in linux.json
# - each job runs in that distro's container, which is what decides DEB or RPM
# - with 'publish: true' a job also uploads what it built
# (see package/publish_pkg.sh)
#
# Only linux/amd64 is supported; the runner is hardcoded in the job below.
# Build Linux packages (DEB and RPM) from pre-built binary artifacts (xrpld and
# validator-keys). Discovers which configurations to package from linux.json
# (configs in "package_configs") and fans out one job per distro. Only
# linux/amd64 is supported; the runner is hardcoded in the job below.
name: Package
on:
workflow_call:
inputs:
publish:
description: "Whether to publish the packages after building them."
required: false
type: boolean
default: false
nexus_url:
description: "The base URL of the Nexus instance hosting the deb and rpm repositories."
pkg_release:
description: "Package release number. Increment when repackaging the same executable."
required: false
type: string
default: https://packages.xrplf.org
secrets:
remote_username:
description: "The username of a Nexus account with write access to the repositories."
required: false
remote_password:
description: "The password or token for that Nexus account."
required: false
signing_key:
description: "Armoured PGP private key used to sign the RPMs. Required when publishing."
required: false
default: "1"
defaults:
run:
@@ -61,7 +41,7 @@ jobs:
package:
needs: [generate-matrix]
if: ${{ github.event.repository.visibility == 'public' || startsWith(github.ref, 'refs/tags/') }}
if: ${{ github.event.repository.visibility == 'public' }}
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
@@ -91,24 +71,11 @@ jobs:
- name: Make binaries executable
run: chmod +x "${BUILD_DIR}/xrpld" "${BUILD_DIR}/validator-keys"
- name: Determine release info
id: release_info
uses: ./.github/actions/release-info
- name: Build package
env:
PKG_RELEASE: ${{ steps.release_info.outputs.pkg_release }}
PKG_CHANNEL: ${{ steps.release_info.outputs.channel }}
PKG_RELEASE: ${{ inputs.pkg_release }}
run: ./package/build_pkg.sh
# Before the upload, so the artifact and the published package are the
# same bytes. DEBs are not signed, so the key is never set on that job.
- name: Sign RPM
if: ${{ inputs.publish && matrix.distro == 'rhel' }}
env:
PKG_SIGNING_KEY: ${{ secrets.signing_key }}
run: ./package/sign_rpm.sh "${BUILD_DIR}"
- name: Upload package artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
@@ -118,12 +85,3 @@ jobs:
${{ env.BUILD_DIR }}/debbuild/*.ddeb
${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/*.rpm
if-no-files-found: error
- name: Publish package
if: ${{ inputs.publish }}
env:
CHANNEL: ${{ steps.release_info.outputs.channel }}
NEXUS_URL: ${{ inputs.nexus_url }}
NEXUS_USERNAME: ${{ secrets.remote_username }}
NEXUS_PASSWORD: ${{ secrets.remote_password }}
run: ./package/publish_pkg.sh "${CHANNEL}" "${BUILD_DIR}"

View File

@@ -1,80 +0,0 @@
# Clippy, coverage and documentation for the Rust crates in crates/. Each runs
# as an independent job on a GitHub-hosted runner, but inside the same container
# image used to build the crates in the C++/Corrosion path, so the toolchain
# (and therefore the lints, coverage instrumentation and the cargo cache) matches
# what production builds use.
#
# Rust unit tests are deliberately NOT run here. They run as part of the C++
# build (reusable-build-test-config.yml), which already compiles the crates on a
# self-hosted runner, so there is no need to provision a toolchain again.
name: Rust
on:
workflow_call:
secrets:
CODECOV_TOKEN:
description: "The Codecov token to use for uploading coverage reports."
required: true
defaults:
run:
shell: bash
working-directory: crates
permissions:
contents: read
jobs:
clippy:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-a0074f8
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Use cargo artifacts cache
uses: ./.github/actions/cargo-cache
- name: Run clippy
run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
coverage:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-a0074f8
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Use cargo artifacts cache
uses: ./.github/actions/cargo-cache
- name: Generate coverage report
run: cargo llvm-cov nextest --workspace --all-features --locked --no-tests=warn --lcov --output-path lcov.info
- name: Upload coverage report
if: ${{ github.repository == 'XRPLF/rippled' }}
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
disable_search: true
disable_telem: true
fail_ci_if_error: true
files: crates/lcov.info
flags: rust
plugins: noop
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true
doc:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-a0074f8
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Use cargo artifacts cache
uses: ./.github/actions/cargo-cache
- name: Build documentation
env:
RUSTDOCFLAGS: "-D warnings"
run: cargo doc --workspace --no-deps --all-features --locked

View File

@@ -49,9 +49,9 @@ jobs:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Determine release info
id: release_info
uses: ./.github/actions/release-info
- name: Generate build version number
id: version
uses: ./.github/actions/generate-version
- name: Set up Conan
uses: ./.github/actions/setup-conan
@@ -64,8 +64,8 @@ jobs:
- name: Upload Conan recipe (version)
run: |
conan export . --version=${{ steps.release_info.outputs.version }}
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/${{ steps.release_info.outputs.version }}
conan export . --version=${{ steps.version.outputs.version }}
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/${{ steps.version.outputs.version }}
# When this workflow is triggered by a push event, it will always be when merging into the
# 'develop' branch, see on-trigger.yml.
@@ -92,4 +92,4 @@ jobs:
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/release
outputs:
ref: xrpl/${{ steps.release_info.outputs.version }}
ref: xrpl/${{ steps.version.outputs.version }}

View File

@@ -68,15 +68,10 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@7bf7ceca5932114abdd0d43493c3c30c5a654e13
uses: XRPLF/actions/prepare-runner@c00c22ada3bd6bcda48fcb0d62fbbab49fec8a0f
with:
enable_ccache: false
# Before any step that uses a build tool, composite actions included.
- name: Setup Nix environment
if: ${{ matrix.toolchain == 'nix' }}
uses: ./.github/actions/setup-nix-env
- name: Print build environment
uses: XRPLF/actions/print-build-env@59dec886e4afb05a1724443af08baccbc045b574
@@ -92,9 +87,7 @@ jobs:
with:
compiler: ${{ matrix.compiler }}
# `setup-nix-env` already did this for the Nix toolchain.
- name: Setup Conan
if: ${{ matrix.toolchain != 'nix' }}
env:
SANITIZERS: ${{ matrix.sanitizers }}
uses: ./.github/actions/setup-conan
@@ -113,10 +106,6 @@ jobs:
log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }}
sanitizers: ${{ matrix.sanitizers }}
- name: Check the Conan cache for Nix store references (Nix toolchain)
if: ${{ matrix.toolchain == 'nix' }}
run: ./bin/check-nix-store-refs.sh "${CONAN_HOME}"
- name: Log into Conan remote
if: ${{ github.repository == 'XRPLF/rippled' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
run: conan remote login "${CONAN_REMOTE_NAME}" "${{ secrets.NEXUS_REMOTE_USERNAME }}" --password "${{ secrets.NEXUS_REMOTE_PASSWORD }}"

3
.gitignore vendored
View File

@@ -89,6 +89,3 @@ target/
# clangd cache
/.cache
# Rust build directory
crates/target

View File

@@ -62,15 +62,6 @@ repos:
types_or: [c++, c, proto]
exclude: ^include/xrpl/protocol_autogen/(transactions|ledger_entries)/
- repo: local
hooks:
- id: cargo-fmt
name: cargo fmt
entry: cargo fmt --manifest-path crates/Cargo.toml --all
language: system
types: [rust]
pass_filenames: false # rustfmt formats the whole workspace
- repo: https://github.com/BlankSpruce/gersemi-pre-commit
rev: e98930bdc210d3387007f9252d8c1694ea7e410f # frozen: 0.27.7
hooks:

View File

@@ -39,6 +39,7 @@ This section contains changes targeting a future version.
- `TRANSACTION_FLAGS`: Maps transaction type names to their supported flags and flag values.
- `LEDGER_ENTRY_FLAGS`: Maps ledger entry type names to their flags and flag values.
- `ACCOUNT_SET_FLAGS`: Maps AccountSet flag names (asf flags) to their numeric values.
- `submit`: Augmented response fields (`accepted`, `applied`, `broadcast`, `queued`, `kept`, `account_sequence_next`, `account_sequence_available`, `open_ledger_cost`, `validated_ledger_index`) are now included in sign-and-submit mode. Previously, these fields were only returned when submitting a binary transaction blob.
### Bugfixes
@@ -54,9 +55,6 @@ This section contains changes targeting a future version.
- `submit`: The `fail_hard` field now returns an error if the value is not a boolean. [#6529](https://github.com/XRPLF/rippled/pull/6529)
- `subscribe`: The `taker` field in the `books` array now returns `actMalformed` instead of `badIssuer` if the value is not a valid account. [#6529](https://github.com/XRPLF/rippled/pull/6529)
- Fixed a bug in `Forwarded` HTTP header parsing where the extracted IP address could be incorrect when no comma or semicolon delimiter follows the address. This could cause the server to misidentify a client's IP address when operating behind a reverse proxy. [#6529](https://github.com/XRPLF/rippled/pull/6529)
- `vault_info`: Errors now identify what the request got wrong instead of reporting every failure as the unregistered token `malformedRequest`, and the `error`, `error_code` and `error_message` fields now agree with each other. An invalid `vault_id` or `seq` returns `invalidParams`, an invalid `owner` returns `actMalformed`, and a request that mixes `vault_id` with `owner`/`seq` or supplies neither returns `invalidParams` with a message naming the accepted combinations. [#8015](https://github.com/XRPLF/rippled/pull/8015)
- `vault_info`: A well-formed all-zero `vault_id` now returns `entryNotFound` instead of being rejected as malformed, and `entryNotFound` responses now include `error_code` and `error_message`. Clients that request `ripplerpc` 3.0 or above therefore receive HTTP 400 with that error rather than HTTP 200. [#8015](https://github.com/XRPLF/rippled/pull/8015)
- `vault_info`: `vault_id` and `owner` must now be strings, matching how `ledger_entry` reads the same fields. An object or an array in either field previously produced an internal error, and a number was silently converted to its decimal text; `vault_id` now returns `invalidParams` and `owner` returns `actMalformed`. [#8015](https://github.com/XRPLF/rippled/pull/8015)
- `gateway_balances`: The `account` and `ident` fields now return an `invalidParams` error if the value is not a string, instead of an `internal` error. [#7655](https://github.com/XRPLF/rippled/pull/7655)
- `account_lines`: The `peer` field now returns an error if the value is not a string. [#7728](https://github.com/XRPLF/rippled/pull/7728)

View File

@@ -304,7 +304,6 @@ See [Sanitizers docs](./docs/build/sanitizers.md) for more details.
| ---------------- | ------------- | ----------------------------------------------------------------------------- |
| `assert` | OFF | Force enabling assertions. |
| `coverage` | OFF | Prepare the coverage report. |
| `rust` | OFF | Build the Rust crates and the C++ code that depends on them. |
| `tests` | OFF | Build tests. |
| `unity` | OFF | Configure a unity build. |
| `verify_headers` | ON | Make the `verify-headers` target available to compile each header on its own. |
@@ -317,30 +316,6 @@ memory) since they concatenate sources into fewer translation units. Non-unity
builds may be faster for incremental builds, and can be helpful for detecting
`#include` omissions.
### Rust crates
The Rust crates in `crates/` are only part of the build when `rust` is ON. With
`-Drust=OFF` (the default) the `crates` directory is not added to the build, no
cxxbridge bindings are generated, and the C++ tests that exercise the Rust
interop are not compiled — so no Rust toolchain is needed. CI builds always pass
`-Drust=ON`.
With `-Drust=ON` you need one extra dependency: a Rust toolchain (`cargo`,
`rustc`) matching the channel pinned in
[`rust-toolchain.toml`](./rust-toolchain.toml), which compiles the crates and
generates the cxxbridge bindings. It is provided by the
[Nix development shell](./docs/build/nix.md), so `-Drust=ON` works there without
any extra setup; otherwise install it as described in
[Rust](./docs/build/environment.md#rust).
The crates also have their own Rust unit tests. Those are run with `cargo` and
need only the Rust toolchain, independently of CMake and of the `rust` option
(CI runs them with `cargo nextest`):
```bash
cargo test --manifest-path crates/Cargo.toml --workspace
```
### Verifying headers
The regular build only compiles `.cpp` files, so a header is only ever checked

View File

@@ -158,13 +158,7 @@ if(coverage)
include(XrplCov)
endif()
add_custom_target(tidy_prerequisites)
if(rust)
add_subdirectory(crates)
endif()
include(XrplCore)
include(XrplProtocolAutogen)
include(XrplInstall)
include(XrplValidatorKeys)

View File

@@ -225,9 +225,8 @@ environment, so you don't need to install most of the individual tools
yourself. The version of each hook sourced from an external repository
(`clang-format`, `gersemi`, etc.) is pinned in that file, so running the hooks
locally uses exactly the same versions as CI. A few `local` hooks — most notably
`clang-tidy` and `cargo fmt` — run tools from your own environment; see
[Installing clang-tidy](#installing-clang-tidy) and
[Rust](./docs/build/environment.md#rust) for how to get those.
`clang-tidy` — run tools from your own environment; see
[Installing clang-tidy](#installing-clang-tidy) for how to get those.
To get started, install `pre-commit` and enable the git hook scripts:
@@ -256,7 +255,6 @@ The hooks configured in this repository include, among others:
- `clang-tidy` — C++ static analysis (see [Clang-tidy](#clang-tidy)); opt in with `TIDY=1`
- `fix-include-style`, `fix-pragma-once`, `check-doxygen-style` — C++ hygiene
- `gersemi` — CMake formatting
- `cargo fmt` — Rust formatting for the crates in `crates/`
- `prettier`, `black`, `shfmt` — formatting for JavaScript/JSON/Markdown, Python, and shell
- `cspell` — spell checking
@@ -321,11 +319,7 @@ See the [environment setup guide](./docs/build/environment.md#clang-tidy) for ho
### Running clang-tidy locally
Before running clang-tidy, you must generate the files it depends on (protobuf headers, and, when the project is configured with `-Drust=ON`, the cxxbridge headers from the Rust crates). Configure the project as described in [`BUILD.md`](./BUILD.md), then build the `tidy_prerequisites` target, which generates all of them:
```bash
cmake --build build --target tidy_prerequisites
```
Before running clang-tidy, you must build the project to generate required files (particularly protobuf headers). Refer to [`BUILD.md`](./BUILD.md) for build instructions.
#### Via pre-commit (recommended)

View File

@@ -54,7 +54,6 @@ Here are some good places to start learning the source code:
| `./docs` | Source documentation files and doxygen config. |
| `./cfg` | Example configuration files. |
| `./src` | Source code. |
| `./crates` | Rust source code. |
Some of the directories under `src` are external repositories included using
git-subtree. See those directories' README files for more details.

View File

@@ -1,111 +0,0 @@
#!/usr/bin/env bash
# Fail if a binary under <path> records a /nix/store path it resolves at run
# time. See docs/build/nix.md#prebuilt-packages for why that matters.
#
# <path> is a file or a directory. macOS: nothing may reference the store, so
# point it at whole trees. Linux: the toolchain always writes the store into
# PT_INTERP and RUNPATH, so only at what cmake/PatchNixBinary.cmake retargets.
#
# Only Mach-O / ELF is inspected. Static archives hold store paths in debug info
# alone; the scripts in a Conan cache are all git hook samples and autotools
# scratch, 36 false positives to 0 real.
#
# Usage: bin/check-nix-store-refs.sh <path>
set -euo pipefail
if [ "$#" -ne 1 ]; then
echo "usage: $0 <path>" >&2
exit 2
fi
if [ ! -e "$1" ]; then
echo "$0: no such path: $1" >&2
exit 2
fi
case "$(uname -s)" in
Darwin)
format=Mach-O
recorded_paths=macho_recorded_paths
tool=otool
;;
Linux)
format=ELF
recorded_paths=elf_recorded_paths
tool=readelf
;;
*)
echo "Unsupported OS - skipping the Nix store reference check."
exit 0
;;
esac
# `pipefail` would catch this too, but only as a bare nonzero exit.
if ! command -v "${tool}" >/dev/null; then
echo "$0: ${tool} not found; cannot inspect binaries" >&2
exit 2
fi
# Both list what the file records. `ldd` would answer what this machine resolves
# now, which is wrong both ways: store paths for a correctly patched binary,
# silence for a store RUNPATH that resolves nowhere.
# `name` covers LC_ID_DYLIB and LC_LOAD*_DYLIB, `path` covers LC_RPATH.
macho_recorded_paths() {
otool -l "$1" | sed -nE 's#^ *(name|path) ([^ ]*).*#\2#p'
}
# RPATH and RUNPATH are colon-separated.
elf_recorded_paths() {
readelf -ldW "$1" |
sed -nE \
-e 's#.*program interpreter: ([^]]*)\].*#\1#p' \
-e 's#.*\((RPATH|RUNPATH|NEEDED)\).*\[([^]]*)\].*#\2#p' |
tr ':' '\n'
}
checked=0
skipped=0
leaked=0
while IFS= read -r file; do
case "$(file -b "${file}" 2>/dev/null)" in
*"${format}"*) ;;
*)
skipped=$((skipped + 1))
continue
;;
esac
checked=$((checked + 1))
# Filter after extracting, or a search path starting elsewhere ($ORIGIN)
# hides the rest. `sed` not `grep`: grep calls "no matches" a failure, and
# the `|| true` that would need masks a broken pipeline too.
refs="$("${recorded_paths}" "${file}" | sed -n '\#^/nix/store/#p' | sort -u)"
if [ -n "${refs}" ]; then
leaked=$((leaked + 1))
echo "::error file=${file}::references the Nix store at run time"
echo "${file}"
echo "${refs}" | sed 's/^/ /'
fi
done < <(find "$1" -type f \( -perm -u+x -o -name '*.dylib' -o -name '*.so*' \))
echo "$1: checked ${checked}, skipped ${skipped}, ${leaked} with Nix store references."
if [ "${leaked}" -ne 0 ]; then
cat >&2 <<'EOF'
Fixes, in order of preference:
- A Conan package built before this check existed: drop it
(`conan remove '<name>/*'`) and rebuild.
- A binary that should have been retargeted to the system loader: check that
cmake/PatchNixBinary.cmake ran for it.
- Link the macOS system library instead of the Nix one - see
libresolvSystemStub in nix/darwin.nix.
- No system library exists (libstdc++): link it statically.
- None of the above: pin the toolchain into the package ID, following
`user.package:libc_version` in conan/profiles/ci.
EOF
exit 1
fi

View File

@@ -120,10 +120,7 @@ if(MSVC)
_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:Debug>>:_CRTDBG_MAP_ALLOC>
)
target_link_libraries(
common
INTERFACE -errorreport:none -machine:X64 -ignore:4099
)
target_link_libraries(common INTERFACE -errorreport:none -machine:X64)
else()
target_compile_options(
common

View File

@@ -51,8 +51,6 @@ target_compile_options(
target_link_libraries(xrpl.libpb PUBLIC protobuf::libprotobuf gRPC::grpc++)
add_dependencies(tidy_prerequisites xrpl.libpb)
# TODO: Clean up the number of library targets later.
add_library(xrpl.imports.main INTERFACE)

View File

@@ -32,11 +32,6 @@ endif()
option(benchmark "Build benchmarks" ON)
# When OFF, the crates directory is not added to the build at all: no Rust
# toolchain is required, no cxxbridge bindings are generated, and the C++ tests
# that consume those bindings are left out of the build tree.
option(rust "Build the Rust crates and the C++ code that depends on them" OFF)
# Enabled by default so every header is compiled on its own as the main file of
# its own compile_commands.json entry - this is what lets clang-tidy (and clangd
# and IDEs) analyse a header's own includes directly. The per-header objects are

View File

@@ -8,7 +8,6 @@ Uses pcpp to preprocess the macro file and pyparsing to parse the DSL.
import io
import argparse
import re
from pathlib import Path
import pyparsing as pp
@@ -54,89 +53,28 @@ def create_transaction_parser():
return macro_parser
# Defaults for xrpl::TxSettings members, mirroring
# include/xrpl/protocol/TxSettings.h. A transaction's settings blob only names
# the members that differ from these.
SETTING_DEFAULTS = {
"delegable": "Delegation::NotDelegable",
"amendment": "uint256{}",
"privileges": "Privilege::NoPriv",
}
def parse_settings(settings_str):
"""Parse a TxSettings blob into a dict, filling in defaults.
Args:
settings_str: A string like '({.delegable = Delegation::NotDelegable,
.privileges = Privilege::CreateAcct})', or '({})'.
Returns:
A dict with a value for every key in SETTING_DEFAULTS.
"""
body = settings_str.strip()
if not (body.startswith("(") and body.endswith(")")):
raise ValueError(
f"Malformed settings blob, expected '({{...}})': {settings_str!r}"
)
body = body[1:-1].strip()
if not (body.startswith("{") and body.endswith("}")):
raise ValueError(
f"Malformed settings blob, expected '({{...}})': {settings_str!r}"
)
body = body[1:-1]
# Strip comments, which may be interleaved with the designated initializers.
body = re.sub(r"//[^\n]*", "", body)
settings = dict(SETTING_DEFAULTS)
seen = set()
# Each entry runs from '.key =' up to the next '.key =' or the end.
for key, value in re.findall(
r"\.(\w+)\s*=\s*(.*?)(?=,\s*\.\w+\s*=|,?\s*$)", body, re.S
):
if key not in SETTING_DEFAULTS:
raise ValueError(f"Unknown TxSettings member '.{key}' in {settings_str!r}")
settings[key] = " ".join(value.split()).rstrip(",")
seen.add(key)
# Catch a typo'd or unparsed initializer rather than silently defaulting it.
# Every '.member' in the blob must have been consumed above.
if len(re.findall(r"\.\w+", body)) != len(seen):
raise ValueError(f"Could not parse every setting in {settings_str!r}")
# A blob with content but no designated initializer is positional, which
# would otherwise be read as "all defaults" and silently generate the
# wrong output.
if body.strip() and not seen:
raise ValueError(
"TxSettings requires designated initializers (.member = value), "
f"got {settings_str!r}"
)
return settings
def parse_transaction_args(args_list):
"""Parse the arguments of a TRANSACTION macro call.
Args:
args_list: A list of parsed arguments from pyparsing, e.g.,
['ttPAYMENT', '0', 'Payment',
'({.privileges = Privilege::CreateAcct})', '({...})']
['ttPAYMENT', '0', 'Payment', 'Delegation::delegable',
'uint256{}', 'createAcct', '({...})']
Returns:
A dict with parsed transaction information.
"""
if len(args_list) < 5:
if len(args_list) < 7:
raise ValueError(
f"Expected at least 5 parts in TRANSACTION, got {len(args_list)}: {args_list}"
f"Expected at least 7 parts in TRANSACTION, got {len(args_list)}: {args_list}"
)
tag = args_list[0]
value = args_list[1]
name = args_list[2]
settings = parse_settings(args_list[3])
delegable = args_list[3]
amendments = args_list[4]
privileges = args_list[5]
fields_str = args_list[-1]
# Parse fields: ({field1, field2, ...})
@@ -146,9 +84,9 @@ def parse_transaction_args(args_list):
"tag": tag,
"value": value,
"name": name,
"delegable": settings["delegable"],
"amendments": settings["amendment"],
"privileges": settings["privileges"],
"delegable": delegable,
"amendments": amendments,
"privileges": privileges,
"fields": fields,
}

View File

@@ -23,7 +23,6 @@
"fast_float/8.2.10#f6f28d6bb22112078e7dbda611caf681%1782494504.298",
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1782307148.15562",
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1782392402.538492",
"corrosion/0.6.1#bfa292df0a957bc70a450ff316cd9435%1786119416.131296",
"c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1782392402.681654",
"bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1782392402.296732",
"boost/1.91.0#ea540ca2133d831b560036aa24dece3c%1782392419.475605",

View File

@@ -28,7 +28,6 @@ class Xrpl(ConanFile):
}
requires = [
"corrosion/0.6.1",
"ed25519/2015.03",
"fast_float/8.2.10",
"grpc/1.81.1",

View File

@@ -1,17 +0,0 @@
# The Rust static libraries are linked into C++ targets, so the runtime linkage
# here has to match what the C++ build uses (see cmake/XrplCompiler.cmake).
#
# macOS needs nothing: AppleClang cannot link libgcc/libc++ statically, so the
# C++ build skips those flags on Apple as well.
# Both amd64 and arm64 Linux builds link libgcc statically. This only affects
# links that rustc itself drives (`cargo test` binaries and the like) — the
# `staticlib` crates consumed by CMake are archived, not linked, so rustc
# silently ignores link args for them. Keeping libgcc_s.so.1 off the xrpld link
# line is handled in crates/CMakeLists.txt instead.
[target.'cfg(target_os = "linux")']
rustflags = ["-C", "link-args=-static-libgcc"]
# Windows builds use the static MSVC runtime.
[target.'cfg(windows)']
rustflags = ["-C", "target-feature=+crt-static"]

View File

@@ -1,104 +0,0 @@
find_package(Corrosion REQUIRED)
corrosion_import_crate(MANIFEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Cargo.toml)
# The generated C++ lands in the build tree, so put a .clang-tidy next to it to
# keep clang-tidy from analyzing code we don't own.
configure_file(
generated.clang-tidy
"${CMAKE_CURRENT_BINARY_DIR}/.clang-tidy"
COPYONLY
)
add_custom_target(xrpl_crates)
add_dependencies(tidy_prerequisites xrpl_crates)
# On macOS, ld warns `ignoring duplicate libraries` when linking a crate.
# Corrosion is the source of both duplicates it names:
#
# * The crate archive and its cxxbridge archive, because
# `corrosion_add_cxxbridge` makes the two depend on each other, and CMake
# repeats a static library cycle on the link line so single-pass linkers can
# resolve it. (LINK_INTERFACE_MULTIPLICITY can only raise that count.)
# * `-lSystem`, which Corrosion copies from rustc's `native-static-libs` even
# though the compiler driver always links libSystem.
#
# ld needs neither: it resolves the cycle from one copy of each archive and
# links libSystem once. So silence the warning rather than rewrite Corrosion's
# link interface, which the cycle is also part of. The option itself is old —
# Xcode 15 is only where the warning became the default — and the check below
# leaves it out on a linker that does not know it.
if(is_macos)
include(CheckLinkerFlag)
check_linker_flag(
CXX
-Wl,-no_warn_duplicate_libraries
have_no_warn_duplicate_libraries
)
endif()
function(_unlink_libgcc_s crate)
if(NOT (is_linux AND static))
return()
endif()
# Corrosion exposes a crate's staticlib as an imported `<crate>-static`
# target and puts the native libs in its INTERFACE_LINK_LIBRARIES. If either
# of those changes, warn instead of silently letting libgcc_s.so.1 return.
set(imported "${crate}-static")
if(NOT TARGET ${imported})
message(
FATAL_ERROR
"Corrosion did not create the imported target '${imported}', so "
"libgcc_s cannot be removed from the link interface of '${crate}'. "
"xrpld will link libgcc_s.so.1 dynamically. Check where Corrosion "
"${CORROSION_VERSION} now records `native-static-libs`."
)
return()
endif()
get_target_property(libs ${imported} INTERFACE_LINK_LIBRARIES)
if(NOT "gcc_s" IN_LIST libs)
message(
WARNING
"'gcc_s' was not in the link interface of '${imported}' as "
"expected. If the Rust toolchain stopped reporting it this "
"workaround is obsolete and can be deleted; otherwise xrpld may "
"link libgcc_s.so.1 dynamically. Verify with: "
"objdump -p xrpld | grep NEEDED"
)
return()
endif()
list(REMOVE_ITEM libs gcc_s)
set_property(TARGET ${imported} PROPERTY INTERFACE_LINK_LIBRARIES ${libs})
endfunction()
function(add_xrpl_crate name)
cmake_parse_arguments(ARG "" "CRATE" "FILES" ${ARGN})
_unlink_libgcc_s(${ARG_CRATE})
# `cc` picks its runtime flag from `crt-static` alone, so it compiles a
# crate's C++ with `-MT`; Debug needs `-MTd` (to match cmake/XrplCompiler.cmake).
if(is_msvc)
corrosion_set_env_vars(
${ARG_CRATE}
"$<$<CONFIG:Debug>:CXXFLAGS=-MTd>"
)
endif()
corrosion_add_cxxbridge(${name}_cxxbridge CRATE ${ARG_CRATE} FILES
${ARG_FILES}
)
# Generated cxxbridge headers don't exist at configure time; CMake 3.28+
# validates INTERFACE_SOURCES on consuming targets. Clear it to skip the
# existence check — build-time ordering is enforced by the custom commands.
set_target_properties(${name}_cxxbridge PROPERTIES INTERFACE_SOURCES "")
if(have_no_warn_duplicate_libraries)
target_link_options(
${name}_cxxbridge
INTERFACE -Wl,-no_warn_duplicate_libraries
)
endif()
add_dependencies(xrpl_crates ${name}_cxxbridge)
endfunction()
add_xrpl_crate(rs_hello_world CRATE rs_hello_world FILES lib.rs)

301
crates/Cargo.lock generated
View File

@@ -1,301 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "anstyle"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
[[package]]
name = "cc"
version = "1.2.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d"
dependencies = [
"find-msvc-tools",
"shlex",
]
[[package]]
name = "clap"
version = "4.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
dependencies = [
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_lex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]]
name = "codespan-reporting"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681"
dependencies = [
"serde",
"termcolor",
"unicode-width",
]
[[package]]
name = "cxx"
version = "1.0.199"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824894a4a85dca76d4c95c2b9098c036f5a29f627b30c12780774f6654e60974"
dependencies = [
"cc",
"cxx-build",
"cxxbridge-cmd",
"cxxbridge-flags",
"cxxbridge-macro",
"foldhash",
"link-cplusplus",
]
[[package]]
name = "cxx-build"
version = "1.0.199"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1ae0b651ea5b0000b19513aef5a03f194d7e3486f2d9258b658da8677fe9036"
dependencies = [
"cc",
"codespan-reporting",
"indexmap",
"proc-macro2",
"quote",
"scratch",
"syn 3.0.3",
]
[[package]]
name = "cxxbridge-cmd"
version = "1.0.199"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb05f91d3fb8435d9bab6ac5ce6ac1868be774325fb7fb2a91be39393b21388e"
dependencies = [
"clap",
"codespan-reporting",
"indexmap",
"proc-macro2",
"quote",
"syn 3.0.3",
]
[[package]]
name = "cxxbridge-flags"
version = "1.0.199"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf293202e0e3e98495785745389e8d0755b217e66f19194a5c695c25e03282ef"
[[package]]
name = "cxxbridge-macro"
version = "1.0.199"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca001d746947c7249ed9d332a10f7a59daedbafeb0ec68c5c18a7db7a93f6ccc"
dependencies = [
"indexmap",
"proc-macro2",
"quote",
"syn 3.0.3",
]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
[[package]]
name = "foldhash"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
[[package]]
name = "hashbrown"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
[[package]]
name = "indexmap"
version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "link-cplusplus"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f78c730aaa7d0b9336a299029ea49f9ee53b0ed06e9202e8cb7db9bae7b8c82"
dependencies = [
"cc",
]
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rs-hello_world"
version = "0.1.0"
dependencies = [
"cxx",
]
[[package]]
name = "scratch"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d68f2ec51b097e4c1a75b681a8bec621909b5e91f15bb7b840c4f2f7b01148b2"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "termcolor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-width"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]]
name = "winapi-util"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]

View File

@@ -1,15 +0,0 @@
[workspace]
members = ["hello_world"]
resolver = "3"
[workspace.dependencies]
cxx = { version = "1.0.198", features = ["c++20"] }
[workspace.package]
edition = "2024"
[profile.release]
opt-level = 3
overflow-checks = true
lto = true
debug = true

View File

@@ -1,10 +0,0 @@
---
# Neutralizes clang-tidy for the corrosion/cxxbridge-generated C++. Copied into
# the crates build directory by crates/CMakeLists.txt, next to the generated
# sources, so clang-tidy picks it up instead of the top-level configuration.
#
# One check is kept enabled to avoid clang-tidy's "no checks enabled" error.
Checks: "-*,google-readability-todo"
WarningsAsErrors: ""
HeaderFilterRegex: ""
InheritParentConfig: false

View File

@@ -1,10 +0,0 @@
[package]
name = "rs-hello_world"
version = "0.1.0"
edition.workspace = true
[lib]
crate-type = ["staticlib"]
[dependencies]
cxx.workspace = true

View File

@@ -1,10 +0,0 @@
#[cxx::bridge(namespace = "rs::hello_world")]
mod ffi {
extern "Rust" {
fn hello_world() -> String;
}
}
pub fn hello_world() -> String {
"hello_world".to_string()
}

View File

@@ -46,9 +46,6 @@ Besides a compiler, building `xrpld` requires:
On Linux and macOS, the [Nix development shell](./nix.md) provides all of them
(see below). On Windows they have to be installed manually.
Building with `-Drust=ON` additionally requires a Rust toolchain, see
[Rust](#rust). A default build does not, so it is not in the table above.
Once they are in place, verify that everything is installed and runnable with:
```bash
@@ -124,25 +121,6 @@ manually:
- [Git for Windows](https://git-scm.com/download/win)
- Python, Conan, and CMake, at the versions listed in
[Required tools](#required-tools).
- a [Rust toolchain](https://rustup.rs) — only needed to build with
`-Drust=ON`, see [Rust](#rust)
## Rust
The repository contains a Rust workspace in [`crates/`](../../crates), whose
crates are exposed to C++ through [cxx](https://cxx.rs) bindings. It is **not**
part of a default build: the CMake `rust` option is OFF by default, and with it
off no Rust toolchain is needed. It is only required when configuring with
`-Drust=ON` (which is what CI does), see [Options](../../BUILD.md#options).
The toolchain (`cargo`, `rustc`) is pinned to the channel in
[`rust-toolchain.toml`](../../rust-toolchain.toml) at the repository root. If
you install Rust with [rustup](https://rustup.rs), that file is picked up
automatically, and `cargo`/`rustc` in the repository will use the pinned
version.
Everything else the Rust build needs on the CMake side comes from Conan along
with the rest of the dependencies, so there is nothing further to install.
## Clang-tidy

View File

@@ -1,10 +1,3 @@
# Installing xrpld 3.3.0 and earlier
> [!IMPORTANT]
> These instructions apply to xrpld 3.3.0 and earlier, published to
> repos.ripple.com.
> For later releases see [install.md](./install.md).
This document contains instructions for installing xrpld.
The APT package manager is common on Debian-based Linux distributions like
Ubuntu,
@@ -59,7 +52,7 @@ The default [prefix][1] is typically `/usr/local` on Linux and macOS and
5. Add the appropriate XRPL repository for your operating system version:
echo "deb [signed-by=/usr/local/share/keyrings/ripple-key.gpg] https://repos.ripple.com/repos/rippled-deb focal stable" | \
echo "deb [signed-by=/usr/local/share/keyrings/ripple-key.gpg] https://repos.ripple.com/repos/xrpld-deb focal stable" | \
sudo tee -a /etc/apt/sources.list.d/ripple.list
The above example is appropriate for **Ubuntu 20.04 Focal Fossa**. For other operating systems, replace the word `focal` with one of the following:
@@ -113,8 +106,8 @@ The default [prefix][1] is typically `/usr/local` on Linux and macOS and
enabled=1
gpgcheck=0
repo_gpgcheck=1
baseurl=https://repos.ripple.com/repos/rippled-rpm/stable/
gpgkey=https://repos.ripple.com/repos/rippled-rpm/stable/repodata/repomd.xml.key
baseurl=https://repos.ripple.com/repos/xrpld-rpm/stable/
gpgkey=https://repos.ripple.com/repos/xrpld-rpm/stable/repodata/repomd.xml.key
REPOFILE
_Unstable_
@@ -125,8 +118,8 @@ The default [prefix][1] is typically `/usr/local` on Linux and macOS and
enabled=1
gpgcheck=0
repo_gpgcheck=1
baseurl=https://repos.ripple.com/repos/rippled-rpm/unstable/
gpgkey=https://repos.ripple.com/repos/rippled-rpm/unstable/repodata/repomd.xml.key
baseurl=https://repos.ripple.com/repos/xrpld-rpm/unstable/
gpgkey=https://repos.ripple.com/repos/xrpld-rpm/unstable/repodata/repomd.xml.key
REPOFILE
_Nightly_
@@ -137,8 +130,8 @@ The default [prefix][1] is typically `/usr/local` on Linux and macOS and
enabled=1
gpgcheck=0
repo_gpgcheck=1
baseurl=https://repos.ripple.com/repos/rippled-rpm/nightly/
gpgkey=https://repos.ripple.com/repos/rippled-rpm/nightly/repodata/repomd.xml.key
baseurl=https://repos.ripple.com/repos/xrpld-rpm/nightly/
gpgkey=https://repos.ripple.com/repos/xrpld-rpm/nightly/repodata/repomd.xml.key
REPOFILE
2. Fetch the latest repo updates:

84
docs/build/nix.md vendored
View File

@@ -7,7 +7,7 @@ This guide explains how to use Nix to set up a reproducible development environm
## Benefits of Using Nix
- **Reproducible environment**: Everyone gets the same versions of tools and compilers
- **Matches CI**: The Linux CI runs in Docker images built from this exact Nix environment, and CI builds some macOS configurations in it as well
- **Matches CI**: The Linux CI runs in Docker images built from this exact Nix environment
- **No system pollution**: Dependencies are isolated and don't affect your system packages
- **Consistent compilers**: The GCC and Clang shells use the same versions as CI
- **Quick setup**: Get started with a single command
@@ -68,7 +68,7 @@ A compiler can be chosen by providing its name with the `.#` prefix, e.g. `nix d
On Linux, `.#gcc` and `.#clang` provide the exact toolchain CI uses:
the compiler (pinned in [`nix/packages.nix`](../../nix/packages.nix))
rebuilt against the pinned custom glibc (see [`nix/linux.nix`](../../nix/linux.nix)).
rebuilt against the pinned custom glibc (see [`nix/compilers.nix`](../../nix/compilers.nix)).
Building that toolchain the first time is slow unless it is fetched from a Nix binary cache.
If you don't need the custom glibc, the Linux-only `.#gcc-plain` and `.#clang-plain`
give you the stock nixpkgs compilers of the same versions.
@@ -128,12 +128,6 @@ Coverage builds (`-Dcoverage=ON`) work in the `gcc` shell (and `gcc-plain` on Li
each ships a `gcov` matching its compiler, since Nix's cc-wrapper does not expose one.
The `clang` shells do not include `llvm-cov`, so use a `gcc` shell for coverage.
Builds of the Rust crates (`-Drust=ON`) also work out of the box: every shell
provides the Rust toolchain pinned in
[`rust-toolchain.toml`](../../rust-toolchain.toml) (see
[Rust](./environment.md#rust)), plus the `cargo-audit`, `cargo-llvm-cov` and
`cargo-nextest` plugins.
## Conan configuration
The shell runs [`conan/init.sh`](../../conan/init.sh) on entry, so
@@ -148,80 +142,14 @@ environment — CI runs in Docker images that bundle the dev shell's toolchain (
`-plain` shells do not match that toolchain's glibc, so binaries from the remote
are not a reliable match there.
On **macOS**, CI also builds in this Nix environment, in Debug and Release (the
`macos-arm64-*-nix` configurations — Debug because the profile defaults to it).
The Nix build resolves to `compiler=clang`, so it gets its own package IDs,
separate from the Apple Clang ones. The
[dependency upload](../../.github/workflows/upload-conan-deps.yml) publishes them
on pushes to `develop` and on manual runs — its nightly run rebuilds everything
from source but uploads nothing — so once a set has been published `nix develop`
can reuse it instead of compiling every dependency locally. These configurations
run outside the reduced pull-request matrix, so label a PR `Full CI build` when it
touches `flake.lock` or `nix/`.
On **macOS**, CI builds with Apple Clang, so the remote holds nothing for the Nix
`clang` toolchain and dependencies are compiled locally. We do not publish
Nix-built macOS binaries because a Conan package ID records the compiler version
but not the nixpkgs revision.
To compile everything from source, add `--build '*'` to the `conan install`
command.
### Why the nixpkgs revision is not part of the package ID
A Conan package ID records the compiler and its major version, but nothing about
the nixpkgs revision the toolchain came from — and `flake.lock` moves far more
often than the toolchain meaningfully changes, so folding it in would rebuild
every dependency on every bump for nothing.
That is safe as long as no cached artifact resolves a `/nix/store` path at run
time, because store paths change on every update and the old ones disappear with
`nix-collect-garbage`. With the `clang` toolchain macOS CI and the dev shell use,
they do not: it links against `/usr/lib/libc++` and `/usr/lib/libSystem`, and
store paths reach the `.a` files only through debug info, which nothing resolves
at link or run time.
> [!WARNING]
> This does not hold for `nix develop .#gcc` on macOS. There is no system
> libstdc++, so GCC links its own from the store and every binary keeps a
> `/nix/store` reference. That shell is fine for tooling, but it is not a build
> configuration CI covers, and no dependency binaries are published for it.
This is checked rather than assumed.
[`bin/check-nix-store-refs.sh`](../../bin/check-nix-store-refs.sh) takes one file
or directory and fails if a binary under it resolves a store path at run time.
CI runs it over the build output and the Conan cache, and again in the upload job
before anything is published. You can run it yourself:
```bash
bin/check-nix-store-refs.sh build
bin/check-nix-store-refs.sh ~/.conan2-nix
```
It works on Linux too, but asserts something narrower there: the toolchain always
writes the store into `PT_INTERP` and `RUNPATH`, and CI builds inside an image
whose store is fixed for its lifetime, so that is fine. Only the binaries
[`PatchNixBinary.cmake`](../../cmake/PatchNixBinary.cmake) retargets to the
system loader have to be clean, and those are what CI checks:
```bash
bin/check-nix-store-refs.sh build/xrpld
```
### The libresolv stub
This is not hypothetical: `xrpld` used to be caught by it. The c-ares package
tells the linker to pass `-lresolv`, and nixpkgs keeps `libresolv` out of the
macOS SDK and ships it as an ordinary store dylib — so every Nix-built `xrpld`
recorded a `/nix/store/…-libresolv-93/lib/libresolv.9.dylib` load command and
stopped running once that path was collected. Nothing in the link uses a single
symbol from it.
Both environments now put a stub on the linker search path
(`libresolvSystemStub` in [`nix/darwin.nix`](../../nix/darwin.nix)): the
same library with its install name set to `/usr/lib/libresolv.9.dylib`, which is
exactly the load command the Apple Clang build records.
Package IDs did not change, so Conan keeps serving anything built before the
stub landed. If a binary fails to start with `Library not loaded: /nix/store/…`,
see [that entry](./nix_troubleshooting.md#library-not-loaded-nixstore-from-a-binary-that-used-to-work)
in the troubleshooting guide.
## Automatic Activation with direnv
[direnv](https://direnv.net/) or [nix-direnv](https://github.com/nix-community/nix-direnv) can automatically activate the Nix development shell when you enter the repository directory.

View File

@@ -131,91 +131,3 @@ once it picks up that rebuild, then re-run the `grep libgit2` check above to
confirm it reports `1.9.4` or newer.
Until then, prefer the workarounds above.
## `wint_t` / `uint32_t` errors from the Nix libc++ headers
A build that mixes the Nix toolchain with the system SDK fails in libc++ itself,
with errors that look nothing like your code:
```
/nix/store/...-libcxx-.../include/c++/v1/cwchar:136:9: error: target of using declaration conflicts with declaration already in scope
136 | using ::wint_t _LIBCPP_USING_IF_EXISTS;
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types/_wint_t.h:32:25: note: target of using declaration
...
error: use of undeclared identifier 'UINT32_C'
```
The give-away is the second path: Nix's libc++ headers are being combined with
the **Xcode Command Line Tools** SDK instead of the Nix one.
### Why it happens
`SDKROOT` and `DEVELOPER_DIR` are what point the toolchain at the Nix SDK, and
they are not baked into the compiler — a dev shell gets them from the
`apple-sdk` setup hook. CMake, finding neither, asks `xcrun`, which answers with
the system SDK. Nix's `libc++` and Apple's headers then declare the same types
twice.
### Fix
Run the build from inside the dev shell (`nix develop`), or from an environment
that exports both variables. To confirm which SDK a configured build is using:
```bash
grep -o '\-isysroot [^ ]*' build/compile_commands.json | sort -u
```
It should print a `/nix/store/...-apple-sdk-*` path. If it prints
`/Library/Developer/CommandLineTools/...`, re-configure from within the shell —
CMake caches the sysroot, so an existing `build/` directory keeps the wrong one.
## `Library not loaded: /nix/store/…` from a binary that used to work
A binary stops starting after a `nix flake update`, or after
`nix-collect-garbage` removes the paths the previous toolchain used:
```
dyld[57271]: Library not loaded: /nix/store/…-libresolv-93/lib/libresolv.9.dylib
```
[`bin/check-nix-store-refs.sh`](../../bin/check-nix-store-refs.sh) finds the same
thing without having to run anything, and names the file:
```
$ bin/check-nix-store-refs.sh ~/.conan2-nix
::error file=/Users/you/.conan2-nix/p/b/c-area24ded30c388c/p/bin/adig::references the Nix store at run time
/Users/you/.conan2-nix/p/b/c-area24ded30c388c/p/bin/adig
/nix/store/p4lp3xq4imd1qzqh08x8vcq2zfhi7rca-libresolv-93/lib/libresolv.9.dylib
/Users/you/.conan2-nix: checked 135, skipped 2495, 1 with Nix store references.
```
Conan's cache folders are named after a truncated package name plus a hash, so
ask Conan which package the offending one belongs to — pass the folder holding
the hash, not the file itself:
```
$ conan cache ref ~/.conan2-nix/p/b/c-area24ded30c388c
c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650:dab5992496abe6d219defb7986ecbf367615a5e5#…
```
### Why it happens
The binary records a store path that no longer exists. Nothing we build should:
see [Prebuilt packages](./nix.md#prebuilt-packages) for why, and
`libresolvSystemStub` in [`nix/darwin.nix`](../../nix/darwin.nix) for the one
dependency that needed help to comply.
A Conan package ID does not encode the nixpkgs revision, so a package built
before that stub existed stays in your local cache and keeps being reused. The
dev shell is also what tends to produce one: it is a slightly _less_ isolated
build environment than CI's, because `mkShell` puts every tool's headers and
libraries on the compiler's search path — which is how c-ares found the Nix
`libresolv` in the first place.
### Fix
Drop that package and let Conan refetch or rebuild it:
```bash
conan remove 'c-ares/*'
```

View File

@@ -1,144 +0,0 @@
# Installing xrpld
> [!NOTE]
> These instructions apply to packages published from 2026-08-19 onwards.
> For xrpld 3.3.0 and earlier see [install-legacy.md](./install-legacy.md).
`xrpld` is published as DEB and RPM packages for 64-bit x86 Linux.
Use APT on Debian-based distributions such as Debian and Ubuntu,
and YUM on Red Hat-based distributions such as RHEL, AlmaLinux, and Rocky Linux.
To build from source instead, see [BUILD.md](../BUILD.md).
## Release channels
Packages are published to four channels:
- `stable` - the latest production release
- `unstable` - release candidates
- `experimental` - beta builds
- `develop` - every push to the [`develop` branch](https://github.com/XRPLF/rippled/tree/develop)
See [Publishing packages](../package/README.md#publishing-packages) for how channels are produced.
The instructions below use `stable`.
To follow another channel, replace `stable` with its name
wherever it appears in the repository configuration.
> [!WARNING]
> Channels other than `stable` may be broken at any time.
> Do not use them for production servers.
## Install the xrpld package
### With the APT package manager
1. Install utilities:
```bash
sudo apt update -y
sudo apt install -y apt-transport-https ca-certificates curl gnupg
```
2. Add the XRPL Foundation package-signing key to your list of trusted keys:
```bash
sudo install -d -m 0755 /etc/apt/keyrings
sudo curl -fsS https://packages.xrplf.org/xrplf.asc -o /etc/apt/keyrings/xrplf.asc
```
3. Check the fingerprint of the newly-added key:
```bash
gpg --show-keys /etc/apt/keyrings/xrplf.asc
```
The output should be:
```text
pub rsa4096 2026-08-18 [SC]
B655416741221F780FBCFBC9AA84D41A11D29FA9
uid XRPLF Packages <distribution@xrplf.org>
```
In particular, make sure that the fingerprint matches.
4. Add the repository, using the channel you picked in [Release channels](#release-channels):
```bash
echo "deb [signed-by=/etc/apt/keyrings/xrplf.asc] https://packages.xrplf.org/repository/deb-stable any main" | \
sudo tee /etc/apt/sources.list.d/xrplf.list
```
5. Fetch the repository:
```bash
sudo apt -y update
```
6. Install the `xrpld` software package:
```bash
sudo apt -y install xrpld
```
### With the YUM package manager
1. Add the XRPL Foundation package-signing key:
```bash
sudo rpm --import https://packages.xrplf.org/xrplf.asc
```
2. Add the repository, using the channel you picked in [Release channels](#release-channels):
```bash
cat << 'REPOFILE' | sudo tee /etc/yum.repos.d/xrplf.repo
[xrplf-stable]
name=XRP Ledger Packages
enabled=1
baseurl=https://packages.xrplf.org/repository/rpm-stable/$basearch/
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.xrplf.org/xrplf.asc
REPOFILE
```
`gpgcheck=1` verifies each package against the key above.
`repo_gpgcheck=1` verifies the repository metadata, which the server signs with the same key.
3. Install the `xrpld` package:
```bash
sudo yum install -y xrpld
```
## The xrpld service
Both package managers install a systemd unit and enable it, so `xrpld` starts on boot.
Check whether it is already running:
```bash
systemctl status xrpld.service
```
The APT packages start it immediately as well; the YUM packages do not, so start it yourself:
```bash
sudo systemctl start xrpld.service
```
### Optional: binding to privileged ports
To serve incoming API requests on port 80 or 443, grant the service the capability to bind them.
You must also update the config file's port settings.
```bash
sudo install -d -m 0755 /etc/systemd/system/xrpld.service.d
sudo tee /etc/systemd/system/xrpld.service.d/privileged-ports.conf >/dev/null <<'EOF'
[Service]
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
EOF
sudo systemctl daemon-reload
sudo systemctl restart xrpld.service
```

View File

@@ -24,7 +24,6 @@
#include <optional>
#include <set>
#include <utility>
#include <vector>
namespace xrpl {
@@ -199,10 +198,7 @@ dirLink(
* if withdrawing to self.
* - If withdrawing to self, succeed.
* - If not, checks if the receiver requires deposit authorization, and if
* the sender has it (account-based or credential-based).
* - Expects any credentials passed in to already exist in the ledger, and
* returns an internal error otherwise. Validate them beforehand with
* credentials::valid().
* the sender has it.
* - Checks that the receiver will not exceed the limit (IOU trustline limit
* or MPT MaximumAmount).
*/
@@ -213,8 +209,7 @@ canWithdraw(
AccountID const& to,
SLE::const_ref toSle,
STAmount const& amount,
bool hasDestinationTag,
std::optional<std::vector<uint256>> const& credentialIDs = std::nullopt);
bool hasDestinationTag);
/**
* Checks that can withdraw funds from an object to itself or a destination.
@@ -227,10 +222,7 @@ canWithdraw(
* if withdrawing to self.
* - If withdrawing to self, succeed.
* - If not, checks if the receiver requires deposit authorization, and if
* the sender has it (account-based or credential-based).
* - Expects any credentials passed in to already exist in the ledger, and
* returns an internal error otherwise. Validate them beforehand with
* credentials::valid().
* the sender has it.
* - Checks that the receiver will not exceed the limit (IOU trustline limit
* or MPT MaximumAmount).
*/
@@ -240,25 +232,20 @@ canWithdraw(
AccountID const& from,
AccountID const& to,
STAmount const& amount,
bool hasDestinationTag,
std::optional<std::vector<uint256>> const& credentialIDs = std::nullopt);
bool hasDestinationTag);
/**
* Checks that can withdraw funds from an object to itself or a destination.
*
* The receiver may be either the submitting account (sfAccount) or a different
* destination account (sfDestination). Credentials, if any, are taken from the
* transaction's sfCredentialIDs field.
* destination account (sfDestination).
*
* - Checks that the receiver account exists.
* - If the receiver requires a destination tag, check that one exists, even
* if withdrawing to self.
* - If withdrawing to self, succeed.
* - If not, checks if the receiver requires deposit authorization, and if
* the sender has it (account-based or credential-based).
* - Expects any credentials in sfCredentialIDs to already exist in the
* ledger, and returns an internal error otherwise. Validate them
* beforehand with credentials::valid().
* the sender has it.
* - Checks that the receiver will not exceed the limit (IOU trustline limit
* or MPT MaximumAmount).
*/

View File

@@ -1,45 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class AMMEntry : public SLEBase<ViewT, ltAMM>
{
public:
using Base = SLEBase<ViewT, ltAMM>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit AMMEntry(
Asset const& issue1,
Asset const& issue2,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::amm(issue1, issue2), view, j)
{
}
explicit AMMEntry(
uint256 const& ammID,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::amm(ammID), view, j)
{
}
};
using RAMMEntry = AMMEntry<ReadView>;
using WAMMEntry = AMMEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,35 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class AccountRootEntry : public SLEBase<ViewT, ltACCOUNT_ROOT>
{
public:
using Base = SLEBase<ViewT, ltACCOUNT_ROOT>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit AccountRootEntry(
AccountID const& id,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::account(id), view, j)
{
}
};
using RAccountRootEntry = AccountRootEntry<ReadView>;
using WAccountRootEntry = AccountRootEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,33 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class AmendmentsEntry : public SLEBase<ViewT, ltAMENDMENTS>
{
public:
using Base = SLEBase<ViewT, ltAMENDMENTS>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit AmendmentsEntry(
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::amendments(), view, j)
{
}
};
using RAmendmentsEntry = AmendmentsEntry<ReadView>;
using WAmendmentsEntry = AmendmentsEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,36 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/STXChainBridge.h>
namespace xrpl {
template <typename ViewT>
class BridgeEntry : public SLEBase<ViewT, ltBRIDGE>
{
public:
using Base = SLEBase<ViewT, ltBRIDGE>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit BridgeEntry(
STXChainBridge const& bridge,
STXChainBridge::ChainType chainType,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::bridge(bridge, chainType), view, j)
{
}
};
using RBridgeEntry = BridgeEntry<ReadView>;
using WBridgeEntry = BridgeEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,46 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class CheckEntry : public SLEBase<ViewT, ltCHECK>
{
public:
using Base = SLEBase<ViewT, ltCHECK>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit CheckEntry(
AccountID const& id,
SeqProxy const& seq,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::check(id, seq), view, j)
{
}
explicit CheckEntry(
uint256 const& checkID,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::check(checkID), view, j)
{
}
};
using RCheckEntry = CheckEntry<ReadView>;
using WCheckEntry = CheckEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,47 +0,0 @@
#pragma once
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class CredentialEntry : public SLEBase<ViewT, ltCREDENTIAL>
{
public:
using Base = SLEBase<ViewT, ltCREDENTIAL>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit CredentialEntry(
AccountID const& subject,
AccountID const& issuer,
Slice const& credType,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::credential(subject, issuer, credType), view, j)
{
}
explicit CredentialEntry(
uint256 const& credentialID,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::credential(credentialID), view, j)
{
}
};
using RCredentialEntry = CredentialEntry<ReadView>;
using WCredentialEntry = CredentialEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,35 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class DIDEntry : public SLEBase<ViewT, ltDID>
{
public:
using Base = SLEBase<ViewT, ltDID>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit DIDEntry(
AccountID const& account,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::did(account), view, j)
{
}
};
using RDIDEntry = DIDEntry<ReadView>;
using WDIDEntry = DIDEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,36 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class DelegateEntry : public SLEBase<ViewT, ltDELEGATE>
{
public:
using Base = SLEBase<ViewT, ltDELEGATE>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit DelegateEntry(
AccountID const& account,
AccountID const& authorizedAccount,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::delegate(account, authorizedAccount), view, j)
{
}
};
using RDelegateEntry = DelegateEntry<ReadView>;
using WDelegateEntry = DelegateEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,58 +0,0 @@
#pragma once
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <set>
#include <utility>
namespace xrpl {
template <typename ViewT>
class DepositPreauthEntry : public SLEBase<ViewT, ltDEPOSIT_PREAUTH>
{
public:
using Base = SLEBase<ViewT, ltDEPOSIT_PREAUTH>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit DepositPreauthEntry(
AccountID const& owner,
AccountID const& preauthorized,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::depositPreauth(owner, preauthorized), view, j)
{
}
explicit DepositPreauthEntry(
AccountID const& owner,
std::set<std::pair<AccountID, Slice>> const& authCreds,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::depositPreauth(owner, authCreds), view, j)
{
}
explicit DepositPreauthEntry(
uint256 const& preauthID,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::depositPreauth(preauthID), view, j)
{
}
};
using RDepositPreauthEntry = DepositPreauthEntry<ReadView>;
using WDepositPreauthEntry = DepositPreauthEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,50 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <cstdint>
namespace xrpl {
template <typename ViewT>
class DirectoryNodeEntry : public SLEBase<ViewT, ltDIR_NODE>
{
public:
using Base = SLEBase<ViewT, ltDIR_NODE>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit DirectoryNodeEntry(
AccountID const& id,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::ownerDir(id), view, j)
{
}
/**
* Resolve a specific page of the directory rooted at @p root.
*/
explicit DirectoryNodeEntry(
uint256 const& root,
std::uint64_t index,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::page(root, index), view, j)
{
}
};
using RDirectoryNodeEntry = DirectoryNodeEntry<ReadView>;
using WDirectoryNodeEntry = DirectoryNodeEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,37 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class EscrowEntry : public SLEBase<ViewT, ltESCROW>
{
public:
using Base = SLEBase<ViewT, ltESCROW>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit EscrowEntry(
AccountID const& src,
SeqProxy const& seq,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::escrow(src, seq), view, j)
{
}
};
using REscrowEntry = EscrowEntry<ReadView>;
using WEscrowEntry = EscrowEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,33 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class FeeSettingsEntry : public SLEBase<ViewT, ltFEE_SETTINGS>
{
public:
using Base = SLEBase<ViewT, ltFEE_SETTINGS>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit FeeSettingsEntry(
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::feeSettings(), view, j)
{
}
};
using RFeeSettingsEntry = FeeSettingsEntry<ReadView>;
using WFeeSettingsEntry = FeeSettingsEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,33 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class LedgerHashesEntry : public SLEBase<ViewT, ltLEDGER_HASHES>
{
public:
using Base = SLEBase<ViewT, ltLEDGER_HASHES>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit LedgerHashesEntry(
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::skip(), view, j)
{
}
};
using RLedgerHashesEntry = LedgerHashesEntry<ReadView>;
using WLedgerHashesEntry = LedgerHashesEntry<ApplyView>;
} // namespace xrpl

View File

@@ -7,7 +7,6 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/LedgerFormats.h> // IWYU pragma: keep
#include <xrpl/protocol/Protocol.h>
@@ -22,7 +21,6 @@
#include <cstdint>
#include <expected>
#include <optional>
#include <string_view>
#include <utility>
@@ -60,42 +58,6 @@ canApplyToBrokerCover(
bool
checkLendingProtocolDependencies(Rules const& rules, STTx const& tx);
/**
* The accounts and asset that LoanManage::defaultLoan's fixCleanup3_4_0
* freeze/lock exemption applies to.
*
* `defaultLoan` moves funds from the LoanBroker pseudo-account to the Vault
* pseudo-account via `accountSend`. Since neither is the vault asset's
* issuer, this is a third-party transfer that transits through the issuer in
* two hops (broker -> issuer, issuer -> vault; see
* `directSendNoLimitIOU`/`directSendNoLimitMPT`), so the exemption must cover
* both the issuer/broker and issuer/vault pairs, not a direct broker/vault
* pair. `asset` scopes it further to the vault's own currency/MPT issuance,
* so an unrelated one the same accounts happen to hold is still protected.
*/
struct LoanDefaultFreezeExemptAccounts
{
AccountID issuer;
AccountID broker;
AccountID vault;
Asset asset;
};
/**
* Resolves the accounts and asset a LoanManage default transaction is
* exempt from freeze/lock for.
*
* @param view Ledger view used to resolve the Loan -> LoanBroker -> Vault
* chain.
* @param tx The transaction under invariant review.
* @return The exempt accounts and asset if `tx` is a `ttLOAN_MANAGE`
* transaction with the `tfLoanDefault` flag set, `fixCleanup3_4_0` is
* enabled, and the loan/broker/vault objects it references can all be
* resolved; `std::nullopt` otherwise.
*/
[[nodiscard]] std::optional<LoanDefaultFreezeExemptAccounts>
getLoanDefaultFreezeExemptAccounts(ReadView const& view, STTx const& tx);
static constexpr std::uint32_t kSecondsInYear = 365 * 24 * 60 * 60;
Number

View File

@@ -1,46 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class LoanBrokerEntry : public SLEBase<ViewT, ltLOAN_BROKER>
{
public:
using Base = SLEBase<ViewT, ltLOAN_BROKER>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit LoanBrokerEntry(
AccountID const& owner,
SeqProxy const& seq,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::loanBroker(owner, seq), view, j)
{
}
explicit LoanBrokerEntry(
uint256 const& loanBrokerID,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::loanBroker(loanBrokerID), view, j)
{
}
};
using RLoanBrokerEntry = LoanBrokerEntry<ReadView>;
using WLoanBrokerEntry = LoanBrokerEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,45 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class LoanEntry : public SLEBase<ViewT, ltLOAN>
{
public:
using Base = SLEBase<ViewT, ltLOAN>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit LoanEntry(
uint256 const& loanBrokerID,
SeqProxy const& loanSeq,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::loan(loanBrokerID, loanSeq), view, j)
{
}
explicit LoanEntry(
uint256 const& loanID,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::loan(loanID), view, j)
{
}
};
using RLoanEntry = LoanEntry<ReadView>;
using WLoanEntry = LoanEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,55 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/UintTypes.h>
namespace xrpl {
template <typename ViewT>
class MPTokenEntry : public SLEBase<ViewT, ltMPTOKEN>
{
public:
using Base = SLEBase<ViewT, ltMPTOKEN>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit MPTokenEntry(
MPTID const& issuanceID,
AccountID const& holder,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::mptoken(issuanceID, holder), view, j)
{
}
explicit MPTokenEntry(
uint256 const& issuanceKey,
AccountID const& holder,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::mptoken(issuanceKey, holder), view, j)
{
}
explicit MPTokenEntry(
uint256 const& mptokenKey,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::mptoken(mptokenKey), view, j)
{
}
};
using RMPTokenEntry = MPTokenEntry<ReadView>;
using WMPTokenEntry = MPTokenEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,56 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/UintTypes.h>
#include <cstdint>
namespace xrpl {
template <typename ViewT>
class MPTokenIssuanceEntry : public SLEBase<ViewT, ltMPTOKEN_ISSUANCE>
{
public:
using Base = SLEBase<ViewT, ltMPTOKEN_ISSUANCE>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit MPTokenIssuanceEntry(
std::uint32_t seq,
AccountID const& issuer,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::mptokenIssuance(makeMptID(seq, issuer)), view, j)
{
}
explicit MPTokenIssuanceEntry(
MPTID const& issuanceID,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::mptokenIssuance(issuanceID), view, j)
{
}
explicit MPTokenIssuanceEntry(
uint256 const& issuanceKey,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::mptokenIssuance(issuanceKey), view, j)
{
}
};
using RMPTokenIssuanceEntry = MPTokenIssuanceEntry<ReadView>;
using WMPTokenIssuanceEntry = MPTokenIssuanceEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,46 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class NFTokenOfferEntry : public SLEBase<ViewT, ltNFTOKEN_OFFER>
{
public:
using Base = SLEBase<ViewT, ltNFTOKEN_OFFER>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit NFTokenOfferEntry(
AccountID const& owner,
SeqProxy const& seq,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::nftokenOffer(owner, seq), view, j)
{
}
explicit NFTokenOfferEntry(
uint256 const& offerID,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::nftokenOffer(offerID), view, j)
{
}
};
using RNFTokenOfferEntry = NFTokenOfferEntry<ReadView>;
using WNFTokenOfferEntry = NFTokenOfferEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,37 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class NFTokenPageEntry : public SLEBase<ViewT, ltNFTOKEN_PAGE>
{
public:
using Base = SLEBase<ViewT, ltNFTOKEN_PAGE>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit NFTokenPageEntry(
Keylet const& page,
uint256 const& token,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::nftokenPage(page, token), view, j)
{
}
};
using RNFTokenPageEntry = NFTokenPageEntry<ReadView>;
using WNFTokenPageEntry = NFTokenPageEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,33 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class NegativeUNLEntry : public SLEBase<ViewT, ltNEGATIVE_UNL>
{
public:
using Base = SLEBase<ViewT, ltNEGATIVE_UNL>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit NegativeUNLEntry(
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::negativeUNL(), view, j)
{
}
};
using RNegativeUNLEntry = NegativeUNLEntry<ReadView>;
using WNegativeUNLEntry = NegativeUNLEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,46 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class OfferEntry : public SLEBase<ViewT, ltOFFER>
{
public:
using Base = SLEBase<ViewT, ltOFFER>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit OfferEntry(
AccountID const& id,
SeqProxy const& seq,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::offer(id, seq), view, j)
{
}
explicit OfferEntry(
uint256 const& offerID,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::offer(offerID), view, j)
{
}
};
using ROfferEntry = OfferEntry<ReadView>;
using WOfferEntry = OfferEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,38 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <cstdint>
namespace xrpl {
template <typename ViewT>
class OracleEntry : public SLEBase<ViewT, ltORACLE>
{
public:
using Base = SLEBase<ViewT, ltORACLE>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit OracleEntry(
AccountID const& account,
std::uint32_t documentID,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::oracle(account, documentID), view, j)
{
}
};
using ROracleEntry = OracleEntry<ReadView>;
using WOracleEntry = OracleEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,38 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class PayChannelEntry : public SLEBase<ViewT, ltPAYCHAN>
{
public:
using Base = SLEBase<ViewT, ltPAYCHAN>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit PayChannelEntry(
AccountID const& src,
AccountID const& dst,
SeqProxy const& seq,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::payChannel(src, dst, seq), view, j)
{
}
};
using RPayChannelEntry = PayChannelEntry<ReadView>;
using WPayChannelEntry = PayChannelEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,46 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class PermissionedDomainEntry : public SLEBase<ViewT, ltPERMISSIONED_DOMAIN>
{
public:
using Base = SLEBase<ViewT, ltPERMISSIONED_DOMAIN>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit PermissionedDomainEntry(
AccountID const& account,
SeqProxy const& seq,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::permissionedDomain(account, seq), view, j)
{
}
explicit PermissionedDomainEntry(
uint256 const& domainID,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::permissionedDomain(domainID), view, j)
{
}
};
using RPermissionedDomainEntry = PermissionedDomainEntry<ReadView>;
using WPermissionedDomainEntry = PermissionedDomainEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,48 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/UintTypes.h>
namespace xrpl {
template <typename ViewT>
class RippleStateEntry : public SLEBase<ViewT, ltRIPPLE_STATE>
{
public:
using Base = SLEBase<ViewT, ltRIPPLE_STATE>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit RippleStateEntry(
AccountID const& id0,
AccountID const& id1,
Currency const& currency,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::trustLine(id0, id1, currency), view, j)
{
}
explicit RippleStateEntry(
AccountID const& id,
Issue const& issue,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::trustLine(id, issue), view, j)
{
}
};
using RRippleStateEntry = RippleStateEntry<ReadView>;
using WRippleStateEntry = RippleStateEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,493 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/contract.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <concepts>
#include <memory>
#include <stdexcept>
#include <type_traits>
#include <utility>
namespace xrpl {
// Concept to distinguish read-only vs writable view types
template <typename V>
concept WritableView = std::derived_from<V, ApplyView>;
namespace detail {
/**
* Resolves a keylet for a read-only entry.
*
* ReadView::read() on an ApplyView returns the underlying ledger's entry
* whenever the view is not already tracking one, while peek() installs the
* view's own copy and returns that. A read-only entry built with read()
* would therefore hold an SLE that goes stale the moment anything peeks the
* same key and modifies it. Resolve through peek() whenever the view really is
* an ApplyView, so every entry over that view shares one SLE.
*
* @note The const_cast is what makes reaching ApplyView::peek() possible, and
* it is safe only because xrpld never instantiates a ReadView as a
* genuinely const object -- every view is a non-const object that some
* call sites merely observe through a const reference. If an actually
* const-qualified view type is ever introduced (an immutable snapshot,
* say), this becomes undefined behavior and must be revisited.
*
* @note Consequently a "read-only" entry over an ApplyView is not free of
* side effects: peek() installs an Action::Cache entry in the apply
* state table. That is benign for transaction metadata -- Cache entries
* are skipped in ApplyStateTable::apply(), ::visit() and in metadata
* generation -- but it does cost one deep SLE copy on first touch.
*/
inline SLE::const_pointer
resolveEntry(ReadView const& view, Keylet const& key)
{
// Views are never const objects; the read-only entry only holds a const
// reference because it does not itself modify the view.
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
if (auto const applyView = dynamic_cast<ApplyView*>(const_cast<ReadView*>(&view)))
return applyView->peek(key);
return view.read(key);
}
} // namespace detail
/**
* View-parameterized base class for all ledger entries.
*
* SLEBase<ReadView> — read-only: holds shared_ptr<SLE const> + ReadView const&
* SLEBase<ApplyView> — writable: holds shared_ptr<SLE> + ApplyView& + Keylet,
* plus insert/update/erase operations
*
* Write-only members are gated by `requires` clauses, providing compile-time
* guarantees that read-only entries cannot mutate state.
*
* @tparam EntryType the ledger entry type this entry is statically bound to.
* Derived per-type entries pass their own type (e.g. ltACCOUNT_ROOT); the
* generic ReadOnlySLE / WritableSLE aliases leave it at ltANY, which opts out
* of the static type check. Binding the type here is what keeps an entry for
* one entry type from being constructed or converted from another -- see the
* converting constructor below.
*
* Derived classes should provide domain-specific accessors that hide
* implementation details of the underlying ledger entry format.
*/
template <typename ViewT, LedgerEntryType EntryType = ltANY>
class SLEBase
{
public:
static constexpr bool kIsWritable = WritableView<ViewT>;
// The ledger entry type this entry is bound to, and whether that binding
// is meaningful (ltANY means "any type", i.e. no static check).
static constexpr LedgerEntryType kEntryType = EntryType;
static constexpr bool kIsTyped = (EntryType != ltANY);
// SLE pointer type: mutable for writable views, const for read-only
using sle_ptr_type = std::conditional_t<kIsWritable, SLE::pointer, SLE::const_pointer>;
// View reference type: ApplyView& for writable, ReadView const& for
// read-only
using view_ref_type = std::conditional_t<kIsWritable, ApplyView&, ReadView const&>;
// Non-virtual by design: these entries are parameterized on the view and
// entry type, never used polymorphically through a base pointer. A vptr
// would be 8 bytes of pure overhead on a type meant to be as cheap as the
// shared_ptr it wraps. See the static_assert below the class.
//
// The destructor is public because the ReadOnlySLE / WritableSLE aliases
// name this class directly and are used as value types. Since it is not
// virtual, never delete a derived entry through an SLEBase*.
~SLEBase() = default;
SLEBase(SLEBase const&) = default;
SLEBase(SLEBase&&) = default;
SLEBase&
operator=(SLEBase const&) = delete;
SLEBase&
operator=(SLEBase&&) = delete;
SLEBase() = delete;
// --- Constructors that adopt/resolve an SLE (public so the ReadOnlySLE /
// WritableSLE aliases and the per-type entries can be built directly
// from a keylet, or -- read-only only -- from an already-fetched
// SLE). ---
/**
* Constructor for read-only context (adopt an already-fetched SLE).
*
* There is deliberately no writable equivalent: a writable entry needs
* a Keylet so that newSLE() can still build an entry when none exists,
* and that cannot be recovered from a null SLE.
*/
explicit SLEBase(
SLE::const_pointer sle,
view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
requires(!kIsWritable)
: view_(view), sle_(std::move(sle)), j_(j)
{
XRPL_ASSERT(
!kIsTyped || !sle_ || sle_->getType() == kEntryType,
"xrpl::SLEBase::SLEBase : adopted SLE matches bound entry type");
}
/**
* Constructor for read-only context (read from view by keylet)
*/
explicit SLEBase(
Keylet const& key,
view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
requires(!kIsWritable)
: view_(view), sle_(detail::resolveEntry(view, key)), j_(j)
{
XRPL_ASSERT(
!kIsTyped || key.type == kEntryType,
"xrpl::SLEBase::SLEBase : keylet matches bound entry type");
}
/**
* Converting constructor: writable → read-only.
*
* Enables implicit conversion from SLEBase<ApplyView> to
* SLEBase<ReadView>, so functions taking ReadOnlySLE const& can accept
* WritableSLE.
*
* Constrained to the same entry type (or to a ltANY target, i.e. widening
* a typed entry to a generic ReadOnlySLE). The constraint is load-bearing:
* this constructor is inherited into every per-type entry, and unconstrained
* it would bind any writable entry that slices to SLEBase, so a WOfferEntry
* would convert to an RAccountRootEntry with no cast at the call site.
*/
template <typename OtherViewT, LedgerEntryType OtherType>
SLEBase(SLEBase<OtherViewT, OtherType> const& other)
requires(!kIsWritable && WritableView<OtherViewT> &&
(OtherType == EntryType || EntryType == ltANY))
: view_(other.readView()), sle_(other.rawSle()), j_(other.journal())
{
}
/**
* Constructor for writable context (peek from view by keylet)
*/
explicit SLEBase(
Keylet const& key,
ApplyView& view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
requires kIsWritable
: view_(view), key_(key), sle_(view_.peek(key)), j_(j)
{
XRPL_ASSERT(
!kIsTyped || key.type == kEntryType,
"xrpl::SLEBase::SLEBase : keylet matches bound entry type");
}
/**
* Constructor for writable context, for call sites that hold an
* ApplyViewContext (peek from ctx.view by keylet).
*
* ctx.tx is not retained: this exists purely so transactors can pass the
* context they already have instead of spelling out ctx.view. If an entry
* ever needs the applying transaction, store it here rather than adding
* another overload.
*/
explicit SLEBase(
Keylet const& key,
ApplyViewContext const& ctx,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
requires kIsWritable
: SLEBase(key, ctx.view, j)
{
}
// --- Common interface (always available) ---
/**
* Returns true if the ledger entry exists
*/
[[nodiscard]] bool
exists() const
{
return sle_ != nullptr;
}
/**
* Explicit conversion to bool for convenient existence checking
*/
explicit
operator bool() const
{
return exists();
}
/**
* Returns the underlying SLE for read access.
*
* Prefer operator-> / operator* for field access; this is for the call
* sites that need the shared_ptr itself.
*/
[[nodiscard]] SLE::const_pointer
rawSle() const
{
return sle_;
}
/**
* Returns the ledger entry type of this entry.
*
* For a per-type entry this is kEntryType, known at compile time and
* valid whether or not the entry exists. Only the generic ReadOnlySLE /
* WritableSLE aliases have to read it back out of the SLE.
*
* @throws std::logic_error for a generic (ltANY) entry if exists() is
* false.
*/
[[nodiscard]] LedgerEntryType
type() const
{
if constexpr (kIsTyped)
{
return kEntryType;
}
else
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::type : entry does not exist");
return sle_->getType();
}
}
/**
* Returns the keylet identifying this entry.
*
* Writable entries keep the keylet they were built from, so it is valid
* even before newSLE(). Read-only entries derive it from the SLE, which
* must therefore exist.
*
* @throws std::logic_error for a read-only entry if exists() is false.
*/
[[nodiscard]] Keylet
keylet() const
{
if constexpr (kIsWritable)
{
return key_;
}
else
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::keylet : entry does not exist");
// Take the type from the SLE, not from kEntryType: the adopt-SLE
// constructor's type check is assert-only, so a Release build can
// be holding an SLE whose type disagrees with the binding, and the
// SLE is the one telling the truth.
return Keylet(sle_->getType(), sle_->key());
}
}
/**
* Returns the ledger key of this entry.
*
* @throws std::logic_error same as keylet(): for read-only entries,
* if exists() is false.
*/
[[nodiscard]] uint256
key() const
{
return keylet().key;
}
/**
* Returns the read view (always available; ApplyView inherits ReadView)
*/
[[nodiscard]] ReadView const&
readView() const
{
return view_;
}
/**
* Const dereference operators (always available)
*
* @throws std::logic_error if exists() is false.
*/
STLedgerEntry const*
operator->() const
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::operator-> : entry does not exist");
return sle_.get();
}
STLedgerEntry const&
operator*() const
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::operator* : entry does not exist");
return *sle_;
}
// --- Writable interface (compile-time gated) ---
//
// Everything that hands out mutable access (or mutates) is non-const, so
// that a `WFooEntry const&` is as inert as a `RFooEntry`. Use readView()
// when a const entry only needs to inspect the view.
/**
* Returns the underlying SLE for write access.
*
* Prefer operator-> / operator* for field access; this is for the call
* sites that need the shared_ptr itself.
*/
[[nodiscard]] sle_ptr_type const&
mutableRawSle()
requires kIsWritable
{
return sle_;
}
/**
* Returns the apply view for write operations
*/
[[nodiscard]] ApplyView&
applyView()
requires kIsWritable
{
return view_;
}
/**
* Mutable dereference operators
*
* @throws std::logic_error if exists() is false.
*/
STLedgerEntry*
operator->()
requires kIsWritable
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::operator-> : entry does not exist");
return sle_.get();
}
STLedgerEntry&
operator*()
requires kIsWritable
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::operator* : entry does not exist");
return *sle_;
}
/**
* Inserts the entry into the view.
*
* @throws std::logic_error if exists() is false.
*/
void
insert()
requires kIsWritable
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::insert : entry does not exist");
view_.insert(sle_);
}
/**
* Erases the entry from the view.
*
* Drops the SLE afterwards, so the entry reports !exists() and any
* further use trips an assertion here rather than either throwing from
* deep inside ApplyStateTable or -- worse -- silently succeeding. For an
* entry that already existed, ApplyStateTable::erase keeps holding this
* exact SLE and builds the DeletedNode's FinalFields from it, so a write
* through the entry after erase() would land in transaction metadata
* with no diagnostic at all.
*
* @throws std::logic_error if exists() is false.
*/
void
erase()
requires kIsWritable
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::erase : entry does not exist");
view_.erase(sle_);
sle_ = nullptr;
}
/**
* @throws std::logic_error if exists() is false.
*/
void
update()
requires kIsWritable
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::update : entry does not exist");
view_.update(sle_);
}
/**
* @throws std::logic_error if exists() is true: newSLE() would otherwise
* silently discard the SLE already held.
*/
void
newSLE()
requires kIsWritable
{
if (exists())
Throw<std::logic_error>("xrpl::SLEBase::newSLE : entry already exists");
sle_ = std::make_shared<SLE>(key_);
}
[[nodiscard]] beast::Journal
journal() const
{
return j_;
}
protected:
view_ref_type view_;
// Keylet is only meaningful for writable views, which need it to build an
// SLE that does not exist yet; read-only entries derive it from the SLE.
struct Empty
{
};
// No default member initializer: Keylet is not default-constructible, so
// every writable constructor must initialize key_ explicitly.
[[no_unique_address]]
std::conditional_t<kIsWritable, Keylet, Empty> key_;
sle_ptr_type sle_{};
beast::Journal j_;
};
/**
* Generic (any-entry-type) SLE entries.
*
* Use these when the concrete ledger entry type is not known at a given site;
* otherwise prefer the per-type entries (e.g. AccountRootEntry.h), which
* additionally enforce the entry type at compile time.
*
* SLE::const_pointer / SLE::const_ref -> ReadOnlySLE
* SLE::pointer / SLE::ref -> WritableSLE
*/
using ReadOnlySLE = SLEBase<ReadView>;
using WritableSLE = SLEBase<ApplyView>;
static_assert(
!std::is_polymorphic_v<ReadOnlySLE> && !std::is_polymorphic_v<WritableSLE>,
"SLEBase must stay a thin value type; it must not acquire a vtable");
} // namespace xrpl

View File

@@ -1,35 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class SignerListEntry : public SLEBase<ViewT, ltSIGNER_LIST>
{
public:
using Base = SLEBase<ViewT, ltSIGNER_LIST>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit SignerListEntry(
AccountID const& account,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::signerList(account), view, j)
{
}
};
using RSignerListEntry = SignerListEntry<ReadView>;
using WSignerListEntry = SignerListEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,36 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class SponsorshipEntry : public SLEBase<ViewT, ltSPONSORSHIP>
{
public:
using Base = SLEBase<ViewT, ltSPONSORSHIP>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit SponsorshipEntry(
AccountID const& sponsor,
AccountID const& sponsee,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::sponsorship(sponsor, sponsee), view, j)
{
}
};
using RSponsorshipEntry = SponsorshipEntry<ReadView>;
using WSponsorshipEntry = SponsorshipEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,46 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class TicketEntry : public SLEBase<ViewT, ltTICKET>
{
public:
using Base = SLEBase<ViewT, ltTICKET>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit TicketEntry(
AccountID const& id,
SeqProxy const& ticketSeq,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::ticket(id, ticketSeq), view, j)
{
}
explicit TicketEntry(
uint256 const& ticketID,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::ticket(ticketID), view, j)
{
}
};
using RTicketEntry = TicketEntry<ReadView>;
using WTicketEntry = TicketEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,46 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class VaultEntry : public SLEBase<ViewT, ltVAULT>
{
public:
using Base = SLEBase<ViewT, ltVAULT>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit VaultEntry(
AccountID const& owner,
SeqProxy const& seq,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::vault(owner, seq), view, j)
{
}
explicit VaultEntry(
uint256 const& vaultID,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::vault(vaultID), view, j)
{
}
};
using RVaultEntry = VaultEntry<ReadView>;
using WVaultEntry = VaultEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,9 +1,7 @@
#pragma once
#include <xrpl/basics/Number.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STLedgerEntry.h>
@@ -57,38 +55,6 @@ enum class TruncateShares : bool { No = false, Yes = true };
*/
enum class WaiveUnrealizedLoss : bool { No = false, Yes = true };
/**
* Returns the effective total of assets backing outstanding shares for the
* purposes of a withdrawal, i.e. sfAssetsTotal, discounted by sfLossUnrealized
* unless waived. This is the numerator used by both withdraw conversion
* helpers (assetsToSharesWithdraw and sharesToAssetsWithdraw) to compute the
* share/asset exchange rate.
*
* @param vault The vault SLE.
* @param waive Whether to waive (i.e. not subtract) the vault's unrealized
* loss.
*/
[[nodiscard]] Number
assetsTotalForWithdrawal(SLE::const_ref vault, WaiveUnrealizedLoss waive);
/**
* Returns whether debiting `amount` from `total` — the current value of a
* vault's sfAssetsTotal or sfAssetsAvailable field — would canonicalize back
* to the exact same STAmount value it started at. This happens when a
* genuinely non-zero debit is dust relative to a `total` large enough to
* exceed STAmount's significant-digit precision: the shares still move, but
* the stored total doesn't change, which otherwise trips the ValidVault
* invariant after the fact instead of failing cleanly upfront.
*
* @param asset The vault's underlying asset, used to canonicalize both sides
* the same way the ledger will when the field is stored.
* @param total The field's current value.
* @param amount The amount to debit. A value of zero always returns false;
* that case is rejected separately and unconditionally.
*/
[[nodiscard]] bool
debitIsNonZeroDust(Asset const& asset, Number const& total, Number const& amount);
/**
* From the perspective of a vault, return the number of shares to demand from
* the depositor when they ask to withdraw a fixed amount of assets. Since

View File

@@ -1,38 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/STXChainBridge.h>
#include <cstdint>
namespace xrpl {
template <typename ViewT>
class XChainOwnedClaimIDEntry : public SLEBase<ViewT, ltXCHAIN_OWNED_CLAIM_ID>
{
public:
using Base = SLEBase<ViewT, ltXCHAIN_OWNED_CLAIM_ID>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit XChainOwnedClaimIDEntry(
STXChainBridge const& bridge,
std::uint64_t seq,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::xChainClaimID(bridge, seq), view, j)
{
}
};
using RXChainOwnedClaimIDEntry = XChainOwnedClaimIDEntry<ReadView>;
using WXChainOwnedClaimIDEntry = XChainOwnedClaimIDEntry<ApplyView>;
} // namespace xrpl

View File

@@ -1,39 +0,0 @@
#pragma once
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/STXChainBridge.h>
#include <cstdint>
namespace xrpl {
template <typename ViewT>
class XChainOwnedCreateAccountClaimIDEntry
: public SLEBase<ViewT, ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID>
{
public:
using Base = SLEBase<ViewT, ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit XChainOwnedCreateAccountClaimIDEntry(
STXChainBridge const& bridge,
std::uint64_t seq,
Base::view_ref_type view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::xChainCreateAccountClaimID(bridge, seq), view, j)
{
}
};
using RXChainOwnedCreateAccountClaimIDEntry = XChainOwnedCreateAccountClaimIDEntry<ReadView>;
using WXChainOwnedCreateAccountClaimIDEntry = XChainOwnedCreateAccountClaimIDEntry<ApplyView>;
} // namespace xrpl

View File

@@ -91,17 +91,6 @@ getFee(std::uint16_t tfee)
return Number{tfee} / kAuctionSlotFeeScaleFactor;
}
/**
* Minimum auction slot price: LPTokens * TradingFee / kAuctionSlotMinFeeFraction
* @param lptAMMBalance AMM LP token balance
* @param tradingFee trading fee in {0, 1000}
*/
inline Number
ammAuctionMinSlotPrice(Number const& lptAMMBalance, std::uint16_t tradingFee)
{
return lptAMMBalance * getFee(tradingFee) / kAuctionSlotMinFeeFraction;
}
/**
* Get fee multiplier (1 - tfee)
* @tfee trading fee in basis points

View File

@@ -4,7 +4,6 @@
#include <xrpl/protocol/Rules.h>
#include <xrpl/protocol/SOTemplate.h>
#include <xrpl/protocol/TxFormats.h>
#include <xrpl/protocol/TxSettings.h>
#include <cstdint>
#include <functional>
@@ -39,6 +38,11 @@ enum GranularPermissionType : std::uint32_t {
#pragma pop_macro("GRANULAR_PERMISSION")
};
// Injected bare enumerators (xrpl::delegable / xrpl::notDelegable) are required by preprocessor
// tricks in tests and macro-generated code; enum class would break that.
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
enum Delegation { Delegable, NotDelegable };
class Permission
{
private:
@@ -61,7 +65,7 @@ private:
struct TxDelegationEntry
{
uint256 amendment;
Delegation delegable{Delegation::NotDelegable};
Delegation delegable{NotDelegable};
};
std::unordered_set<TxType> granularTxTypes_;

View File

@@ -1,96 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/safe_cast.h>
#include <cstdint>
#include <type_traits>
namespace xrpl {
enum class Delegation { Delegable, NotDelegable };
/**
* Operations a transaction is permitted to perform, as a bitfield.
*
* These are declared per-transaction in transactions.macro (via
* TxSettings::privileges) and enforced in InvariantCheck.cpp.
*/
enum class Privilege : std::uint16_t {
NoPriv = 0x0000, // The transaction can not do any of the enumerated operations
CreateAcct = 0x0001, // The transaction can create a new ACCOUNT_ROOT object.
CreatePseudoAcct = 0x0002, // The transaction can create a pseudo account,
// which implies createAcct
MustDeleteAcct = 0x0004, // The transaction must delete an ACCOUNT_ROOT object
MayDeleteAcct = 0x0008, // The transaction may delete an ACCOUNT_ROOT
// object, but does not have to
OverrideFreeze = 0x0010, // The transaction can override some freeze rules
ChangeNftCounts = 0x0020, // The transaction can mint or burn an NFT
CreateMptIssuance = 0x0040, // The transaction can create a new MPT issuance
DestroyMptIssuance = 0x0080, // The transaction can destroy an MPT issuance
MustAuthorizeMpt = 0x0100, // The transaction MUST create or delete an MPT
// object (except by issuer)
MayAuthorizeMpt = 0x0200, // The transaction MAY create or delete an MPT
// object (except by issuer)
MayDeleteMpt = 0x0400, // The transaction MAY delete an MPT object. May not create.
MustModifyVault = 0x0800, // The transaction must modify, delete or create, a vault
MayModifyVault = 0x1000, // The transaction MAY modify, delete or create, a vault
MayCreateMpt = 0x2000, // The transaction MAY create an MPT object, except for issuer.
};
// The inner static_cast is not redundant: the underlying type is narrower than
// `int`, so the operands integer-promote and the result has to be narrowed back.
// safeCast rejects that narrowing, but every input bit is a Privilege bit by
// construction, so the result is always representable.
constexpr Privilege
operator|(Privilege lhs, Privilege rhs)
{
using Underlying = std::underlying_type_t<Privilege>;
return static_cast<Privilege>(
static_cast<Underlying>(safeCast<Underlying>(lhs) | safeCast<Underlying>(rhs)));
}
constexpr Privilege
operator&(Privilege lhs, Privilege rhs)
{
using Underlying = std::underlying_type_t<Privilege>;
return static_cast<Privilege>(
static_cast<Underlying>(safeCast<Underlying>(lhs) & safeCast<Underlying>(rhs)));
}
/**
* Per-transaction metadata declared in transactions.macro.
*
* Every member has a default, so a transaction only needs to name the settings
* that differ from the common case. See the documentation at the top of
* transactions.macro for the authoring syntax.
*
* This is deliberately not a constexpr-friendly type: amendment identifiers are
* runtime-initialized `extern uint256 const` globals (see Feature.h), so a
* TxSettings can only be built at runtime.
*/
struct TxSettings
{
/**
* Whether an account may delegate this transaction to another account.
*/
Delegation delegable{Delegation::NotDelegable};
/**
* The amendment gating this transaction, or uint256{} if always available.
*/
// The `{}` looks redundant, because BaseUInt's default constructor already
// zeroes the value. It is not: without a default member initializer here,
// every partial designated initializer in transactions.macro trips the
// missing-designated-field-initializers warning, which the build treats as
// an error.
// NOLINTNEXTLINE(readability-redundant-member-init)
uint256 amendment{};
/**
* Operations this transaction is permitted to perform.
*/
Privilege privileges{Privilege::NoPriv};
};
} // namespace xrpl

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,7 @@ class AMMBidBuilder;
* Type: ttAMM_BID (39)
* Delegable: Delegation::Delegable
* Amendment: featureAMM
* Privileges: Privilege::NoPriv
* Privileges: NoPriv
*
* Immutable wrapper around STTx providing type-safe field access.
* Use AMMBidBuilder to construct new transactions.

View File

@@ -21,7 +21,7 @@ class AMMClawbackBuilder;
* Type: ttAMM_CLAWBACK (31)
* Delegable: Delegation::Delegable
* Amendment: featureAMMClawback
* Privileges: Privilege::MayDeleteAcct | Privilege::OverrideFreeze | Privilege::MayAuthorizeMpt
* Privileges: MayDeleteAcct | OverrideFreeze | MayAuthorizeMpt
*
* Immutable wrapper around STTx providing type-safe field access.
* Use AMMClawbackBuilder to construct new transactions.

View File

@@ -21,7 +21,7 @@ class AMMCreateBuilder;
* Type: ttAMM_CREATE (35)
* Delegable: Delegation::Delegable
* Amendment: featureAMM
* Privileges: Privilege::CreatePseudoAcct | Privilege::MayCreateMpt
* Privileges: CreatePseudoAcct | MayCreateMpt
*
* Immutable wrapper around STTx providing type-safe field access.
* Use AMMCreateBuilder to construct new transactions.

View File

@@ -21,7 +21,7 @@ class AMMDeleteBuilder;
* Type: ttAMM_DELETE (40)
* Delegable: Delegation::Delegable
* Amendment: featureAMM
* Privileges: Privilege::MustDeleteAcct | Privilege::MayDeleteMpt
* Privileges: MustDeleteAcct | MayDeleteMpt
*
* Immutable wrapper around STTx providing type-safe field access.
* Use AMMDeleteBuilder to construct new transactions.

View File

@@ -21,7 +21,7 @@ class AMMDepositBuilder;
* Type: ttAMM_DEPOSIT (36)
* Delegable: Delegation::Delegable
* Amendment: featureAMM
* Privileges: Privilege::NoPriv
* Privileges: NoPriv
*
* Immutable wrapper around STTx providing type-safe field access.
* Use AMMDepositBuilder to construct new transactions.

View File

@@ -21,7 +21,7 @@ class AMMVoteBuilder;
* Type: ttAMM_VOTE (38)
* Delegable: Delegation::Delegable
* Amendment: featureAMM
* Privileges: Privilege::NoPriv
* Privileges: NoPriv
*
* Immutable wrapper around STTx providing type-safe field access.
* Use AMMVoteBuilder to construct new transactions.

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