mirror of
https://github.com/XRPLF/rippled.git
synced 2026-09-25 22:50:12 +00:00
Compare commits
147 Commits
copilot/fi
...
copilot/ad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
930def8040 | ||
|
|
0219c01b33 | ||
|
|
00606bec1a | ||
|
|
2bc17c3e73 | ||
|
|
0229c294a9 | ||
|
|
184fe173fb | ||
|
|
16f7b263fd | ||
|
|
f6b51f0b8b | ||
|
|
07b36871c7 | ||
|
|
638ae08eeb | ||
|
|
24be48ee84 | ||
|
|
e20f448a71 | ||
|
|
f6c80fef68 | ||
|
|
a0c12420b5 | ||
|
|
1245254cac | ||
|
|
b60636169a | ||
|
|
d6022fbc4d | ||
|
|
295b74da1c | ||
|
|
faa2bf583f | ||
|
|
da260fa42b | ||
|
|
53788b193d | ||
|
|
227f1b4d9c | ||
|
|
26b66957ec | ||
|
|
54e62a621f | ||
|
|
53628b70c0 | ||
|
|
6fec2c11bf | ||
|
|
04108a030c | ||
|
|
551a19b10d | ||
|
|
b0a940a383 | ||
|
|
e302e4eeed | ||
|
|
1a4a40ebb8 | ||
|
|
7f55dd390c | ||
|
|
6558ce3d22 | ||
|
|
9403736199 | ||
|
|
028783661d | ||
|
|
21890d9daf | ||
|
|
060957ed39 | ||
|
|
1381483c7a | ||
|
|
3e4bdf2782 | ||
|
|
e3c8996e44 | ||
|
|
4b2cd3637d | ||
|
|
d5bfe94f15 | ||
|
|
7f0190949a | ||
|
|
2ad4def35f | ||
|
|
f7f50caa6e | ||
|
|
3e54e7d00b | ||
|
|
827b50f169 | ||
|
|
58a59c37ed | ||
|
|
986065c16f | ||
|
|
37cb4cdbe3 | ||
|
|
2ddf6ee148 | ||
|
|
8ce4f71427 | ||
|
|
6e1eb88e6e | ||
|
|
49cdc105de | ||
|
|
636d2d4851 | ||
|
|
7d7275847d | ||
|
|
f0fd6ad85e | ||
|
|
5d8fd9824e | ||
|
|
346ea40f69 | ||
|
|
8809bdf3f0 | ||
|
|
deaf596494 | ||
|
|
7863ac8cf6 | ||
|
|
b3b38e4416 | ||
|
|
ccd5dc5e06 | ||
|
|
b2453b626e | ||
|
|
de6e5d3a94 | ||
|
|
73d2ed51c4 | ||
|
|
fac20a06f3 | ||
|
|
9a7c5ea593 | ||
|
|
7281e0606a | ||
|
|
71f5555873 | ||
|
|
3967ed6d54 | ||
|
|
e0151229b6 | ||
|
|
b6a899583b | ||
|
|
dc3bd9cf00 | ||
|
|
1e8b136bfb | ||
|
|
3c47af779c | ||
|
|
c28d389e0e | ||
|
|
d83a84510e | ||
|
|
f8fba079fe | ||
|
|
42502e4263 | ||
|
|
36c165f74d | ||
|
|
f7ea645bf4 | ||
|
|
50527485d3 | ||
|
|
421af6db79 | ||
|
|
fee4bfc22e | ||
|
|
5e3d20b3ed | ||
|
|
9e2aaf6f60 | ||
|
|
ec042fefee | ||
|
|
45e4b8899d | ||
|
|
c5dc408596 | ||
|
|
473fe44a85 | ||
|
|
0fdaf69e2c | ||
|
|
9d41b1bd1c | ||
|
|
f137d71510 | ||
|
|
8bc6e81c5f | ||
|
|
764cbe7c29 | ||
|
|
520650081b | ||
|
|
a097ccebae | ||
|
|
fe4ccdf750 | ||
|
|
046d4dd4af | ||
|
|
d27beef500 | ||
|
|
85512541ad | ||
|
|
3ab5288ef2 | ||
|
|
d0dbf9163c | ||
|
|
a1478fac39 | ||
|
|
cc76708563 | ||
|
|
422e5245e4 | ||
|
|
e3ba569187 | ||
|
|
959a186a0f | ||
|
|
3b1c9e4320 | ||
|
|
a3a2c85c41 | ||
|
|
b1ac891210 | ||
|
|
da57183e0c | ||
|
|
f370289733 | ||
|
|
d1dc7a6ccf | ||
|
|
5639863715 | ||
|
|
1be4868875 | ||
|
|
368ff1afce | ||
|
|
3adf2d40b5 | ||
|
|
a6983f8bf3 | ||
|
|
4113b105a5 | ||
|
|
7442ff2dec | ||
|
|
666e77b22c | ||
|
|
8c12de6c56 | ||
|
|
b21fd86f6e | ||
|
|
f5f47f1cf5 | ||
|
|
ca39bff3c8 | ||
|
|
dd0edc19a0 | ||
|
|
5a76baabb3 | ||
|
|
373952a62c | ||
|
|
261b5201e0 | ||
|
|
890b2cfa17 | ||
|
|
f03f890511 | ||
|
|
553a36ac6f | ||
|
|
e6d849dd01 | ||
|
|
a1ac0a31de | ||
|
|
1368a1cdf1 | ||
|
|
91724750fb | ||
|
|
8febef6777 | ||
|
|
3bc338211a | ||
|
|
1b05dba80b | ||
|
|
3595ad0928 | ||
|
|
0af23e1466 | ||
|
|
cfcf1d30e2 | ||
|
|
6f8618b2f2 | ||
|
|
361f3469b8 |
24
.codecov.yml
24
.codecov.yml
@@ -1,10 +1,32 @@
|
||||
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: false
|
||||
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/
|
||||
|
||||
coverage:
|
||||
range: "70..85"
|
||||
|
||||
@@ -64,11 +64,13 @@ words:
|
||||
- blindings
|
||||
- bookdir
|
||||
- Bougalis
|
||||
- bthomee
|
||||
- Britto
|
||||
- Btrfs
|
||||
- Buildx
|
||||
- canonicality
|
||||
- canonicalised
|
||||
- cctools
|
||||
- changespq
|
||||
- checkme
|
||||
- choco
|
||||
@@ -110,6 +112,7 @@ words:
|
||||
- disablerepo
|
||||
- distro
|
||||
- doxyfile
|
||||
- dsymutil
|
||||
- dxrpl
|
||||
- elgamal
|
||||
- enabled
|
||||
@@ -139,6 +142,7 @@ words:
|
||||
- hwrap
|
||||
- ifndef
|
||||
- inequation
|
||||
- Injectivity
|
||||
- insuf
|
||||
- insuff
|
||||
- invasively
|
||||
@@ -168,6 +172,7 @@ words:
|
||||
- LOCALGOOD
|
||||
- logwstream
|
||||
- Lombrozo
|
||||
- lresolv
|
||||
- lseq
|
||||
- lsmf
|
||||
- ltype
|
||||
@@ -221,6 +226,7 @@ words:
|
||||
- Nyffenegger
|
||||
- onlatest
|
||||
- ostr
|
||||
- otool
|
||||
- oxalica
|
||||
- pargs
|
||||
- partitioner
|
||||
@@ -250,11 +256,15 @@ words:
|
||||
- Raphson
|
||||
- rcflags
|
||||
- replayer
|
||||
- repodata
|
||||
- repomd
|
||||
- rerandomize
|
||||
- rerandomization
|
||||
- rerandomized
|
||||
- rerandomizes
|
||||
- rerere
|
||||
- retargeted
|
||||
- retargets
|
||||
- retriable
|
||||
- RIPD
|
||||
- ripdtop
|
||||
@@ -290,6 +300,7 @@ words:
|
||||
- sles
|
||||
- soci
|
||||
- socidb
|
||||
- Sonatype
|
||||
- sponsee
|
||||
- sponsees
|
||||
- SRPMS
|
||||
@@ -309,6 +320,7 @@ words:
|
||||
- summands
|
||||
- superpeer
|
||||
- superpeers
|
||||
- Swatinem
|
||||
- takergets
|
||||
- takerpays
|
||||
- ters
|
||||
@@ -364,6 +376,7 @@ words:
|
||||
- wthread
|
||||
- xbridge
|
||||
- xchain
|
||||
- xcrun
|
||||
- ximinez
|
||||
- XMACRO
|
||||
- xored
|
||||
@@ -373,4 +386,6 @@ words:
|
||||
- xrplf
|
||||
- xxhash
|
||||
- xxhasher
|
||||
- zstdio
|
||||
- CGNAT
|
||||
- ungated
|
||||
|
||||
3
.envrc
3
.envrc
@@ -1,5 +1,8 @@
|
||||
watch_file nix/*.nix
|
||||
|
||||
# Pinned Rust toolchain, read by nix/packages.nix via fromRustupToolchainFile.
|
||||
watch_file rust-toolchain.toml
|
||||
|
||||
# The dev shell derivation includes all of conan/ (see nix/devshell.nix), so any
|
||||
# change in there has to invalidate direnv's cached environment.
|
||||
watch_dir conan
|
||||
|
||||
39
.github/actions/cargo-cache/action.yml
vendored
Normal file
39
.github/actions/cargo-cache/action.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
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 }}
|
||||
44
.github/actions/generate-version/action.yml
vendored
44
.github/actions/generate-version/action.yml
vendored
@@ -1,44 +0,0 @@
|
||||
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}"
|
||||
44
.github/actions/release-info/action.yml
vendored
Normal file
44
.github/actions/release-info/action.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
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.release_info.outputs.channel }}
|
||||
pkg_release:
|
||||
description: "The package release number: 1 for a tag, <run number>.<commit date>git<short commit hash> otherwise."
|
||||
value: ${{ steps.release_info.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}"
|
||||
|
||||
- name: Determine release channel and package release
|
||||
id: release_info
|
||||
uses: XRPLF/actions/release-info@7cc0e4a8d9d0b838f92c48d312856b190341bbba
|
||||
70
.github/actions/setup-nix-env/action.yml
vendored
Normal file
70
.github/actions/setup-nix-env/action.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
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.
|
||||
|
||||
# In RUNNER_TEMP, which the runner empties per job, like the `.conan2`
|
||||
# prepare-runner hands the system toolchain - but under its own name:
|
||||
# that Conan is a different version, and the two would migrate each
|
||||
# other's cache.
|
||||
echo "CONAN_HOME=${RUNNER_TEMP}/.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
|
||||
19
.github/dependabot.yml
vendored
19
.github/dependabot.yml
vendored
@@ -4,7 +4,8 @@ updates:
|
||||
directories:
|
||||
- /
|
||||
- .github/actions/build-deps/
|
||||
- .github/actions/generate-version/
|
||||
- .github/actions/cargo-cache/
|
||||
- .github/actions/release-info/
|
||||
- .github/actions/set-compiler-env/
|
||||
- .github/actions/setup-conan/
|
||||
schedule:
|
||||
@@ -19,3 +20,19 @@ 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:
|
||||
- "*"
|
||||
|
||||
4
.github/pull_request_template.md
vendored
4
.github/pull_request_template.md
vendored
@@ -18,7 +18,7 @@ If too broad, please consider splitting into multiple PRs.
|
||||
If there is a relevant task or issue, please link it here.
|
||||
-->
|
||||
|
||||
### Context of Change
|
||||
## Context of Change
|
||||
|
||||
<!--
|
||||
Please include the context of a change.
|
||||
@@ -29,7 +29,7 @@ If a refactor, how is this better than the previous implementation?
|
||||
If there is a spec or design document for this feature, please link it here.
|
||||
-->
|
||||
|
||||
### API Impact
|
||||
## API Impact
|
||||
|
||||
<!--
|
||||
Please check [x] relevant options, delete irrelevant ones.
|
||||
|
||||
@@ -82,7 +82,6 @@ test.app > xrpl.tx
|
||||
test.basics > test.jtx
|
||||
test.basics > xrpl.basics
|
||||
test.basics > xrpl.core
|
||||
test.basics > xrpld.rpc
|
||||
test.basics > xrpl.json
|
||||
test.basics > xrpl.protocol
|
||||
test.beast > xrpl.basics
|
||||
@@ -286,10 +285,10 @@ xrpld.perflog > xrpl.basics
|
||||
xrpld.perflog > xrpl.config
|
||||
xrpld.perflog > xrpl.core
|
||||
xrpld.perflog > xrpld.app
|
||||
xrpld.perflog > xrpld.rpc
|
||||
xrpld.perflog > xrpl.json
|
||||
xrpld.perflog > xrpl.nodestore
|
||||
xrpld.perflog > xrpl.protocol
|
||||
xrpld.perflog > xrpl.server
|
||||
xrpld.rpc > xrpl.basics
|
||||
xrpld.rpc > xrpl.config
|
||||
xrpld.rpc > xrpl.core
|
||||
|
||||
2
.github/scripts/rename/binary.sh
vendored
2
.github/scripts/rename/binary.sh
vendored
@@ -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/build/install.md
|
||||
${SED_COMMAND} -i -E 's@XRPLF/xrpld@XRPLF/rippled@g' docs/install.md
|
||||
|
||||
popd
|
||||
echo "Processing complete."
|
||||
|
||||
4
.github/scripts/rename/docs.sh
vendored
4
.github/scripts/rename/docs.sh
vendored
@@ -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/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/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/Doxyfile
|
||||
${SED_COMMAND} -i 's/ripple_basics/basics/' include/xrpl/basics/CountedObject.h
|
||||
${SED_COMMAND} -i 's/<ripple/<xrpl/' include/xrpl/protocol/AccountID.h
|
||||
|
||||
163
.github/scripts/strategy-matrix/generate.py
vendored
163
.github/scripts/strategy-matrix/generate.py
vendored
@@ -7,7 +7,21 @@ from pathlib import Path
|
||||
|
||||
THIS_DIR = Path(__file__).parent.resolve()
|
||||
|
||||
_BASE_CMAKE_ARGS = ["-Dtests=ON", "-Dwerr=ON", "-Dxrpld=ON", "-Dwextra=ON"]
|
||||
_BASE_CMAKE_ARGS = [
|
||||
"-Dtests=ON",
|
||||
"-Dwerr=ON",
|
||||
"-Dxrpld=ON",
|
||||
"-Dwextra=ON",
|
||||
"-Drust=ON",
|
||||
]
|
||||
|
||||
# The package formats a config can be packaged as, each with its own
|
||||
# install-test job in reusable-package.yml.
|
||||
PACKAGE_TYPES = ("deb", "rpm")
|
||||
|
||||
# The package name a variant suffixes, as build_pkg.py's BASE_NAME spells it:
|
||||
# the two have to agree, or the artifact globs miss what was built.
|
||||
BASE_NAME = "xrpld"
|
||||
|
||||
# Maps sanitizer names (as used in cmake) to short config-name suffixes.
|
||||
_SANITIZER_SUFFIX: dict[str, str] = {
|
||||
@@ -17,6 +31,19 @@ _SANITIZER_SUFFIX: dict[str, str] = {
|
||||
}
|
||||
|
||||
|
||||
def config_name(
|
||||
distro: str,
|
||||
compiler: str,
|
||||
build_type: str,
|
||||
arch: str,
|
||||
suffix: str = "",
|
||||
sanitizer: str = "",
|
||||
) -> str:
|
||||
"""Name a config. Its artifacts are named after it, so packaging reuses this."""
|
||||
parts = [s for s in [suffix, _SANITIZER_SUFFIX.get(sanitizer, "")] if s]
|
||||
return "-".join([f"{distro}-{compiler}-{build_type.lower()}-{arch}", *parts])
|
||||
|
||||
|
||||
def get_cmake_args(build_type: str, extra_args: str) -> str:
|
||||
"""Get the full list of CMake arguments for a config."""
|
||||
args = _BASE_CMAKE_ARGS.copy()
|
||||
@@ -31,17 +58,37 @@ def get_cmake_args(build_type: str, extra_args: str) -> str:
|
||||
|
||||
|
||||
# Every config must declare 'minimal'. Minimal configs form the reduced matrix
|
||||
# built for pull requests by default; the full matrix adds the rest. Packaging
|
||||
# configs declare it too, but packaging is gated in the workflow, not by it.
|
||||
# built for pull requests by default; the full matrix adds the rest.
|
||||
#
|
||||
# Configs may also opt into 'benchmark' to smoke-run the benchmarks. Note that
|
||||
# the flag applies to every entry a config expands into, so only set it on
|
||||
# configs that expand to a single combination.
|
||||
# Configs may also opt into 'benchmark' to smoke-run the benchmarks, or carry a
|
||||
# 'package' map to be packaged as well. Note that either applies to every entry
|
||||
# a config expands into, so only set them on configs that expand to a single
|
||||
# combination.
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class PackageConfig:
|
||||
"""The 'package' map of a config whose binaries are also packaged."""
|
||||
|
||||
type: str # has to match what the image provides
|
||||
# The packaging container image: a vanilla distro image, not the nix image
|
||||
# the config itself builds in.
|
||||
image: str
|
||||
# A flavour of the package, named xrpld-<variant>, for a config whose
|
||||
# binaries are not the plain release build. A variant needs no counterpart
|
||||
# in the other format.
|
||||
variant: str = ""
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
assert self.type in PACKAGE_TYPES, (
|
||||
f"unsupported package type {self.type!r}: "
|
||||
f"use one of {', '.join(PACKAGE_TYPES)}."
|
||||
)
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class LinuxConfig:
|
||||
"""One entry in linux.json's 'configs' or 'package_configs' arrays."""
|
||||
"""One entry in a linux.json 'configs' array."""
|
||||
|
||||
compiler: list[str]
|
||||
build_type: list[str]
|
||||
@@ -51,7 +98,11 @@ class LinuxConfig:
|
||||
sanitizers: list[str] = dataclasses.field(default_factory=list)
|
||||
suffix: str = ""
|
||||
extra_cmake_args: str = ""
|
||||
image: str = "" # only used by package_configs entries
|
||||
package: PackageConfig | None = None # set to also package this config
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if isinstance(self.package, dict):
|
||||
self.package = PackageConfig(**self.package)
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@@ -60,22 +111,16 @@ class LinuxFile:
|
||||
|
||||
image_tag: str
|
||||
configs: dict[str, list[LinuxConfig]] # distro → configs
|
||||
package_configs: dict[str, list[LinuxConfig]] # distro → packaging configs
|
||||
|
||||
@classmethod
|
||||
def load(cls, path: Path) -> "LinuxFile":
|
||||
data = json.loads(path.read_text())
|
||||
|
||||
def parse(section: dict) -> dict[str, list[LinuxConfig]]:
|
||||
return {
|
||||
distro: [LinuxConfig(**c) for c in cfgs]
|
||||
for distro, cfgs in section.items()
|
||||
}
|
||||
|
||||
return cls(
|
||||
image_tag=data["image_tag"],
|
||||
configs=parse(data["configs"]),
|
||||
package_configs=parse(data.get("package_configs", {})),
|
||||
configs={
|
||||
distro: [LinuxConfig(**c) for c in cfgs]
|
||||
for distro, cfgs in data["configs"].items()
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -88,6 +133,9 @@ 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):
|
||||
@@ -137,6 +185,7 @@ 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
|
||||
@@ -146,7 +195,9 @@ class PackagingEntry:
|
||||
xrpld_artifact_name: str
|
||||
validator_keys_artifact_name: str
|
||||
image: str
|
||||
distro: str # e.g. "debian" or "rhel"; drives package-format-specific steps
|
||||
package_type: str # "deb" or "rpm"; drives the format-specific steps
|
||||
package_variant: str # passed to build_pkg.py --variant; empty for xrpld
|
||||
package_name: str # the name it builds under, which the artifact globs use
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -187,13 +238,9 @@ def expand_linux_matrix(linux: LinuxFile, minimal: bool) -> list[MatrixEntry]:
|
||||
effective_sanitizers,
|
||||
effective_archs.items(),
|
||||
):
|
||||
name = f"{distro}-{compiler}-{build_type.lower()}-{arch}"
|
||||
suffix_parts = [
|
||||
s for s in [cfg.suffix, _SANITIZER_SUFFIX.get(sanitizer, "")] if s
|
||||
]
|
||||
if suffix_parts:
|
||||
name += "-" + "-".join(suffix_parts)
|
||||
|
||||
name = config_name(
|
||||
distro, compiler, build_type, arch, cfg.suffix, sanitizer
|
||||
)
|
||||
entries.append(
|
||||
MatrixEntry(
|
||||
config_name=name,
|
||||
@@ -213,33 +260,59 @@ 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.
|
||||
"""Generate the packaging matrix from the configs that carry a 'package' map.
|
||||
|
||||
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'.
|
||||
Packaging consumes the binaries that config's build job uploaded, so the
|
||||
artifact names come from the same config name, and a packaged config is one
|
||||
that passes -Dvalidator_keys=ON.
|
||||
|
||||
The artifact names must match what the build job uploads: one artifact per
|
||||
binary, each named after the build config.
|
||||
Packaging itself runs in vanilla distro images (debian:trixie, almalinux:10)
|
||||
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.
|
||||
"""
|
||||
entries = []
|
||||
for distro, configs in linux.package_configs.items():
|
||||
for distro, configs in linux.configs.items():
|
||||
for cfg in configs:
|
||||
for compiler, build_type in itertools.product(cfg.compiler, cfg.build_type):
|
||||
config_name = f"{distro}-{compiler}-{build_type.lower()}-amd64"
|
||||
if cfg.package is None:
|
||||
continue
|
||||
for compiler, build_type, arch in itertools.product(
|
||||
cfg.compiler, cfg.build_type, cfg.arch
|
||||
):
|
||||
# The packaging workflow hardcodes an amd64 runner.
|
||||
assert arch == "amd64", f"cannot package {distro} on {arch}"
|
||||
name = config_name(distro, compiler, build_type, arch, cfg.suffix)
|
||||
entries.append(
|
||||
PackagingEntry(
|
||||
xrpld_artifact_name=f"xrpld-{config_name}",
|
||||
validator_keys_artifact_name=f"validator-keys-{config_name}",
|
||||
image=cfg.image,
|
||||
distro=distro,
|
||||
xrpld_artifact_name=f"xrpld-{name}",
|
||||
validator_keys_artifact_name=f"validator-keys-{name}",
|
||||
image=cfg.package.image,
|
||||
package_type=cfg.package.type,
|
||||
package_variant=cfg.package.variant,
|
||||
package_name=(
|
||||
f"{BASE_NAME}-{cfg.package.variant}"
|
||||
if cfg.package.variant
|
||||
else BASE_NAME
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
return entries
|
||||
|
||||
|
||||
def package_names_by_type(entries: list[PackagingEntry]) -> dict[str, list[str]]:
|
||||
"""The names of the packages in 'entries', keyed by format.
|
||||
|
||||
Derived from the packaging matrix rather than listed again, so the packages
|
||||
the install-test jobs look for are the packages that were built.
|
||||
"""
|
||||
return {
|
||||
package_type: sorted(
|
||||
{e.package_name for e in entries if e.package_type == package_type}
|
||||
)
|
||||
for package_type in PACKAGE_TYPES
|
||||
}
|
||||
|
||||
|
||||
def expand_platform_matrix(pf: PlatformFile, minimal: bool) -> list[MatrixEntry]:
|
||||
"""Expand a PlatformFile (macOS or Windows) into matrix entries.
|
||||
|
||||
@@ -253,9 +326,12 @@ 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=f"{platform_name}-{arch}-{build_type.lower()}",
|
||||
config_name=name,
|
||||
cmake_args=get_cmake_args(build_type, cfg.extra_cmake_args),
|
||||
cmake_target="install" if is_windows else "all",
|
||||
build_only=cfg.build_only,
|
||||
@@ -263,6 +339,7 @@ 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
|
||||
@@ -304,6 +381,10 @@ if __name__ == "__main__":
|
||||
|
||||
if args.packaging:
|
||||
matrix = expand_linux_packaging(LinuxFile.load(THIS_DIR / "linux.json"))
|
||||
# One list per format, so each install-test job installs the packages its
|
||||
# own format produced.
|
||||
for package_type, names in package_names_by_type(matrix).items():
|
||||
print(f"{package_type}_package_names={json.dumps(names)}")
|
||||
else:
|
||||
if args.config in ("linux", None):
|
||||
matrix += expand_linux_matrix(
|
||||
|
||||
48
.github/scripts/strategy-matrix/linux.json
vendored
48
.github/scripts/strategy-matrix/linux.json
vendored
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"image_tag": "sha-a0074f8",
|
||||
"image_tag": "sha-060957e",
|
||||
"configs": {
|
||||
"ubuntu": [
|
||||
{
|
||||
@@ -71,7 +71,24 @@
|
||||
"build_type": ["Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false,
|
||||
"extra_cmake_args": "-Dvalidator_keys=ON"
|
||||
"extra_cmake_args": "-Dvalidator_keys=ON",
|
||||
"package": {
|
||||
"type": "deb",
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-49cdc10"
|
||||
}
|
||||
},
|
||||
{
|
||||
"compiler": ["gcc"],
|
||||
"build_type": ["Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false,
|
||||
"suffix": "assert",
|
||||
"extra_cmake_args": "-Dvalidator_keys=ON -Dassert=ON",
|
||||
"package": {
|
||||
"type": "deb",
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-49cdc10",
|
||||
"variant": "assert"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -81,28 +98,11 @@
|
||||
"build_type": ["Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false,
|
||||
"extra_cmake_args": "-Dvalidator_keys=ON"
|
||||
}
|
||||
]
|
||||
},
|
||||
"package_configs": {
|
||||
"debian": [
|
||||
{
|
||||
"compiler": ["gcc"],
|
||||
"build_type": ["Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false,
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-577d745"
|
||||
}
|
||||
],
|
||||
|
||||
"rhel": [
|
||||
{
|
||||
"compiler": ["gcc"],
|
||||
"build_type": ["Release"],
|
||||
"arch": ["amd64"],
|
||||
"minimal": false,
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-577d745"
|
||||
"extra_cmake_args": "-Dvalidator_keys=ON",
|
||||
"package": {
|
||||
"type": "rpm",
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-49cdc10"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
13
.github/scripts/strategy-matrix/macos.json
vendored
13
.github/scripts/strategy-matrix/macos.json
vendored
@@ -12,6 +12,19 @@
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
6
.github/workflows/build-nix-images.yml
vendored
6
.github/workflows/build-nix-images.yml
vendored
@@ -5,14 +5,13 @@ on:
|
||||
branches:
|
||||
- develop
|
||||
paths:
|
||||
- ".github/workflows/build-nix-images.yml"
|
||||
- "flake.nix"
|
||||
- "flake.lock"
|
||||
- "rust-toolchain.toml"
|
||||
- "nix/**"
|
||||
- "!nix/docker/README.md"
|
||||
- "!nix/devshell.nix"
|
||||
- "bin/check-tools.sh"
|
||||
- "!nix/check-tools/**"
|
||||
- "bin/default-loader-path.sh"
|
||||
- "bin/install-sanitizer-libs.sh"
|
||||
pull_request:
|
||||
@@ -24,6 +23,7 @@ on:
|
||||
- "nix/**"
|
||||
- "!nix/docker/README.md"
|
||||
- "!nix/devshell.nix"
|
||||
- "!nix/check-tools/**"
|
||||
- "bin/check-tools.sh"
|
||||
- "bin/default-loader-path.sh"
|
||||
- "bin/install-sanitizer-libs.sh"
|
||||
@@ -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@9e7e4e80af9e684c116b38369add8eea64451f32
|
||||
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@034e87065fcd0100214cf0672923bd38d193cf78
|
||||
with:
|
||||
image_name: xrpld/nix-${{ matrix.distro.name }}
|
||||
dockerfile: nix/docker/Dockerfile
|
||||
|
||||
19
.github/workflows/build-packaging-images.yml
vendored
19
.github/workflows/build-packaging-images.yml
vendored
@@ -6,13 +6,13 @@ on:
|
||||
- develop
|
||||
paths:
|
||||
- ".github/workflows/build-packaging-images.yml"
|
||||
- "package/Dockerfile"
|
||||
- "package/install-packaging-tools.sh"
|
||||
- "bin/install-packaging-tools.sh"
|
||||
- "package/docker/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/build-packaging-images.yml"
|
||||
- "package/Dockerfile"
|
||||
- "package/install-packaging-tools.sh"
|
||||
- "bin/install-packaging-tools.sh"
|
||||
- "package/docker/**"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
@@ -33,14 +33,17 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Newest of each distro: these images only wrap pre-built binaries, so
|
||||
# they set no floor for consumers. build_pkg.py pins the RPM dist tag.
|
||||
distro:
|
||||
- name: debian
|
||||
base_image: debian:bookworm
|
||||
base_image: debian:trixie
|
||||
# AlmaLinux rather than UBI, which does not ship rpm-sign.
|
||||
- name: rhel
|
||||
base_image: registry.access.redhat.com/ubi9/ubi:latest
|
||||
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@9e7e4e80af9e684c116b38369add8eea64451f32
|
||||
base_image: almalinux:10
|
||||
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@034e87065fcd0100214cf0672923bd38d193cf78
|
||||
with:
|
||||
image_name: xrpld/packaging-${{ matrix.distro.name }}
|
||||
dockerfile: package/Dockerfile
|
||||
dockerfile: package/docker/Dockerfile
|
||||
base_image: ${{ matrix.distro.base_image }}
|
||||
push: ${{ github.event_name == 'push' }}
|
||||
|
||||
2
.github/workflows/build-pre-commit-image.yml
vendored
2
.github/workflows/build-pre-commit-image.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@9e7e4e80af9e684c116b38369add8eea64451f32
|
||||
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@034e87065fcd0100214cf0672923bd38d193cf78
|
||||
with:
|
||||
image_name: xrpld/pre-commit
|
||||
dockerfile: bin/pre-commit/Dockerfile
|
||||
|
||||
80
.github/workflows/cargo-audit.yml
vendored
Normal file
80
.github/workflows/cargo-audit.yml
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
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-060957e
|
||||
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
|
||||
2
.github/workflows/check-tools.yml
vendored
2
.github/workflows/check-tools.yml
vendored
@@ -79,7 +79,7 @@ jobs:
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@c00c22ada3bd6bcda48fcb0d62fbbab49fec8a0f
|
||||
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
|
||||
24
.github/workflows/on-pr.yml
vendored
24
.github/workflows/on-pr.yml
vendored
@@ -77,24 +77,29 @@ jobs:
|
||||
|
||||
# Keep the paths below in sync with those in `on-trigger.yml`.
|
||||
.github/actions/build-deps/**
|
||||
.github/actions/generate-version/**
|
||||
.github/actions/release-info/**
|
||||
.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-test-install.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/**
|
||||
@@ -102,6 +107,9 @@ jobs:
|
||||
CMakeLists.txt
|
||||
conanfile.py
|
||||
conan.lock
|
||||
flake.lock
|
||||
flake.nix
|
||||
nix/**
|
||||
LICENSE.md
|
||||
package/**
|
||||
README.md
|
||||
@@ -168,6 +176,13 @@ 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
|
||||
@@ -175,6 +190,12 @@ jobs:
|
||||
# matrix (i.e. not yet labeled "Ready to merge" or "Full CI build").
|
||||
if: ${{ needs.should-run.outputs.go == 'true' && (github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'Ready to merge') || contains(github.event.pull_request.labels.*.name, 'Full CI build')) }}
|
||||
uses: ./.github/workflows/reusable-package.yml
|
||||
with:
|
||||
# A pull request builds packages to prove they still build, and publishes
|
||||
# nothing. Stated rather than left to the input's default, so that changing
|
||||
# that default cannot start publishing from pull requests. No secrets are
|
||||
# passed either, which is the second reason a publish here cannot succeed.
|
||||
publish: false
|
||||
|
||||
upload-recipe:
|
||||
needs:
|
||||
@@ -211,6 +232,7 @@ jobs:
|
||||
- check-rename
|
||||
- clang-tidy
|
||||
- build-test
|
||||
- rust
|
||||
- package
|
||||
- upload-recipe
|
||||
- notify-clio
|
||||
|
||||
18
.github/workflows/on-tag.yml
vendored
18
.github/workflows/on-tag.yml
vendored
@@ -1,5 +1,9 @@
|
||||
# This workflow uploads the libxrpl recipe to the Conan remote and builds
|
||||
# release packages when a versioned tag is pushed.
|
||||
# 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
|
||||
name: Tag
|
||||
|
||||
on:
|
||||
@@ -24,7 +28,7 @@ jobs:
|
||||
remote_password: ${{ secrets.NEXUS_REMOTE_PASSWORD }}
|
||||
|
||||
build-test:
|
||||
if: ${{ github.repository == 'XRPLF/rippled' }}
|
||||
if: ${{ github.repository_owner == 'XRPLF' }}
|
||||
uses: ./.github/workflows/reusable-build-test.yml
|
||||
strategy:
|
||||
fail-fast: true
|
||||
@@ -37,6 +41,12 @@ jobs:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
package:
|
||||
if: ${{ github.repository == 'XRPLF/rippled' }}
|
||||
if: ${{ github.repository_owner == 'XRPLF' }}
|
||||
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 }}
|
||||
|
||||
23
.github/workflows/on-trigger.yml
vendored
23
.github/workflows/on-trigger.yml
vendored
@@ -15,24 +15,29 @@ on:
|
||||
|
||||
# Keep the paths below in sync with those in `on-pr.yml`.
|
||||
- ".github/actions/build-deps/**"
|
||||
- ".github/actions/generate-version/**"
|
||||
- ".github/actions/release-info/**"
|
||||
- ".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-test-install.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/**"
|
||||
@@ -40,6 +45,9 @@ on:
|
||||
- "CMakeLists.txt"
|
||||
- "conanfile.py"
|
||||
- "conan.lock"
|
||||
- "flake.lock"
|
||||
- "flake.nix"
|
||||
- "nix/**"
|
||||
- "LICENSE.md"
|
||||
- "package/**"
|
||||
- "README.md"
|
||||
@@ -96,6 +104,11 @@ 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.
|
||||
@@ -108,3 +121,11 @@ 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 }}
|
||||
|
||||
4
.github/workflows/pre-commit.yml
vendored
4
.github/workflows/pre-commit.yml
vendored
@@ -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@3ba08d6ddf114092891d48491fc2e26c3ba15552
|
||||
uses: XRPLF/actions/.github/workflows/pre-commit.yml@279ec358f4a1be4088be3e024b07916fa97c75b6
|
||||
with:
|
||||
runs_on: ubuntu-latest
|
||||
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-f56b79f" }'
|
||||
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-473fe44" }'
|
||||
|
||||
6
.github/workflows/publish-docs.yml
vendored
6
.github/workflows/publish-docs.yml
vendored
@@ -41,13 +41,13 @@ env:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-a0074f8
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@c00c22ada3bd6bcda48fcb0d62fbbab49fec8a0f
|
||||
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
@@ -91,4 +91,4 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deploy
|
||||
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
|
||||
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
|
||||
|
||||
60
.github/workflows/reusable-build-test-config.yml
vendored
60
.github/workflows/reusable-build-test-config.yml
vendored
@@ -69,6 +69,12 @@ 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."
|
||||
@@ -111,6 +117,9 @@ 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' }}
|
||||
@@ -120,10 +129,15 @@ jobs:
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@c00c22ada3bd6bcda48fcb0d62fbbab49fec8a0f
|
||||
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
|
||||
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}"
|
||||
@@ -148,7 +162,21 @@ 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
|
||||
@@ -212,6 +240,24 @@ 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: |
|
||||
@@ -222,7 +268,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Upload the binary (Linux)
|
||||
if: ${{ github.event.repository.visibility == 'public' && runner.os == 'Linux' }}
|
||||
if: ${{ env.PACKAGING_ARTIFACTS_ENABLED == 'true' && runner.os == 'Linux' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: xrpld-${{ inputs.config_name }}
|
||||
@@ -236,7 +282,7 @@ jobs:
|
||||
run: ./validator-keys --unittest
|
||||
|
||||
- name: Upload the validator-keys binary
|
||||
if: ${{ github.event.repository.visibility == 'public' && env.VALIDATOR_KEYS_ENABLED == 'true' }}
|
||||
if: ${{ env.PACKAGING_ARTIFACTS_ENABLED == 'true' && env.VALIDATOR_KEYS_ENABLED == 'true' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: validator-keys-${{ inputs.config_name }}
|
||||
@@ -323,6 +369,11 @@ 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
|
||||
@@ -388,12 +439,13 @@ jobs:
|
||||
|
||||
- name: Upload coverage report
|
||||
if: ${{ github.repository_owner == 'XRPLF' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }}
|
||||
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
|
||||
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
|
||||
with:
|
||||
disable_search: true
|
||||
disable_telem: true
|
||||
fail_ci_if_error: true
|
||||
files: ${{ env.BUILD_DIR }}/coverage.xml
|
||||
flags: cpp
|
||||
plugins: noop
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
verbose: true
|
||||
|
||||
1
.github/workflows/reusable-build-test.yml
vendored
1
.github/workflows/reusable-build-test.yml
vendored
@@ -51,5 +51,6 @@ jobs:
|
||||
config_name: ${{ matrix.config_name }}
|
||||
sanitizers: ${{ matrix.sanitizers }}
|
||||
compiler: ${{ matrix.compiler || '' }}
|
||||
toolchain: ${{ matrix.toolchain || '' }}
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
18
.github/workflows/reusable-clang-tidy.yml
vendored
18
.github/workflows/reusable-clang-tidy.yml
vendored
@@ -27,14 +27,14 @@ jobs:
|
||||
determine-files:
|
||||
permissions:
|
||||
contents: read
|
||||
uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@d041ac9f1fa9f07a4ba335eb4c1c82233fb3fef6
|
||||
uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@70145243b905dc3e040a61d39c00e178cfb96f71
|
||||
|
||||
run-clang-tidy:
|
||||
name: Run clang tidy
|
||||
needs: [determine-files]
|
||||
if: ${{ needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.need_full_run == 'true' }}
|
||||
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
|
||||
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-a0074f8"
|
||||
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-060957e"
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@c00c22ada3bd6bcda48fcb0d62fbbab49fec8a0f
|
||||
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
@@ -59,6 +59,12 @@ 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
|
||||
|
||||
@@ -80,13 +86,13 @@ jobs:
|
||||
-Dwerr=ON \
|
||||
-Dxrpld=ON \
|
||||
-Dverify_headers=ON \
|
||||
-Drust=ON \
|
||||
..
|
||||
|
||||
# clang-tidy needs headers generated from proto files
|
||||
- name: Build libxrpl.libpb
|
||||
- name: Build clang-tidy prerequisites
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
run: |
|
||||
ninja -j ${{ steps.nproc.outputs.nproc }} xrpl.libpb
|
||||
ninja -j ${{ steps.nproc.outputs.nproc }} tidy_prerequisites
|
||||
|
||||
- name: Run clang tidy
|
||||
id: run_clang_tidy
|
||||
|
||||
120
.github/workflows/reusable-package-test-install.yml
vendored
Normal file
120
.github/workflows/reusable-package-test-install.yml
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
# Install one package format on every distro family it targets, one job per
|
||||
# package name and image, and run the binaries there. Called once per format by
|
||||
# reusable-package.yml, which owns the names and the image lists.
|
||||
name: Install packages
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
package_type:
|
||||
description: 'The package format to install ("deb" or "rpm").'
|
||||
required: true
|
||||
type: string
|
||||
package_names:
|
||||
description: "JSON array of package names built for this format."
|
||||
required: true
|
||||
type: string
|
||||
images:
|
||||
description: "JSON array of container images to install in."
|
||||
required: true
|
||||
type: string
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
env:
|
||||
PACKAGE_DIR: packages
|
||||
|
||||
jobs:
|
||||
install:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
package_name: ${{ fromJson(inputs.package_names) }}
|
||||
image: ${{ fromJson(inputs.images) }}
|
||||
name: "${{ matrix.package_name }} on ${{ matrix.image }}"
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ubuntu-latest
|
||||
container: ${{ matrix.image }}
|
||||
timeout-minutes: 5
|
||||
|
||||
steps:
|
||||
# Every package lands in one directory; the step below picks its own,
|
||||
# which keeps this independent of the artifact names.
|
||||
- name: Download package artifacts
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
pattern: "*-pkg"
|
||||
merge-multiple: true
|
||||
path: ${{ env.PACKAGE_DIR }}
|
||||
|
||||
- name: Find the package
|
||||
id: find
|
||||
env:
|
||||
PACKAGE_NAME: ${{ matrix.package_name }}
|
||||
PACKAGE_TYPE: ${{ inputs.package_type }}
|
||||
run: |
|
||||
# The version follows the name, separated by '_' in a DEB and '-' in an
|
||||
# RPM. Requiring a digit after it is what keeps 'xrpld' from picking up
|
||||
# another package, such as 'xrpld-assert'.
|
||||
pattern="${PACKAGE_NAME}[_-][0-9]*.${PACKAGE_TYPE}"
|
||||
package="$(find "${PACKAGE_DIR}" -type f -name "${pattern}" -print -quit)"
|
||||
test -n "${package}" || {
|
||||
echo "no ${pattern} found in ${PACKAGE_DIR}" >&2
|
||||
exit 1
|
||||
}
|
||||
echo "package=${package}" >>"${GITHUB_OUTPUT}"
|
||||
|
||||
# Debian 11 went end-of-life on 2026-08-31
|
||||
# (https://www.debian.org/News/2026/20260831) and its packages are
|
||||
# already partly gone from deb.debian.org, so switch to the
|
||||
# snapshot.debian.org entries the image ships commented out in its
|
||||
# sources.list: they are pinned to the snapshot the image was built
|
||||
# from, so they serve every version it needs and never go away.
|
||||
# Snapshots keep their original, long-passed Valid-Until, hence the
|
||||
# disabled check; the retries absorb snapshot.debian.org's throttling.
|
||||
- name: Switch Debian 11 to snapshot.debian.org
|
||||
if: ${{ matrix.image == 'debian:11' }}
|
||||
run: |
|
||||
sed -i 's|^deb |# deb |; s|^# deb http://snapshot|deb http://snapshot|' /etc/apt/sources.list
|
||||
printf '%s\n' \
|
||||
'Acquire::Check-Valid-Until "false";' \
|
||||
'Acquire::Retries "3";' \
|
||||
>/etc/apt/apt.conf.d/99snapshot
|
||||
|
||||
- name: Install the DEB
|
||||
if: ${{ inputs.package_type == 'deb' }}
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
PACKAGE: ${{ steps.find.outputs.package }}
|
||||
run: |
|
||||
# Stock Debian and Ubuntu images carry no package lists, so apt has
|
||||
# nothing to resolve the systemd dependency from until it fetches them.
|
||||
apt-get update -qq
|
||||
apt-get install -y "./${PACKAGE}"
|
||||
|
||||
- name: Install the RPM
|
||||
if: ${{ inputs.package_type == 'rpm' }}
|
||||
env:
|
||||
PACKAGE: ${{ steps.find.outputs.package }}
|
||||
run: dnf install -y "./${PACKAGE}"
|
||||
|
||||
- name: Run xrpld
|
||||
run: xrpld --version
|
||||
|
||||
- name: Run validator-keys
|
||||
run: validator-keys --version
|
||||
|
||||
- name: Run rippled, the legacy compatibility symlink
|
||||
run: rippled --version
|
||||
|
||||
- name: Check the service account
|
||||
run: id xrpld
|
||||
|
||||
- name: Check the state directory
|
||||
run: test -d /var/lib/xrpld
|
||||
|
||||
- name: Check the log directory
|
||||
run: test -d /var/log/xrpld
|
||||
185
.github/workflows/reusable-package.yml
vendored
185
.github/workflows/reusable-package.yml
vendored
@@ -1,17 +1,42 @@
|
||||
# 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.
|
||||
# Build, verify and publish Linux packages from the pre-built xrpld and
|
||||
# validator-keys artifacts, in three stages:
|
||||
#
|
||||
# - 'package' builds and signs one format per config that carries a "package"
|
||||
# map in linux.json; that map names the container image and the format
|
||||
# - 'test-install-deb' and 'test-install-rpm' call
|
||||
# reusable-package-test-install.yml to install what was built on a range of
|
||||
# distros and run the binaries there, so a package that cannot be installed
|
||||
# never reaches Nexus
|
||||
# - 'publish' uploads with the image's publish_pkg.py, doing a --dry-run
|
||||
# unless 'publish: true'
|
||||
#
|
||||
# Only linux/amd64 is supported; the runner is hardcoded in the jobs below.
|
||||
name: Package
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
pkg_release:
|
||||
description: "Package release number. Increment when repackaging the same executable."
|
||||
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."
|
||||
required: false
|
||||
type: string
|
||||
default: "1"
|
||||
default: https://packages-upload.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
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -19,12 +44,15 @@ defaults:
|
||||
|
||||
env:
|
||||
BUILD_DIR: build
|
||||
PACKAGE_DIR: packages
|
||||
|
||||
jobs:
|
||||
generate-matrix:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.generate.outputs.matrix }}
|
||||
deb_package_names: ${{ steps.generate.outputs.deb_package_names }}
|
||||
rpm_package_names: ${{ steps.generate.outputs.rpm_package_names }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
@@ -41,7 +69,7 @@ jobs:
|
||||
|
||||
package:
|
||||
needs: [generate-matrix]
|
||||
if: ${{ github.event.repository.visibility == 'public' }}
|
||||
if: ${{ github.event.repository.visibility == 'public' || startsWith(github.ref, 'refs/tags/') }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
|
||||
@@ -50,12 +78,17 @@ jobs:
|
||||
contents: read
|
||||
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
|
||||
container: ${{ matrix.image }}
|
||||
timeout-minutes: 30
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
- name: Download pre-built xrpld binary
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
@@ -71,17 +104,141 @@ 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: ${{ inputs.pkg_release }}
|
||||
run: ./package/build_pkg.sh
|
||||
PACKAGE_TYPE: ${{ matrix.package_type }}
|
||||
PACKAGE_VARIANT: ${{ matrix.package_variant }}
|
||||
PKG_RELEASE: ${{ steps.release_info.outputs.pkg_release }}
|
||||
CHANNEL: ${{ steps.release_info.outputs.channel }}
|
||||
run: |
|
||||
./package/build_pkg.py \
|
||||
--package-type "${PACKAGE_TYPE}" \
|
||||
--build-dir "${BUILD_DIR}" \
|
||||
--pkg-release "${PKG_RELEASE}" \
|
||||
--variant "${PACKAGE_VARIANT}" \
|
||||
--channel "${CHANNEL}"
|
||||
|
||||
# Before the upload, so the artifact, the tested package and the published
|
||||
# package are the same bytes.
|
||||
- name: Sign RPM
|
||||
if: ${{ inputs.publish && matrix.package_type == 'rpm' }}
|
||||
env:
|
||||
PKG_SIGNING_KEY: ${{ secrets.signing_key }}
|
||||
run: ./package/sign_rpm.py --package-dir "${BUILD_DIR}"
|
||||
|
||||
# Split from the debug symbols, which are an order of magnitude larger, so
|
||||
# that test-install downloads only what it installs. In the globs below the
|
||||
# version follows the name, separated by '_' in a DEB and '-' in an RPM. A
|
||||
# version starts with a digit and a longer name does not, so that one digit
|
||||
# is what tells 'xrpld-3.4.1-...' from 'xrpld-assert-3.4.1-...'.
|
||||
- name: Upload package artifact
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: ${{ matrix.xrpld_artifact_name }}-pkg
|
||||
path: |
|
||||
${{ env.BUILD_DIR }}/debbuild/*.deb
|
||||
${{ env.BUILD_DIR }}/debbuild/*.ddeb
|
||||
${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/*.rpm
|
||||
${{ env.BUILD_DIR }}/debbuild/${{ matrix.package_name }}_[0-9]*.deb
|
||||
${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/${{ matrix.package_name }}-[0-9]*.rpm
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload debug symbol artifact
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: ${{ matrix.xrpld_artifact_name }}-pkg-debug
|
||||
path: |
|
||||
${{ env.BUILD_DIR }}/debbuild/${{ matrix.package_name }}-dbgsym_[0-9]*.deb
|
||||
${{ env.BUILD_DIR }}/debbuild/${{ matrix.package_name }}-dbgsym_[0-9]*.ddeb
|
||||
${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/${{ matrix.package_name }}-debuginfo-[0-9]*.rpm
|
||||
if-no-files-found: error
|
||||
|
||||
# One call per format, so a variant packaged for one format is installed for
|
||||
# that format alone. The images are every distro family that format targets,
|
||||
# oldest release first, so both ends of the dependency range the packages
|
||||
# declare are exercised.
|
||||
test-install-deb:
|
||||
needs: [generate-matrix, package]
|
||||
name: install deb
|
||||
uses: ./.github/workflows/reusable-package-test-install.yml
|
||||
with:
|
||||
package_type: deb
|
||||
package_names: ${{ needs.generate-matrix.outputs.deb_package_names }}
|
||||
images: |
|
||||
[
|
||||
"debian:11",
|
||||
"debian:12",
|
||||
"debian:13",
|
||||
"ubuntu:20.04",
|
||||
"ubuntu:22.04",
|
||||
"ubuntu:24.04",
|
||||
"ubuntu:26.04"
|
||||
]
|
||||
|
||||
test-install-rpm:
|
||||
needs: [generate-matrix, package]
|
||||
name: install rpm
|
||||
uses: ./.github/workflows/reusable-package-test-install.yml
|
||||
with:
|
||||
package_type: rpm
|
||||
package_names: ${{ needs.generate-matrix.outputs.rpm_package_names }}
|
||||
images: |
|
||||
[
|
||||
"almalinux:9",
|
||||
"almalinux:10",
|
||||
"rockylinux/rockylinux:9",
|
||||
"rockylinux/rockylinux:10",
|
||||
"registry.access.redhat.com/ubi9/ubi",
|
||||
"registry.access.redhat.com/ubi10/ubi"
|
||||
]
|
||||
|
||||
publish:
|
||||
needs: [generate-matrix, package, test-install-deb, test-install-rpm]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
|
||||
# The name says which of the two this is, because the job runs either way:
|
||||
# with publish false it passes --dry-run and uploads nothing, and a job
|
||||
# called "publish ..." succeeding on a pull request reads like a release.
|
||||
name: "publish ${{ matrix.xrpld_artifact_name }}${{ !inputs.publish && ' (dry run)' || '' }}"
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
|
||||
container: ${{ matrix.image }}
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
# Both artifacts, so the debug symbols are published alongside the package.
|
||||
- name: Download package artifacts
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
pattern: ${{ matrix.xrpld_artifact_name }}-pkg*
|
||||
merge-multiple: true
|
||||
path: ${{ env.PACKAGE_DIR }}
|
||||
|
||||
- name: Determine release info
|
||||
id: release_info
|
||||
uses: ./.github/actions/release-info
|
||||
|
||||
- name: Publish package
|
||||
env:
|
||||
CHANNEL: ${{ steps.release_info.outputs.channel }}
|
||||
DRY_RUN_OPTION: ${{ !inputs.publish && '--dry-run' || '' }}
|
||||
NEXUS_URL: ${{ inputs.nexus_url }}
|
||||
NEXUS_USERNAME: ${{ inputs.publish && secrets.remote_username || '' }}
|
||||
NEXUS_PASSWORD: ${{ inputs.publish && secrets.remote_password || '' }}
|
||||
run: |
|
||||
publish_pkg.py \
|
||||
--channel "${CHANNEL}" \
|
||||
--package-dir "${PACKAGE_DIR}" \
|
||||
--nexus-url "${NEXUS_URL}" \
|
||||
${DRY_RUN_OPTION}
|
||||
|
||||
84
.github/workflows/reusable-rust.yml
vendored
Normal file
84
.github/workflows/reusable-rust.yml
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
# 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 and the cargo cache) matches what production builds
|
||||
# use. Coverage is the exception: it needs the nightly rustc that honours
|
||||
# #[coverage(off)], which the image carries alongside the pinned stable.
|
||||
#
|
||||
# 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-060957e
|
||||
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-060957e
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Use the nightly Rust toolchain
|
||||
run: rust-nightly path >>"${GITHUB_PATH}"
|
||||
|
||||
- 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@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
|
||||
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-060957e
|
||||
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
|
||||
19
.github/workflows/reusable-upload-recipe.yml
vendored
19
.github/workflows/reusable-upload-recipe.yml
vendored
@@ -40,7 +40,7 @@ defaults:
|
||||
jobs:
|
||||
upload:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-a0074f8
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
|
||||
env:
|
||||
REMOTE_NAME: ${{ inputs.remote_name }}
|
||||
CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.remote_username }}
|
||||
@@ -49,9 +49,14 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Generate build version number
|
||||
id: version
|
||||
uses: ./.github/actions/generate-version
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
- name: Determine release info
|
||||
id: release_info
|
||||
uses: ./.github/actions/release-info
|
||||
|
||||
- name: Set up Conan
|
||||
uses: ./.github/actions/setup-conan
|
||||
@@ -64,8 +69,8 @@ jobs:
|
||||
|
||||
- name: Upload Conan recipe (version)
|
||||
run: |
|
||||
conan export . --version=${{ steps.version.outputs.version }}
|
||||
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/${{ steps.version.outputs.version }}
|
||||
conan export . --version=${{ steps.release_info.outputs.version }}
|
||||
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/${{ steps.release_info.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 +97,4 @@ jobs:
|
||||
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/release
|
||||
|
||||
outputs:
|
||||
ref: xrpl/${{ steps.version.outputs.version }}
|
||||
ref: xrpl/${{ steps.release_info.outputs.version }}
|
||||
|
||||
13
.github/workflows/upload-conan-deps.yml
vendored
13
.github/workflows/upload-conan-deps.yml
vendored
@@ -68,10 +68,15 @@ jobs:
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@c00c22ada3bd6bcda48fcb0d62fbbab49fec8a0f
|
||||
uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82
|
||||
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
|
||||
|
||||
@@ -87,7 +92,9 @@ 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
|
||||
@@ -106,6 +113,10 @@ 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 }}"
|
||||
|
||||
12
.gitignore
vendored
12
.gitignore
vendored
@@ -72,11 +72,16 @@ DerivedData
|
||||
/.zed/
|
||||
|
||||
# AI tools.
|
||||
# Shared/committable AI agent config (AGENTS.md, CLAUDE.md, GEMINI.md, .claude/settings.json,
|
||||
# tool-specific rules files, etc.) should be checked in — see CONTRIBUTING.md. Only the
|
||||
# personal/local variants below are ignored.
|
||||
/.agent
|
||||
/.agents
|
||||
/.augment
|
||||
/.claude
|
||||
/CLAUDE.md
|
||||
/.claude/settings.local.json
|
||||
AGENTS.override.md
|
||||
CLAUDE.local.md
|
||||
GEMINI.local.md
|
||||
|
||||
# Python
|
||||
__pycache__
|
||||
@@ -89,3 +94,6 @@ target/
|
||||
|
||||
# clangd cache
|
||||
/.cache
|
||||
|
||||
# Rust build directory
|
||||
crates/target
|
||||
|
||||
@@ -62,6 +62,20 @@ 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
|
||||
- id: check-coverage-attrs
|
||||
name: check Rust coverage attributes
|
||||
entry: ./bin/pre-commit/check_rust_coverage_attrs.py
|
||||
language: python
|
||||
files: ^crates/.*\.rs$
|
||||
|
||||
- repo: https://github.com/BlankSpruce/gersemi-pre-commit
|
||||
rev: e98930bdc210d3387007f9252d8c1694ea7e410f # frozen: 0.27.7
|
||||
hooks:
|
||||
@@ -73,11 +87,27 @@ repos:
|
||||
- id: prettier
|
||||
args: [--end-of-line=auto]
|
||||
|
||||
# Scoped to package/: the rest of the repo's Python has pre-existing findings,
|
||||
# so widening these is its own change.
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: 7c55798a78262d14b2074abf623d8a992ebb70d4 # frozen: v0.16.2
|
||||
hooks:
|
||||
- id: ruff-check
|
||||
args: [--fix]
|
||||
files: ^package/.*\.py$
|
||||
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 4160603246a6b365d4a2af661c6d71b0a0f50478 # frozen: 26.5.1
|
||||
hooks:
|
||||
- id: black
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: 41e691678310dfd3833f7ab4e180ddb014310356 # frozen: v2.3.0
|
||||
hooks:
|
||||
- id: mypy
|
||||
args: [--strict]
|
||||
files: ^package/.*\.py$
|
||||
|
||||
- repo: https://github.com/scop/pre-commit-shfmt
|
||||
rev: 05c1426671b9237fb5e1444dd63aa5731bec0dfb # frozen: v3.13.1-1
|
||||
hooks:
|
||||
|
||||
42
AGENTS.md
Normal file
42
AGENTS.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# AGENTS.md
|
||||
|
||||
This file provides guidance to AI coding agents (Claude Code, and other AGENTS.md-compatible tools) when working with code in this repository.
|
||||
|
||||
## Build
|
||||
|
||||
Required on Linux/macOS: use the Nix devshell, which sets up the compiler, Conan, ccache, and (optionally) Rust automatically.
|
||||
|
||||
```bash
|
||||
nix develop
|
||||
```
|
||||
|
||||
For alternate devshell variants (specific compiler, no-compiler, coverage), see [docs/build/nix.md](./docs/build/nix.md). For the manual build steps, CMake options, and protocol codegen commands, see [BUILD.md](./BUILD.md) (`## Steps`, `## Options`, `## Code generation`).
|
||||
|
||||
Rust crate tests (independent of the CMake build): `cargo test --manifest-path crates/Cargo.toml --workspace` (CI uses `cargo nextest`).
|
||||
|
||||
## Testing
|
||||
|
||||
Unit tests are a custom framework built into the `xrpld` binary itself (not Boost.Test/GTest/Catch); see [CONTRIBUTING.md](./CONTRIBUTING.md#unit-tests) for the basic invocation. Notes not covered there:
|
||||
|
||||
- A suite's `--unittest` name is built from the arguments to its `BEAST_DEFINE_TESTSUITE`/`BEAST_DEFINE_TESTSUITE_PRIO` macro (usually at the bottom of the test file), in reverse order and joined with `.`: `BEAST_DEFINE_TESTSUITE(Credentials, app, xrpl)` → `xrpl.app.Credentials`.
|
||||
- `--unittest-arg` does nothing — don't use it.
|
||||
- Tests that run offline in under a minute should be automatic `--unittest` suites; anything else is a manual/integration test.
|
||||
- New tests should be written using `gtest` under `src/tests/` unless that isn't possible, in which case fall back to the legacy Beast framework under `src/test/`. `tests/` (top-level) holds integration tests exercised against `libxrpl`/`xrpld`.
|
||||
|
||||
## Lint/Format
|
||||
|
||||
See [CONTRIBUTING.md](./CONTRIBUTING.md#pre-commit-hooks) for `pre-commit` setup and [CONTRIBUTING.md](./CONTRIBUTING.md#clang-tidy) for `clang-tidy` (opt-in, needs local `clang-tidy` and generated headers).
|
||||
|
||||
## Code Style
|
||||
|
||||
New file placement and header levelization: see [CONTRIBUTING.md](./CONTRIBUTING.md#before-making-a-pull-request). Braces, whitespace, member order, and other conventions: see [docs/CodingStyle.md](./docs/CodingStyle.md). `XRPL_ASSERT`/`UNREACHABLE` contracts: see [CONTRIBUTING.md](./CONTRIBUTING.md#contracts-and-instrumentation). Commit messages: see [CONTRIBUTING.md](./CONTRIBUTING.md#good-commit-messages).
|
||||
|
||||
## Architecture
|
||||
|
||||
Paths below reflect the current layout; update this section if modularization moves a subsystem to a different directory.
|
||||
|
||||
- `include/xrpl/` + `src/libxrpl/` — the core protocol library: ledger, shamap, consensus, crypto, json, resource, nodestore, rdb, peerfinder, and `tx/` (transaction application: `Transactor.cpp`, `applySteps.cpp`, invariants, payment paths). `tx/transactors/` has one file per transaction type, grouped by subsystem: `escrow/`, `vault/`, `lending/`, `sponsor/`, `nft/`, `token/` (MPT), `payment_channel/`, `permissioned_domain/`, `dex/`, `oracle/`, `did/`, `credentials/`, `bridge/`, `check/`, `delegate/`, `account/`, `system/`. Any change to transaction-processing behavior must be gated behind an Amendment.
|
||||
- `src/xrpld/` — the server application built on top of `libxrpl`: `app`, `core`, `overlay` (P2P networking), `peerfinder`, `perflog`, `rpc`, `shamap`. `main` builds an `ApplicationImp` implementing `Application`; most components hold a reference to it (`app_`), giving broad cross-component access — expect to trace call chains through `Application&`.
|
||||
- `src/test/` — unit tests mirroring the subsystems above, plus `jtx/` (the transaction-building test DSL — e.g. `jtx/escrow.h`, `jtx/vault.h`, `jtx/sponsor.h`, `jtx/permissioned_dex.h`) and `unit_test/` (the custom test framework itself, derived from Beast).
|
||||
- `src/tests/` — unit tests for `libxrpl` written in `gtest`, gradually replacing the `src/test` equivalents.
|
||||
- `crates/` — a Rust workspace (only built with `-Dxrpld -Drust=ON`) bridged into C++ via `cxxbridge`/the `cxx` crate; currently just a `hello_world` interop scaffold. Requires the Rust toolchain pinned in `rust-toolchain.toml` (the Nix devshell provides it automatically).
|
||||
@@ -22,21 +22,49 @@ API version 2 is available in `xrpld` version 2.0.0 and later. See [API-VERSION-
|
||||
|
||||
This version is supported by all `xrpld` versions. For WebSocket and HTTP JSON-RPC requests, it is currently the default API version used when no `api_version` is specified.
|
||||
|
||||
## Unreleased
|
||||
## XRP Ledger server version 3.4.0
|
||||
|
||||
This section contains changes targeting a future version.
|
||||
Version 3.4.0 is not yet released. These changes are available in the 3.4.0 beta releases.
|
||||
|
||||
### Breaking changes
|
||||
### Additions in 3.4.0
|
||||
|
||||
- `feature`: In admin-mode responses, the `vetoed` field is now always a boolean. Disabled obsolete amendments now have `"vetoed": true` and a new `"obsolete": true` field, instead of the previous `"vetoed": "Obsolete"` string value. This change improves type safety for API clients. Both `vetoed` and `obsolete` fields are only present in admin-mode responses for disabled amendments.
|
||||
- `ledger`: `nftoken_id`, `nftoken_ids`, and `offer_id` are now included in transaction metadata when transactions are expanded (`expand`, or admin-only `full`), matching the `tx`, `account_tx`, and `subscribe` (`transactions` stream) responses. ([#5706](https://github.com/XRPLF/rippled/pull/5706))
|
||||
|
||||
### Additions
|
||||
### Bugfixes in 3.4.0
|
||||
|
||||
- `account_tx`: Added an optional `delegate` request object to filter delegated transactions. The object requires `delegate_filter`, which must be either `actor` for transactions owned by the requested account but signed by another account, or `authorizer` for transactions signed by the requested account on behalf of another account. The optional `counter_party` account narrows the results to a specific signer/delegate for `actor` or a specific owner/delegator for `authorizer`. Malformed `delegate`, `delegate_filter`, and `counter_party` values return standard invalid field errors, and invalid account IDs return `actMalformed`.
|
||||
When paginating delegate-filtered queries, a marker from a delegate-filtered query includes a `delegate` flag and is only valid for follow-up requests that also supply `delegate` (mixing marker conventions returns `invalidParams`). Because filtering is applied after the ledger scan, a page may contain fewer results than `limit` (possibly zero) while still returning a marker, so callers must continue until no marker is present.
|
||||
- `sign`, `sign_for`, `submit`: `signature_target` now returns `invalidParams` unless it names `CounterpartySignature` or `SponsorSignature`. It previously accepted any inner object field, such as `Book` or `NFToken`, and signed into it.
|
||||
- `sign`, `sign_for`, `submit`, `submit_multisigned`: With `fixCleanup3_4_0` enabled, a signature in `CounterpartySignature` or `SponsorSignature` covers a different prefix than the transaction's own signature, so a signature can no longer be moved from one of those roles into another. Clients that build these signatures themselves must use the new prefixes: `CPT` and `CPM` (single- and multi-signing) for `CounterpartySignature`, and `SPN` and `SPM` for `SponsorSignature`.
|
||||
- `get_aggregate_price`: Duplicate entries in the `oracles` request array are now ignored. [#6586](https://github.com/XRPLF/rippled/pull/6586)
|
||||
- `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)
|
||||
- `ledger`: `delivered_amount` is now included in the metadata of successful `AccountDelete` transactions when transactions are expanded (`expand`, or admin-only `full`). Previously it was only added for `Payment` and `CheckCash`, which made `ledger` inconsistent with `tx` and `account_tx`. [#5706](https://github.com/XRPLF/rippled/pull/5706)
|
||||
- `noripple_check`: The `transactions` field is no longer included in error responses; it is still returned (possibly as an empty array) whenever `transactions` is `true` and the request succeeds. A malformed `account` is now rejected before the ledger is looked up, so that error response no longer carries the `ledger_hash`, `ledger_index`, and `validated` fields ([#6303](https://github.com/XRPLF/rippled/pull/6303)).
|
||||
- `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. ([#6304](https://github.com/XRPLF/rippled/pull/6304))
|
||||
|
||||
## XRP Ledger server version 3.3.0
|
||||
|
||||
[Version 3.3.0](https://github.com/XRPLF/rippled/releases/tag/3.3.0) was released on Aug 6, 2026.
|
||||
|
||||
### Additions in 3.3.0
|
||||
|
||||
- `account_tx`: Added an optional `delegate` request object to filter delegated transactions. The object requires `delegate_filter`, which must be either `actor` for transactions owned by the requested account but signed by another account, or `authorizer` for transactions signed by the requested account on behalf of another account. The optional `counter_party` account narrows the results to a specific signer/delegate for `actor` or a specific owner/delegator for `authorizer`. Malformed `delegate`, `delegate_filter`, and `counter_party` values return standard invalid field errors, and invalid account IDs return `actMalformed`. When paginating delegate-filtered queries, a marker from a delegate-filtered query includes a `delegate` flag and is only valid for follow-up requests that also supply `delegate` (mixing marker conventions returns `invalidParams`). Because filtering is applied after the ledger scan, a page may contain fewer results than `limit` (possibly zero) while still returning a marker, so callers must continue until no marker is present. ([#6126](https://github.com/XRPLF/rippled/pull/6126))
|
||||
|
||||
## XRP Ledger server version 3.2.1
|
||||
|
||||
[Version 3.2.1](https://github.com/XRPLF/rippled/releases/tag/3.2.1) was released on Aug 1, 2026.
|
||||
|
||||
This release contains bug fixes only and no API changes.
|
||||
|
||||
## XRP Ledger server version 3.2.0
|
||||
|
||||
[Version 3.2.0](https://github.com/XRPLF/rippled/releases/tag/3.2.0) was released on Jun 16, 2026.
|
||||
|
||||
### Additions in 3.2.0
|
||||
|
||||
- `ledger_entry`, `account_objects`: The `Delegate` ledger entry now includes an optional `DestinationNode` field, which stores the index into the authorized account's owner directory. This field is present on entries created after bidirectional directory tracking was introduced and may appear in RPC responses for those entries. ([#6681](https://github.com/XRPLF/rippled/pull/6681))
|
||||
|
||||
- `server_definitions`: Added the following new sections to the response ([#6321](https://github.com/XRPLF/rippled/pull/6321)):
|
||||
- `TRANSACTION_FORMATS`: Describes the fields and their optionality for each transaction type, including common fields shared across all transactions.
|
||||
- `LEDGER_ENTRY_FORMATS`: Describes the fields and their optionality for each ledger entry type, including common fields shared across all ledger entries.
|
||||
@@ -44,9 +72,8 @@ This section contains changes targeting a future version.
|
||||
- `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.
|
||||
|
||||
### Bugfixes
|
||||
### Bugfixes in 3.2.0
|
||||
|
||||
- `get_aggregate_price`: Duplicate entries in the `oracles` request array are now ignored. [#6586](https://github.com/XRPLF/rippled/pull/6586)
|
||||
- Peer Crawler: The `port` field in `overlay.active[]` now consistently returns an integer instead of a string for outbound peers. [#6318](https://github.com/XRPLF/rippled/pull/6318)
|
||||
- `ping`: The `ip` field is no longer returned as an empty string for proxied connections without a forwarded-for header. It is now omitted, consistent with the behavior for identified connections. [#6730](https://github.com/XRPLF/rippled/pull/6730)
|
||||
- gRPC `GetLedgerDiff`: Fixed error message that incorrectly said "base ledger not validated" when the desired ledger was not validated. [#6730](https://github.com/XRPLF/rippled/pull/6730)
|
||||
@@ -58,8 +85,24 @@ 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)
|
||||
- `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)
|
||||
|
||||
## XRP Ledger server version 3.1.3
|
||||
|
||||
[Version 3.1.3](https://github.com/XRPLF/rippled/releases/tag/3.1.3) was released on May 8, 2026.
|
||||
|
||||
This release contains bug fixes only and no API changes.
|
||||
|
||||
## XRP Ledger server version 3.1.2
|
||||
|
||||
[Version 3.1.2](https://github.com/XRPLF/rippled/releases/tag/3.1.2) was released on Mar 12, 2026.
|
||||
|
||||
This release contains bug fixes only and no API changes.
|
||||
|
||||
## XRP Ledger server version 3.1.1
|
||||
|
||||
[Version 3.1.1](https://github.com/XRPLF/rippled/releases/tag/3.1.1) was released on Feb 23, 2026.
|
||||
|
||||
This release contains bug fixes only and no API changes.
|
||||
|
||||
## XRP Ledger server version 3.1.0
|
||||
|
||||
|
||||
25
BUILD.md
25
BUILD.md
@@ -304,6 +304,7 @@ 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. |
|
||||
@@ -316,6 +317,30 @@ 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
|
||||
|
||||
@@ -158,7 +158,13 @@ if(coverage)
|
||||
include(XrplCov)
|
||||
endif()
|
||||
|
||||
add_custom_target(tidy_prerequisites)
|
||||
|
||||
if(rust)
|
||||
add_subdirectory(crates)
|
||||
endif()
|
||||
include(XrplCore)
|
||||
|
||||
include(XrplProtocolAutogen)
|
||||
include(XrplInstall)
|
||||
include(XrplValidatorKeys)
|
||||
|
||||
@@ -59,6 +59,17 @@ to an existing XLS. Neither change will be released (in an amendment's
|
||||
case, marked as `Supported::yes`) until the corresponding XLS's status
|
||||
is `Final`.
|
||||
|
||||
## AI coding agents
|
||||
|
||||
[`AGENTS.md`](./AGENTS.md) (and its `CLAUDE.md` symlink, for Claude Code) holds shared, checked-in guidance for AI coding agents working in this repository — build/test/lint commands and architecture notes. Additional `AGENTS.md` files may exist in subdirectories to give agents context specific to that part of the codebase; whenever you add one, also add a `CLAUDE.md` symlink pointing to it (`ln -s AGENTS.md CLAUDE.md`) so Claude Code picks it up too.
|
||||
|
||||
If you want to give an agent personal instructions that shouldn't be shared with other contributors (e.g. your own workflow preferences), those are gitignored, not checked in:
|
||||
|
||||
- `CLAUDE.local.md` — read by Claude Code alongside `CLAUDE.md`.
|
||||
- `AGENTS.override.md` — read by AGENTS.md-compatible tools that support a personal override file layered on top of `AGENTS.md`.
|
||||
|
||||
Likewise, `.claude/settings.local.json` is for personal, untracked Claude Code settings, while `.claude/settings.json` is shared.
|
||||
|
||||
## Before making a pull request
|
||||
|
||||
(Or marking a draft pull request as ready.)
|
||||
@@ -82,7 +93,7 @@ If you create new source files, they must be organized as follows:
|
||||
under `include/xrpl`, and source (`.cpp`) files must go under
|
||||
`src/libxrpl`.
|
||||
- All other non-test files must go under `src/xrpld`.
|
||||
- All test source files must go under `src/test`.
|
||||
- New test source files should use `gtest` and go under `src/tests`, unless that isn't possible, in which case they should use our legacy test framework and go under `src/test`.
|
||||
- All benchmark source files must go under `src/benchmarks`.
|
||||
|
||||
The source must be formatted according to the style guide below. The easiest
|
||||
@@ -225,8 +236,9 @@ 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` — run tools from your own environment; see
|
||||
[Installing clang-tidy](#installing-clang-tidy) for how to get those.
|
||||
`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.
|
||||
|
||||
To get started, install `pre-commit` and enable the git hook scripts:
|
||||
|
||||
@@ -255,6 +267,7 @@ 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
|
||||
|
||||
@@ -319,7 +332,11 @@ See the [environment setup guide](./docs/build/environment.md#clang-tidy) for ho
|
||||
|
||||
### Running clang-tidy locally
|
||||
|
||||
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.
|
||||
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
|
||||
```
|
||||
|
||||
#### Via pre-commit (recommended)
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ 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.
|
||||
|
||||
111
bin/check-nix-store-refs.sh
Executable file
111
bin/check-nix-store-refs.sh
Executable file
@@ -0,0 +1,111 @@
|
||||
#!/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
|
||||
@@ -158,6 +158,7 @@ if [ "${os}" = "linux" ] || [ "${os}" = "macos" ]; then
|
||||
check cargo-nextest cargo nextest --version
|
||||
check clippy-driver
|
||||
check rust-analyzer
|
||||
check rust-nightly rust-nightly run rustc --version
|
||||
check rustc
|
||||
check rustfmt
|
||||
fi
|
||||
|
||||
@@ -25,32 +25,38 @@ esac
|
||||
# Packaging runs in a vanilla distro image, so the tooling comes from the distro's
|
||||
# archive rather than from nixpkgs:
|
||||
#
|
||||
# - debhelper and dpkg-dev build the DEB
|
||||
# - debhelper and dpkg-dev build the DEB, and lintian checks it
|
||||
# - binutils gives debian/rules the readelf its glibc-floor check runs; it
|
||||
# already arrives via dpkg-dev, but that tool is called directly
|
||||
# - rpm-build builds the RPM, with systemd-rpm-macros and redhat-rpm-config
|
||||
# supplying the systemd and find-debuginfo macros the spec uses
|
||||
# - git gives build_pkg.sh a real history to read SOURCE_DATE_EPOCH from;
|
||||
# without one the timestamp falls back to the wall clock
|
||||
# - curl uploads the finished packages in publish_pkg.sh
|
||||
# - ca-certificates lets curl and git verify TLS
|
||||
# - rpm-sign and gnupg2 sign the built RPM
|
||||
# - python3 runs the packaging scripts
|
||||
# - git gives build_pkg.py the commit timestamp it stamps files with
|
||||
# - ca-certificates lets git and the packaging scripts verify TLS
|
||||
function install() {
|
||||
case "${ID}" in
|
||||
debian | ubuntu)
|
||||
apt-get update -y
|
||||
apt-get install -y --no-install-recommends \
|
||||
binutils \
|
||||
ca-certificates \
|
||||
curl \
|
||||
debhelper \
|
||||
debhelper-compat \
|
||||
dpkg-dev \
|
||||
git
|
||||
git \
|
||||
lintian \
|
||||
python3
|
||||
;;
|
||||
|
||||
rhel | centos | rocky | almalinux)
|
||||
dnf install -y --setopt=install_weak_deps=False \
|
||||
curl-minimal \
|
||||
git \
|
||||
rpm-build \
|
||||
gnupg2 \
|
||||
python3 \
|
||||
redhat-rpm-config \
|
||||
rpm-build \
|
||||
rpm-sign \
|
||||
systemd-rpm-macros
|
||||
;;
|
||||
esac
|
||||
149
bin/pre-commit/check_rust_coverage_attrs.py
Executable file
149
bin/pre-commit/check_rust_coverage_attrs.py
Executable file
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Check that Rust unit tests stay out of the coverage report.
|
||||
|
||||
cargo-llvm-cov instruments the test code along with everything else, so a test
|
||||
module that is not excluded counts its own body as covered and inflates the
|
||||
reported number. Excluding it takes two attributes:
|
||||
|
||||
* every `#[cfg(test)]` module carries
|
||||
`#[cfg_attr(coverage_nightly, coverage(off))]`;
|
||||
* every crate root (lib.rs, main.rs) carries
|
||||
`#![cfg_attr(coverage_nightly, feature(coverage_attribute))]`, which the
|
||||
attribute above needs in order to compile.
|
||||
|
||||
Both are inert outside the coverage job: cargo-llvm-cov defines
|
||||
`coverage_nightly` only when it runs on a nightly toolchain.
|
||||
|
||||
The crate-root gate is checked even in a crate that has no tests yet, because
|
||||
that is what lets the first test module added later carry the attribute without
|
||||
a build failure. Missing it is a hard error, so it cannot go unnoticed; a
|
||||
missing `coverage(off)` fails open, which is why this check exists.
|
||||
|
||||
Matching is on exact attribute text, which works because `cargo fmt` runs over
|
||||
the whole workspace in the hook ahead of this one: rustfmt puts every attribute
|
||||
on its own line and normalizes what is inside it, turning `#[cfg( test )]`
|
||||
and `#[cfg(test,)]` alike into `#[cfg(test)]`. So there is nothing here that
|
||||
parses Rust. The price is that a cfg this file does not spell out literally --
|
||||
`all(test, ...)`, `any(test, ...)`, `not(test)` -- is reported rather than
|
||||
classified, on the grounds that guessing at coverage semantics is how a check
|
||||
like this ends up quietly wrong.
|
||||
|
||||
Usage: ./bin/pre-commit/check_rust_coverage_attrs.py <file1> <file2> ...
|
||||
|
||||
Exit status is non-zero if any violation is found.
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
CRATE_ROOTS = {"lib.rs", "main.rs"}
|
||||
|
||||
FEATURE_ATTR = "#![cfg_attr(coverage_nightly, feature(coverage_attribute))]"
|
||||
COVERAGE_OFF_ATTR = "#[cfg_attr(coverage_nightly, coverage(off))]"
|
||||
CFG_TEST_ATTR = "#[cfg(test)]"
|
||||
|
||||
# Any other cfg that mentions `test`. String literals are blanked before this
|
||||
# runs, so `feature = "test"` does not read as the `test` cfg.
|
||||
RE_CFG_MENTIONS_TEST = re.compile(r"^#\[cfg\(.*\btest\b.*\)\]$")
|
||||
RE_STRING = re.compile(r'"(?:[^"\\]|\\.)*"')
|
||||
RE_MOD = re.compile(r"^(?:pub(?:\([^)]*\))?\s+)?mod\s+([A-Za-z_]\w*)")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Finding:
|
||||
line: int
|
||||
label: str
|
||||
message: str
|
||||
|
||||
|
||||
def _check_module(attrs: list[str], line: int, name: str) -> list[Finding]:
|
||||
"""Findings for one module, given the attributes attached to it."""
|
||||
if COVERAGE_OFF_ATTR in attrs:
|
||||
return [] # excluded from coverage; which cfg gates it does not matter
|
||||
if CFG_TEST_ATTR in attrs:
|
||||
return [
|
||||
Finding(
|
||||
line,
|
||||
"missing-coverage-off",
|
||||
f"`mod {name}` is #[cfg(test)] but not excluded from coverage; "
|
||||
f"add {COVERAGE_OFF_ATTR}",
|
||||
)
|
||||
]
|
||||
unclassified = [
|
||||
attr for attr in attrs if RE_CFG_MENTIONS_TEST.match(RE_STRING.sub('""', attr))
|
||||
]
|
||||
if unclassified:
|
||||
return [
|
||||
Finding(
|
||||
line,
|
||||
"unclassified-cfg",
|
||||
f"`mod {name}` is gated on {unclassified[0]}, which this check "
|
||||
f"cannot tell apart from a module that ships in the library; "
|
||||
f"add {COVERAGE_OFF_ATTR} if it is test-only, or teach this "
|
||||
f"check the cfg if it is not",
|
||||
)
|
||||
]
|
||||
return []
|
||||
|
||||
|
||||
def _check_test_modules(lines: list[str]) -> list[Finding]:
|
||||
"""Findings for every test module that is not excluded from coverage."""
|
||||
findings: list[Finding] = []
|
||||
attrs: list[str] = []
|
||||
attrs_line = 0
|
||||
for number, raw in enumerate(lines, start=1):
|
||||
stripped = raw.strip()
|
||||
# Blank lines and comments are allowed between an attribute and its item.
|
||||
if not stripped or stripped.startswith("//"):
|
||||
continue
|
||||
if stripped.startswith("#["):
|
||||
if not attrs:
|
||||
attrs_line = number
|
||||
attrs.append(stripped)
|
||||
continue
|
||||
module = RE_MOD.match(stripped)
|
||||
if module is not None and attrs:
|
||||
findings += _check_module(attrs, attrs_line, module.group(1))
|
||||
attrs = []
|
||||
return findings
|
||||
|
||||
|
||||
def _check_crate_root(name: str, lines: list[str]) -> list[Finding]:
|
||||
"""A finding if a crate root is missing the coverage_attribute feature gate."""
|
||||
if name not in CRATE_ROOTS:
|
||||
return []
|
||||
if any(line.strip() == FEATURE_ATTR for line in lines):
|
||||
return []
|
||||
return [
|
||||
Finding(
|
||||
1,
|
||||
"missing-feature-gate",
|
||||
f"crate root is missing {FEATURE_ATTR}",
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def check_source(name: str, text: str) -> list[Finding]:
|
||||
"""Findings for one file's contents; `name` is its base name (lib.rs, ...)."""
|
||||
lines = text.splitlines()
|
||||
return _check_crate_root(name, lines) + _check_test_modules(lines)
|
||||
|
||||
|
||||
def check_file(path: Path) -> list[Finding]:
|
||||
return check_source(path.name, path.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def main() -> int:
|
||||
total = 0
|
||||
for path in (Path(name) for name in sys.argv[1:]):
|
||||
for finding in check_file(path):
|
||||
total += 1
|
||||
print(f"{path}:{finding.line}: {finding.label}: {finding.message}")
|
||||
return 1 if total else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -1094,8 +1094,8 @@
|
||||
# Default is 100.
|
||||
#
|
||||
# back_off_milliseconds
|
||||
# Number of milliseconds to wait between
|
||||
# online_delete batches to allow other functions
|
||||
# Number of milliseconds to wait between online_delete
|
||||
# SQL deletion batches to allow other functions
|
||||
# to catch up.
|
||||
# Default is 100.
|
||||
#
|
||||
@@ -1109,10 +1109,22 @@
|
||||
# The online delete process checks periodically
|
||||
# that xrpld is still in sync with the network,
|
||||
# and that the validated ledger is less than
|
||||
# 'age_threshold_seconds' old. If not, then continue
|
||||
# 'age_threshold_seconds' old, and that all
|
||||
# recent ledgers are available. If not, then continue
|
||||
# sleeping for this number of seconds and
|
||||
# checking until healthy.
|
||||
# Default is 5.
|
||||
# Default is 2.
|
||||
#
|
||||
# max_waiting_ledgers
|
||||
# The maximum number of ledgers that may be validated
|
||||
# while online deletion is waiting for the node to get
|
||||
# fully synced with the rest of the network. If more than
|
||||
# this number of ledgers are validated while waiting, then
|
||||
# online deletion gives up on the current ledger and tries
|
||||
# again later. Note this only affects situations that cause
|
||||
# rotation to wait, such as going out of sync, or missing
|
||||
# ledgers. Forward progress is not penalized. Minimum is 64.
|
||||
# Default is the online_delete value.
|
||||
#
|
||||
# Notes:
|
||||
# The 'node_db' entry configures the primary, persistent storage.
|
||||
|
||||
@@ -120,7 +120,10 @@ 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)
|
||||
target_link_libraries(
|
||||
common
|
||||
INTERFACE -errorreport:none -machine:X64 -ignore:4099
|
||||
)
|
||||
else()
|
||||
target_compile_options(
|
||||
common
|
||||
|
||||
@@ -51,6 +51,8 @@ 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)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#[===================================================================[
|
||||
Linux packaging support: 'package' target.
|
||||
|
||||
The packaging script (package/build_pkg.sh) installs to FHS-standard
|
||||
The packaging script (package/build_pkg.py) installs to FHS-standard
|
||||
paths (/usr/bin, /etc/xrpld, etc.) regardless of CMAKE_INSTALL_PREFIX,
|
||||
so no prefix guard is needed here.
|
||||
#]===================================================================]
|
||||
@@ -38,19 +38,26 @@ if(NOT TARGET validator-keys)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(package_env
|
||||
SRC_DIR=${CMAKE_SOURCE_DIR}
|
||||
BUILD_DIR=${CMAKE_BINARY_DIR}
|
||||
PKG_RELEASE=${pkg_release}
|
||||
)
|
||||
if(DPKG_BUILDPACKAGE_EXECUTABLE)
|
||||
set(pkg_type deb)
|
||||
else()
|
||||
set(pkg_type rpm)
|
||||
endif()
|
||||
|
||||
# Unquoted below, so an empty value adds no argument at all.
|
||||
set(pkg_variant_option "")
|
||||
if(assert)
|
||||
set(pkg_variant_option --variant=assert)
|
||||
endif()
|
||||
|
||||
add_custom_target(
|
||||
package
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E env ${package_env}
|
||||
${CMAKE_SOURCE_DIR}/package/build_pkg.sh
|
||||
${CMAKE_SOURCE_DIR}/package/build_pkg.py --package-type=${pkg_type}
|
||||
--build-dir=${CMAKE_BINARY_DIR} --pkg-release=${pkg_release}
|
||||
${pkg_variant_option} --channel=UNRELEASED
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
DEPENDS xrpld validator-keys
|
||||
COMMENT "Building Linux package (deb/rpm inferred from host tooling)"
|
||||
COMMENT "Building Linux ${pkg_type} package"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
@@ -32,6 +32,11 @@ 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
|
||||
|
||||
@@ -8,6 +8,7 @@ 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
|
||||
|
||||
@@ -53,28 +54,89 @@ 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', 'Delegation::delegable',
|
||||
'uint256{}', 'createAcct', '({...})']
|
||||
['ttPAYMENT', '0', 'Payment',
|
||||
'({.privileges = Privilege::CreateAcct})', '({...})']
|
||||
|
||||
Returns:
|
||||
A dict with parsed transaction information.
|
||||
"""
|
||||
if len(args_list) < 7:
|
||||
if len(args_list) < 5:
|
||||
raise ValueError(
|
||||
f"Expected at least 7 parts in TRANSACTION, got {len(args_list)}: {args_list}"
|
||||
f"Expected at least 5 parts in TRANSACTION, got {len(args_list)}: {args_list}"
|
||||
)
|
||||
|
||||
tag = args_list[0]
|
||||
value = args_list[1]
|
||||
name = args_list[2]
|
||||
delegable = args_list[3]
|
||||
amendments = args_list[4]
|
||||
privileges = args_list[5]
|
||||
settings = parse_settings(args_list[3])
|
||||
fields_str = args_list[-1]
|
||||
|
||||
# Parse fields: ({field1, field2, ...})
|
||||
@@ -84,9 +146,9 @@ def parse_transaction_args(args_list):
|
||||
"tag": tag,
|
||||
"value": value,
|
||||
"name": name,
|
||||
"delegable": delegable,
|
||||
"amendments": amendments,
|
||||
"privileges": privileges,
|
||||
"delegable": settings["delegable"],
|
||||
"amendments": settings["amendment"],
|
||||
"privileges": settings["privileges"],
|
||||
"fields": fields,
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"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",
|
||||
|
||||
@@ -28,6 +28,7 @@ class Xrpl(ConanFile):
|
||||
}
|
||||
|
||||
requires = [
|
||||
"corrosion/0.6.1",
|
||||
"ed25519/2015.03",
|
||||
"fast_float/8.2.10",
|
||||
"grpc/1.81.1",
|
||||
@@ -148,6 +149,7 @@ class Xrpl(ConanFile):
|
||||
self.requires("xxhash/0.8.3", transitive_headers=True)
|
||||
|
||||
exports_sources = (
|
||||
"bin/default-loader-path.sh",
|
||||
"CMakeLists.txt",
|
||||
"cfg/*",
|
||||
"cmake/*",
|
||||
|
||||
17
crates/.cargo/config.toml
Normal file
17
crates/.cargo/config.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
# 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"]
|
||||
104
crates/CMakeLists.txt
Normal file
104
crates/CMakeLists.txt
Normal file
@@ -0,0 +1,104 @@
|
||||
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
Normal file
301
crates/Cargo.lock
generated
Normal file
@@ -0,0 +1,301 @@
|
||||
# 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",
|
||||
]
|
||||
18
crates/Cargo.toml
Normal file
18
crates/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[workspace]
|
||||
members = ["hello_world"]
|
||||
resolver = "3"
|
||||
|
||||
[workspace.dependencies]
|
||||
cxx = { version = "1.0.198", features = ["c++20"] }
|
||||
|
||||
[workspace.package]
|
||||
edition = "2024"
|
||||
|
||||
[workspace.lints.rust]
|
||||
unexpected_cfgs = { level = "warn", check-cfg = [ 'cfg(coverage)', 'cfg(coverage_nightly)' ] }
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
overflow-checks = true
|
||||
lto = true
|
||||
debug = true
|
||||
10
crates/generated.clang-tidy
Normal file
10
crates/generated.clang-tidy
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
# 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
|
||||
13
crates/hello_world/Cargo.toml
Normal file
13
crates/hello_world/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "rs-hello_world"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
cxx.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
23
crates/hello_world/src/lib.rs
Normal file
23
crates/hello_world/src/lib.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
|
||||
|
||||
#[cxx::bridge(namespace = "rs::hello_world")]
|
||||
mod ffi {
|
||||
extern "Rust" {
|
||||
fn hello_world() -> String;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hello_world() -> String {
|
||||
"hello_world".to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg_attr(coverage_nightly, coverage(off))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn hello_world_returns_hello_world() {
|
||||
assert_eq!(hello_world(), "hello_world")
|
||||
}
|
||||
}
|
||||
22
docs/build/environment.md
vendored
22
docs/build/environment.md
vendored
@@ -46,6 +46,9 @@ 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
|
||||
@@ -121,6 +124,25 @@ 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
|
||||
|
||||
|
||||
84
docs/build/nix.md
vendored
84
docs/build/nix.md
vendored
@@ -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
|
||||
- **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
|
||||
- **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/compilers.nix`](../../nix/compilers.nix)).
|
||||
rebuilt against the pinned custom glibc (see [`nix/linux.nix`](../../nix/linux.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,6 +128,12 @@ 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
|
||||
@@ -142,14 +148,80 @@ 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 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.
|
||||
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/`.
|
||||
|
||||
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.
|
||||
|
||||
88
docs/build/nix_troubleshooting.md
vendored
88
docs/build/nix_troubleshooting.md
vendored
@@ -131,3 +131,91 @@ 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/*'
|
||||
```
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
# 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,
|
||||
@@ -52,7 +59,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/xrpld-deb focal stable" | \
|
||||
echo "deb [signed-by=/usr/local/share/keyrings/ripple-key.gpg] https://repos.ripple.com/repos/rippled-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:
|
||||
@@ -106,8 +113,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/xrpld-rpm/stable/
|
||||
gpgkey=https://repos.ripple.com/repos/xrpld-rpm/stable/repodata/repomd.xml.key
|
||||
baseurl=https://repos.ripple.com/repos/rippled-rpm/stable/
|
||||
gpgkey=https://repos.ripple.com/repos/rippled-rpm/stable/repodata/repomd.xml.key
|
||||
REPOFILE
|
||||
|
||||
_Unstable_
|
||||
@@ -118,8 +125,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/xrpld-rpm/unstable/
|
||||
gpgkey=https://repos.ripple.com/repos/xrpld-rpm/unstable/repodata/repomd.xml.key
|
||||
baseurl=https://repos.ripple.com/repos/rippled-rpm/unstable/
|
||||
gpgkey=https://repos.ripple.com/repos/rippled-rpm/unstable/repodata/repomd.xml.key
|
||||
REPOFILE
|
||||
|
||||
_Nightly_
|
||||
@@ -130,8 +137,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/xrpld-rpm/nightly/
|
||||
gpgkey=https://repos.ripple.com/repos/xrpld-rpm/nightly/repodata/repomd.xml.key
|
||||
baseurl=https://repos.ripple.com/repos/rippled-rpm/nightly/
|
||||
gpgkey=https://repos.ripple.com/repos/rippled-rpm/nightly/repodata/repomd.xml.key
|
||||
REPOFILE
|
||||
|
||||
2. Fetch the latest repo updates:
|
||||
159
docs/install.md
Normal file
159
docs/install.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# 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 DNF on Red Hat-based distributions such as RHEL, AlmaLinux, and Rocky Linux,
|
||||
where `yum` is a symlink to `dnf`.
|
||||
To build from source instead, see [BUILD.md](../BUILD.md).
|
||||
|
||||
## Release channels
|
||||
|
||||
Packages are published to four channels:
|
||||
|
||||
- `stable` - production releases
|
||||
- `rc` - release candidates
|
||||
- `beta` - 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 DNF 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 dnf install -y xrpld
|
||||
```
|
||||
|
||||
### Optional: the assert-enabled build
|
||||
|
||||
Every channel also carries `xrpld-assert` as a DEB, the same build with assertions
|
||||
enabled, for diagnosing a problem on a non-production server.
|
||||
It installs the same files as `xrpld` and replaces it, so install one or the other:
|
||||
|
||||
```bash
|
||||
sudo apt -y install xrpld-assert # APT removes xrpld itself
|
||||
```
|
||||
|
||||
Switching stops the service, since it is a removal and an installation rather than an upgrade,
|
||||
and APT starts it again.
|
||||
Install `xrpld` the same way to switch back.
|
||||
|
||||
## 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 DEB packages start it immediately as well; the RPM 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
|
||||
```
|
||||
@@ -162,4 +162,89 @@ toUInt64(std::string const& s);
|
||||
bool
|
||||
isProperlyFormedTomlDomain(std::string_view domain);
|
||||
|
||||
/**
|
||||
* Whether a view can be passed on as a C string.
|
||||
*
|
||||
* A reader given only data() stops at the first null, so the view must reach the
|
||||
* terminating null. The test rebuilds the view from data() and compares: a view
|
||||
* that stops earlier rebuilds longer, and so compares unequal.
|
||||
*
|
||||
* consteval because reading the byte after the view is only defined when @p str
|
||||
* points into storage holding a null at or after its end, such as a string
|
||||
* literal. An unterminated view is then a compile error, not an out-of-bounds
|
||||
* read.
|
||||
*
|
||||
* @param str The view to test.
|
||||
* @return Whether @p str is null-terminated. A view with no data is not.
|
||||
*/
|
||||
consteval bool
|
||||
isNullTerminated(std::string_view str)
|
||||
{
|
||||
if (str.data() == nullptr)
|
||||
return false;
|
||||
|
||||
// Reading past the view is the point, so the usual data() warning does not
|
||||
// apply.
|
||||
// NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
|
||||
return std::string_view{str.data()} == str;
|
||||
}
|
||||
|
||||
/**
|
||||
* A string that is known to reach its terminating null.
|
||||
*
|
||||
* Converts to std::string_view, so it compares and hashes as one. Unlike a
|
||||
* view, asCString() may be handed to a reader that expects a C string, such
|
||||
* as json::StaticString.
|
||||
*
|
||||
* The only constructor is consteval and rejects a view that stops before the
|
||||
* null, so the property holds by construction and no caller asserts it.
|
||||
*/
|
||||
class NullTerminatedView
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Build a view from one that reaches its terminating null.
|
||||
*
|
||||
* Explicit, so that a plain view cannot become a proof of termination by
|
||||
* accident. The conversion the other way stays implicit.
|
||||
*
|
||||
* @param view The string to hold. Rejected at compile time if it stops
|
||||
* before its terminating null, or has no data.
|
||||
*/
|
||||
explicit consteval NullTerminatedView(std::string_view view)
|
||||
: data_(view.data()), size_(view.size())
|
||||
{
|
||||
if (!isNullTerminated(view))
|
||||
throw "xrpl::NullTerminatedView : view does not reach a null";
|
||||
}
|
||||
|
||||
constexpr
|
||||
operator std::string_view() const noexcept
|
||||
{
|
||||
return view();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The string as a view.
|
||||
*/
|
||||
[[nodiscard]] constexpr std::string_view
|
||||
view() const noexcept
|
||||
{
|
||||
return {data_, size_};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The string as a C string. Never null.
|
||||
*/
|
||||
[[nodiscard]] constexpr char const*
|
||||
asCString() const noexcept
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
private:
|
||||
char const* data_;
|
||||
std::size_t size_;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -518,7 +518,7 @@ public:
|
||||
* The input must be precisely `2 * bytes` hexadecimal characters
|
||||
* long, with one exception: the value '0'.
|
||||
*
|
||||
* @param sv A null-terminated string of hexadecimal characters
|
||||
* @param sv A string of hexadecimal characters
|
||||
* @return true if the input was parsed properly; false otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace boost {
|
||||
template <>
|
||||
struct hash<::beast::ip::Address>
|
||||
{
|
||||
explicit hash() = default;
|
||||
hash() = default;
|
||||
|
||||
std::size_t
|
||||
operator()(::beast::ip::Address const& addr) const
|
||||
|
||||
@@ -125,6 +125,7 @@ struct Keys
|
||||
static constexpr auto kMaximumTxnInLedger = "maximum_txn_in_ledger";
|
||||
static constexpr auto kMaximumTxnPerAccount = "maximum_txn_per_account";
|
||||
static constexpr auto kMemoryLevel = "memory_level";
|
||||
static constexpr auto kMaxWaitingLedgers = "max_waiting_ledgers";
|
||||
static constexpr auto kMinLedgersToComputeSizeLimit = "min_ledgers_to_compute_size_limit";
|
||||
static constexpr auto kMinimumEscalationMultiplier = "minimum_escalation_multiplier";
|
||||
static constexpr auto kMinimumLastLedgerBuffer = "minimum_last_ledger_buffer";
|
||||
|
||||
@@ -34,7 +34,10 @@ enum class HashRouterFlags : std::uint16_t {
|
||||
PRIVATE4 = 0x0800,
|
||||
// Used in EscrowFinish.cpp
|
||||
PRIVATE5 = 0x1000,
|
||||
PRIVATE6 = 0x2000
|
||||
PRIVATE6 = 0x2000,
|
||||
// Used in apply.cpp
|
||||
PRIVATE7 = 0x4000,
|
||||
PRIVATE8 = 0x8000
|
||||
};
|
||||
|
||||
constexpr HashRouterFlags
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/StringUtilities.h>
|
||||
#include <xrpl/core/Job.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
@@ -9,7 +10,8 @@
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
|
||||
namespace beast {
|
||||
class Journal;
|
||||
@@ -67,7 +69,7 @@ public:
|
||||
* @param requestId Unique identifier to track command
|
||||
*/
|
||||
virtual void
|
||||
rpcStart(std::string const& method, std::uint64_t requestId) = 0;
|
||||
rpcStart(std::string_view method, std::uint64_t requestId) = 0;
|
||||
|
||||
/**
|
||||
* Log successful finish of RPC call
|
||||
@@ -76,7 +78,7 @@ public:
|
||||
* @param requestId Unique identifier to track command
|
||||
*/
|
||||
virtual void
|
||||
rpcFinish(std::string const& method, std::uint64_t requestId) = 0;
|
||||
rpcFinish(std::string_view method, std::uint64_t requestId) = 0;
|
||||
|
||||
/**
|
||||
* Log errored RPC call
|
||||
@@ -85,7 +87,7 @@ public:
|
||||
* @param requestId Unique identifier to track command
|
||||
*/
|
||||
virtual void
|
||||
rpcError(std::string const& method, std::uint64_t requestId) = 0;
|
||||
rpcError(std::string_view method, std::uint64_t requestId) = 0;
|
||||
|
||||
/**
|
||||
* Log queued job
|
||||
@@ -150,10 +152,20 @@ public:
|
||||
PerfLog::Setup
|
||||
setupPerfLog(Section const& section, std::filesystem::path const& configDir);
|
||||
|
||||
/**
|
||||
* @param methodNames The RPC methods to count, one counter per name. Reported
|
||||
* as JSON keys that borrow each name and read it as a C string, which is
|
||||
* why the parameter type requires one that reaches its terminating null.
|
||||
* The names must outlive the returned object, which holds views of them.
|
||||
* The range itself need not: it is copied.
|
||||
* Passed in rather than looked up here, so that this layer needs no
|
||||
* knowledge of the dispatch table.
|
||||
*/
|
||||
std::unique_ptr<PerfLog>
|
||||
makePerfLog(
|
||||
PerfLog::Setup const& setup,
|
||||
Application& app,
|
||||
std::span<NullTerminatedView const> methodNames,
|
||||
beast::Journal journal,
|
||||
std::function<void()>&& signalStop);
|
||||
|
||||
@@ -161,7 +173,7 @@ template <typename Func, class Rep, class Period>
|
||||
auto
|
||||
measureDurationAndLog(
|
||||
Func&& func,
|
||||
std::string const& actionDescription,
|
||||
std::string_view actionDescription,
|
||||
std::chrono::duration<Rep, Period> maxDelay,
|
||||
beast::Journal const& journal)
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -198,7 +199,10 @@ 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.
|
||||
* 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().
|
||||
* - Checks that the receiver will not exceed the limit (IOU trustline limit
|
||||
* or MPT MaximumAmount).
|
||||
*/
|
||||
@@ -209,7 +213,8 @@ canWithdraw(
|
||||
AccountID const& to,
|
||||
SLE::const_ref toSle,
|
||||
STAmount const& amount,
|
||||
bool hasDestinationTag);
|
||||
bool hasDestinationTag,
|
||||
std::optional<std::vector<uint256>> const& credentialIDs = std::nullopt);
|
||||
|
||||
/**
|
||||
* Checks that can withdraw funds from an object to itself or a destination.
|
||||
@@ -222,7 +227,10 @@ 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.
|
||||
* 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().
|
||||
* - Checks that the receiver will not exceed the limit (IOU trustline limit
|
||||
* or MPT MaximumAmount).
|
||||
*/
|
||||
@@ -232,20 +240,25 @@ canWithdraw(
|
||||
AccountID const& from,
|
||||
AccountID const& to,
|
||||
STAmount const& amount,
|
||||
bool hasDestinationTag);
|
||||
bool hasDestinationTag,
|
||||
std::optional<std::vector<uint256>> const& credentialIDs = std::nullopt);
|
||||
|
||||
/**
|
||||
* 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).
|
||||
* destination account (sfDestination). Credentials, if any, are taken from the
|
||||
* transaction's sfCredentialIDs field.
|
||||
*
|
||||
* - 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.
|
||||
* 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().
|
||||
* - Checks that the receiver will not exceed the limit (IOU trustline limit
|
||||
* or MPT MaximumAmount).
|
||||
*/
|
||||
|
||||
45
include/xrpl/ledger/entries/AMMEntry.h
Normal file
45
include/xrpl/ledger/entries/AMMEntry.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::amm(issue1, issue2), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
explicit AMMEntry(
|
||||
uint256 const& ammID,
|
||||
Base::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::amm(ammID), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using AMMEntryR = AMMEntry<ReadView>;
|
||||
using AMMEntryW = AMMEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
35
include/xrpl/ledger/entries/AccountRootEntry.h
Normal file
35
include/xrpl/ledger/entries/AccountRootEntry.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::account(id), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using AccountRootEntryR = AccountRootEntry<ReadView>;
|
||||
using AccountRootEntryW = AccountRootEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
33
include/xrpl/ledger/entries/AmendmentsEntry.h
Normal file
33
include/xrpl/ledger/entries/AmendmentsEntry.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
|
||||
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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::amendments(), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using AmendmentsEntryR = AmendmentsEntry<ReadView>;
|
||||
using AmendmentsEntryW = AmendmentsEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
36
include/xrpl/ledger/entries/BridgeEntry.h
Normal file
36
include/xrpl/ledger/entries/BridgeEntry.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::bridge(bridge, chainType), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using BridgeEntryR = BridgeEntry<ReadView>;
|
||||
using BridgeEntryW = BridgeEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
46
include/xrpl/ledger/entries/CheckEntry.h
Normal file
46
include/xrpl/ledger/entries/CheckEntry.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::check(id, seq), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
explicit CheckEntry(
|
||||
uint256 const& checkID,
|
||||
Base::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::check(checkID), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using CheckEntryR = CheckEntry<ReadView>;
|
||||
using CheckEntryW = CheckEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
47
include/xrpl/ledger/entries/CredentialEntry.h
Normal file
47
include/xrpl/ledger/entries/CredentialEntry.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#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/entries/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::credential(subject, issuer, credType), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
explicit CredentialEntry(
|
||||
uint256 const& credentialID,
|
||||
Base::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::credential(credentialID), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using CredentialEntryR = CredentialEntry<ReadView>;
|
||||
using CredentialEntryW = CredentialEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
35
include/xrpl/ledger/entries/DIDEntry.h
Normal file
35
include/xrpl/ledger/entries/DIDEntry.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::did(account), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using DIDEntryR = DIDEntry<ReadView>;
|
||||
using DIDEntryW = DIDEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
36
include/xrpl/ledger/entries/DelegateEntry.h
Normal file
36
include/xrpl/ledger/entries/DelegateEntry.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::delegate(account, authorizedAccount), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using DelegateEntryR = DelegateEntry<ReadView>;
|
||||
using DelegateEntryW = DelegateEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
58
include/xrpl/ledger/entries/DepositPreauthEntry.h
Normal file
58
include/xrpl/ledger/entries/DepositPreauthEntry.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#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/entries/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::ViewRefType 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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::depositPreauth(owner, authCreds), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
explicit DepositPreauthEntry(
|
||||
uint256 const& preauthID,
|
||||
Base::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::depositPreauth(preauthID), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using DepositPreauthEntryR = DepositPreauthEntry<ReadView>;
|
||||
using DepositPreauthEntryW = DepositPreauthEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
50
include/xrpl/ledger/entries/DirectoryNodeEntry.h
Normal file
50
include/xrpl/ledger/entries/DirectoryNodeEntry.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType 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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::page(root, index), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using DirectoryNodeEntryR = DirectoryNodeEntry<ReadView>;
|
||||
using DirectoryNodeEntryW = DirectoryNodeEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
37
include/xrpl/ledger/entries/EscrowEntry.h
Normal file
37
include/xrpl/ledger/entries/EscrowEntry.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::escrow(src, seq), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using EscrowEntryR = EscrowEntry<ReadView>;
|
||||
using EscrowEntryW = EscrowEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
33
include/xrpl/ledger/entries/FeeSettingsEntry.h
Normal file
33
include/xrpl/ledger/entries/FeeSettingsEntry.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
|
||||
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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::feeSettings(), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using FeeSettingsEntryR = FeeSettingsEntry<ReadView>;
|
||||
using FeeSettingsEntryW = FeeSettingsEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
33
include/xrpl/ledger/entries/LedgerHashesEntry.h
Normal file
33
include/xrpl/ledger/entries/LedgerHashesEntry.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
|
||||
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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::skip(), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using LedgerHashesEntryR = LedgerHashesEntry<ReadView>;
|
||||
using LedgerHashesEntryW = LedgerHashesEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
46
include/xrpl/ledger/entries/LoanBrokerEntry.h
Normal file
46
include/xrpl/ledger/entries/LoanBrokerEntry.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::loanBroker(owner, seq), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
explicit LoanBrokerEntry(
|
||||
uint256 const& loanBrokerID,
|
||||
Base::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::loanBroker(loanBrokerID), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using LoanBrokerEntryR = LoanBrokerEntry<ReadView>;
|
||||
using LoanBrokerEntryW = LoanBrokerEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
45
include/xrpl/ledger/entries/LoanEntry.h
Normal file
45
include/xrpl/ledger/entries/LoanEntry.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::loan(loanBrokerID, loanSeq), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
explicit LoanEntry(
|
||||
uint256 const& loanID,
|
||||
Base::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::loan(loanID), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using LoanEntryR = LoanEntry<ReadView>;
|
||||
using LoanEntryW = LoanEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
55
include/xrpl/ledger/entries/MPTokenEntry.h
Normal file
55
include/xrpl/ledger/entries/MPTokenEntry.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType 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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::mptoken(issuanceKey, holder), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
explicit MPTokenEntry(
|
||||
uint256 const& mptokenKey,
|
||||
Base::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::mptoken(mptokenKey), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using MPTokenEntryR = MPTokenEntry<ReadView>;
|
||||
using MPTokenEntryW = MPTokenEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
56
include/xrpl/ledger/entries/MPTokenIssuanceEntry.h
Normal file
56
include/xrpl/ledger/entries/MPTokenIssuanceEntry.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::mptokenIssuance(makeMptID(seq, issuer)), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
explicit MPTokenIssuanceEntry(
|
||||
MPTID const& issuanceID,
|
||||
Base::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::mptokenIssuance(issuanceID), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
explicit MPTokenIssuanceEntry(
|
||||
uint256 const& issuanceKey,
|
||||
Base::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::mptokenIssuance(issuanceKey), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using MPTokenIssuanceEntryR = MPTokenIssuanceEntry<ReadView>;
|
||||
using MPTokenIssuanceEntryW = MPTokenIssuanceEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
46
include/xrpl/ledger/entries/NFTokenOfferEntry.h
Normal file
46
include/xrpl/ledger/entries/NFTokenOfferEntry.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::nftokenOffer(owner, seq), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
explicit NFTokenOfferEntry(
|
||||
uint256 const& offerID,
|
||||
Base::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::nftokenOffer(offerID), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using NFTokenOfferEntryR = NFTokenOfferEntry<ReadView>;
|
||||
using NFTokenOfferEntryW = NFTokenOfferEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
37
include/xrpl/ledger/entries/NFTokenPageEntry.h
Normal file
37
include/xrpl/ledger/entries/NFTokenPageEntry.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::nftokenPage(page, token), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using NFTokenPageEntryR = NFTokenPageEntry<ReadView>;
|
||||
using NFTokenPageEntryW = NFTokenPageEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
33
include/xrpl/ledger/entries/NegativeUNLEntry.h
Normal file
33
include/xrpl/ledger/entries/NegativeUNLEntry.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
|
||||
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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::negativeUNL(), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using NegativeUNLEntryR = NegativeUNLEntry<ReadView>;
|
||||
using NegativeUNLEntryW = NegativeUNLEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
46
include/xrpl/ledger/entries/OfferEntry.h
Normal file
46
include/xrpl/ledger/entries/OfferEntry.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::offer(id, seq), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
explicit OfferEntry(
|
||||
uint256 const& offerID,
|
||||
Base::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::offer(offerID), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using OfferEntryR = OfferEntry<ReadView>;
|
||||
using OfferEntryW = OfferEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
38
include/xrpl/ledger/entries/OracleEntry.h
Normal file
38
include/xrpl/ledger/entries/OracleEntry.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::oracle(account, documentID), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using OracleEntryR = OracleEntry<ReadView>;
|
||||
using OracleEntryW = OracleEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
38
include/xrpl/ledger/entries/PayChannelEntry.h
Normal file
38
include/xrpl/ledger/entries/PayChannelEntry.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::payChannel(src, dst, seq), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using PayChannelEntryR = PayChannelEntry<ReadView>;
|
||||
using PayChannelEntryW = PayChannelEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
46
include/xrpl/ledger/entries/PermissionedDomainEntry.h
Normal file
46
include/xrpl/ledger/entries/PermissionedDomainEntry.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::permissionedDomain(account, seq), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
explicit PermissionedDomainEntry(
|
||||
uint256 const& domainID,
|
||||
Base::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::permissionedDomain(domainID), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using PermissionedDomainEntryR = PermissionedDomainEntry<ReadView>;
|
||||
using PermissionedDomainEntryW = PermissionedDomainEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
48
include/xrpl/ledger/entries/RippleStateEntry.h
Normal file
48
include/xrpl/ledger/entries/RippleStateEntry.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType 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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::trustLine(id, issue), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using RippleStateEntryR = RippleStateEntry<ReadView>;
|
||||
using RippleStateEntryW = RippleStateEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
503
include/xrpl/ledger/entries/SLEBase.h
Normal file
503
include/xrpl/ledger/entries/SLEBase.h
Normal file
@@ -0,0 +1,503 @@
|
||||
#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 IsWritableView = 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 defined behavior only when the view really is a non-const
|
||||
* object that the caller merely observes through a const reference.
|
||||
* That holds for every production view today, but it is not a
|
||||
* guarantee the codebase makes: the unit tests already build
|
||||
* genuinely const ApplyView-derived objects (`Sandbox const` in
|
||||
* Directory_test.cpp and View_test.cpp, `PaymentSandbox const` in
|
||||
* TheoreticalQuality_test.cpp and View_test.cpp). Constructing a
|
||||
* read-only entry over one of those would be undefined behavior, so
|
||||
* do not, until #8069 removes the cast -- by giving ApplyView a
|
||||
* const-qualified peek(), which needs no amendment because
|
||||
* Action::Cache is invisible to apply(), visit() and metadata.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
// Safe only for a view that is not itself a const object -- see the
|
||||
// note above. The entry holds a const reference because it does not
|
||||
// modify the view, not because the view is const.
|
||||
// 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 = IsWritableView<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 SlePtrType = std::conditional_t<kIsWritable, SLE::pointer, SLE::const_pointer>;
|
||||
|
||||
// View reference type: ApplyView& for writable, ReadView const& for
|
||||
// read-only
|
||||
using ViewRefType = 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&)
|
||||
requires(!kIsWritable)
|
||||
= 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,
|
||||
ViewRefType 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,
|
||||
ViewRefType 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 an OfferEntryW
|
||||
* would convert to an AccountRootEntryR with no cast at the call site.
|
||||
*/
|
||||
template <typename OtherViewT, LedgerEntryType OtherType>
|
||||
SLEBase(SLEBase<OtherViewT, OtherType> const& other)
|
||||
requires(!kIsWritable && IsWritableView<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 `FooEntryW const&` is as inert as a `FooEntryR`. 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]] SlePtrType 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 throws 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:
|
||||
ViewRefType 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_;
|
||||
|
||||
SlePtrType 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
|
||||
35
include/xrpl/ledger/entries/SignerListEntry.h
Normal file
35
include/xrpl/ledger/entries/SignerListEntry.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/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::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::signerList(account), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using SignerListEntryR = SignerListEntry<ReadView>;
|
||||
using SignerListEntryW = SignerListEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user