mirror of
https://github.com/XRPLF/rippled.git
synced 2026-10-12 14:48:10 +00:00
Compare commits
12 Commits
dangell7/b
...
nb-seriali
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef0635d26c | ||
|
|
3c6279b735 | ||
|
|
55b265a8c2 | ||
|
|
02e40e7a00 | ||
|
|
f14395427e | ||
|
|
b707bac74f | ||
|
|
da2b5d5eaf | ||
|
|
4de4902200 | ||
|
|
2ea1f09dcb | ||
|
|
68b4b894de | ||
|
|
defd83e5a6 | ||
|
|
452e31a05f |
@@ -108,75 +108,3 @@ endfunction()
|
||||
|
||||
function(patch_nix_binary target)
|
||||
endfunction()
|
||||
|
||||
function(rpcspec_generate_instantiations)
|
||||
set(options)
|
||||
set(oneValueArgs OUT_VAR VALUE_TYPE VIEW_HEADER INCLUDE_DIR)
|
||||
set(multiValueArgs HANDLERS)
|
||||
cmake_parse_arguments(
|
||||
THIS_FUNCTION_PREFIX
|
||||
"${options}"
|
||||
"${oneValueArgs}"
|
||||
"${multiValueArgs}"
|
||||
${ARGN}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(corrosion_import_crate)
|
||||
set(options
|
||||
ALL_FEATURES
|
||||
NO_DEFAULT_FEATURES
|
||||
NO_STD
|
||||
NO_LINKER_OVERRIDE
|
||||
NO_USES_TERMINAL
|
||||
LOCKED
|
||||
FROZEN
|
||||
)
|
||||
set(oneValueArgs MANIFEST_PATH PROFILE IMPORTED_CRATES)
|
||||
set(multiValueArgs
|
||||
CRATE_TYPES
|
||||
CRATES
|
||||
FEATURES
|
||||
FLAGS
|
||||
OVERRIDE_CRATE_TYPE
|
||||
)
|
||||
cmake_parse_arguments(
|
||||
THIS_FUNCTION_PREFIX
|
||||
"${options}"
|
||||
"${oneValueArgs}"
|
||||
"${multiValueArgs}"
|
||||
${ARGN}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(corrosion_set_env_vars target_name env_var)
|
||||
endfunction()
|
||||
|
||||
function(corrosion_add_cxxbridge cxx_target)
|
||||
set(options)
|
||||
set(oneValueArgs CRATE)
|
||||
set(multiValueArgs FILES)
|
||||
cmake_parse_arguments(
|
||||
THIS_FUNCTION_PREFIX
|
||||
"${options}"
|
||||
"${oneValueArgs}"
|
||||
"${multiValueArgs}"
|
||||
${ARGN}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(_unlink_libgcc_s crate)
|
||||
endfunction()
|
||||
|
||||
function(add_xrpl_crate name)
|
||||
set(options)
|
||||
set(oneValueArgs CRATE)
|
||||
set(multiValueArgs FILES)
|
||||
cmake_parse_arguments(
|
||||
THIS_FUNCTION_PREFIX
|
||||
"${options}"
|
||||
"${oneValueArgs}"
|
||||
"${multiValueArgs}"
|
||||
${ARGN}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
10
.github/actions/build-deps/action.yml
vendored
10
.github/actions/build-deps/action.yml
vendored
@@ -44,12 +44,4 @@ runs:
|
||||
--conf:all tools.build:jobs=${BUILD_NPROC} \
|
||||
--conf:all tools.build:verbosity="${LOG_VERBOSITY}" \
|
||||
--conf:all tools.compilation:verbosity="${LOG_VERBOSITY}" \
|
||||
--format=json \
|
||||
. >"${RUNNER_TEMP}/conan-graph.json"
|
||||
|
||||
# Tools that run during the build may only load glibc from the Nix store,
|
||||
# as their package ID survives a GCC runtime update.
|
||||
- name: Check build-context packages for Nix store dependencies (Linux)
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
shell: bash
|
||||
run: ./bin/check-build-context-runtime.sh "${RUNNER_TEMP}/conan-graph.json"
|
||||
.
|
||||
|
||||
@@ -75,7 +75,6 @@ test.app > xrpl.json
|
||||
test.app > xrpl.ledger
|
||||
test.app > xrpl.nodestore
|
||||
test.app > xrpl.protocol
|
||||
test.app > xrpl.rdb
|
||||
test.app > xrpl.resource
|
||||
test.app > xrpl.server
|
||||
test.app > xrpl.shamap
|
||||
|
||||
8
.github/scripts/strategy-matrix/linux.json
vendored
8
.github/scripts/strategy-matrix/linux.json
vendored
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"image_tag": "sha-3d526d4",
|
||||
"image_tag": "sha-060957e",
|
||||
"configs": {
|
||||
"ubuntu": [
|
||||
{
|
||||
@@ -74,7 +74,7 @@
|
||||
"extra_cmake_args": "-Dvalidator_keys=ON",
|
||||
"package": {
|
||||
"type": "deb",
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-e6055dd"
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-3a2d19f"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -86,7 +86,7 @@
|
||||
"extra_cmake_args": "-Dvalidator_keys=ON -Dassert=ON",
|
||||
"package": {
|
||||
"type": "deb",
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-e6055dd",
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-3a2d19f",
|
||||
"variant": "assert"
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@
|
||||
"extra_cmake_args": "-Dvalidator_keys=ON",
|
||||
"package": {
|
||||
"type": "rpm",
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-e6055dd"
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-3a2d19f"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
1
.github/workflows/build-nix-images.yml
vendored
1
.github/workflows/build-nix-images.yml
vendored
@@ -13,6 +13,7 @@ on:
|
||||
- "!nix/devshell.nix"
|
||||
- "!nix/check-tools/**"
|
||||
- "bin/default-loader-path.sh"
|
||||
- "bin/install-sanitizer-libs.sh"
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/build-nix-images.yml"
|
||||
|
||||
1
.github/workflows/build-packaging-images.yml
vendored
1
.github/workflows/build-packaging-images.yml
vendored
@@ -5,6 +5,7 @@ on:
|
||||
branches:
|
||||
- develop
|
||||
paths:
|
||||
- ".github/workflows/build-packaging-images.yml"
|
||||
- "bin/install-packaging-tools.sh"
|
||||
- "package/images/packaging/**"
|
||||
pull_request:
|
||||
|
||||
1
.github/workflows/build-pre-commit-image.yml
vendored
1
.github/workflows/build-pre-commit-image.yml
vendored
@@ -5,6 +5,7 @@ on:
|
||||
branches:
|
||||
- develop
|
||||
paths:
|
||||
- ".github/workflows/build-pre-commit-image.yml"
|
||||
- "bin/pre-commit/Dockerfile"
|
||||
- "rust-toolchain.toml"
|
||||
pull_request:
|
||||
|
||||
2
.github/workflows/cargo-audit.yml
vendored
2
.github/workflows/cargo-audit.yml
vendored
@@ -34,7 +34,7 @@ permissions:
|
||||
jobs:
|
||||
audit:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
|
||||
permissions:
|
||||
contents: read
|
||||
# Needed to open an issue on scheduled failures.
|
||||
|
||||
2
.github/workflows/pre-commit.yml
vendored
2
.github/workflows/pre-commit.yml
vendored
@@ -17,4 +17,4 @@ jobs:
|
||||
uses: XRPLF/actions/.github/workflows/pre-commit.yml@279ec358f4a1be4088be3e024b07916fa97c75b6
|
||||
with:
|
||||
runs_on: ubuntu-latest
|
||||
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-70b8fd3" }'
|
||||
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-473fe44" }'
|
||||
|
||||
2
.github/workflows/publish-docs.yml
vendored
2
.github/workflows/publish-docs.yml
vendored
@@ -41,7 +41,7 @@ env:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
2
.github/workflows/reusable-clang-tidy.yml
vendored
2
.github/workflows/reusable-clang-tidy.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
needs: [determine-files]
|
||||
if: ${{ needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.need_full_run == 'true' }}
|
||||
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
|
||||
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-ed96e60"
|
||||
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-060957e"
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
|
||||
6
.github/workflows/reusable-rust.yml
vendored
6
.github/workflows/reusable-rust.yml
vendored
@@ -28,7 +28,7 @@ permissions:
|
||||
jobs:
|
||||
clippy:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
|
||||
coverage:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
|
||||
doc:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
2
.github/workflows/reusable-upload-recipe.yml
vendored
2
.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-3d526d4
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
|
||||
env:
|
||||
REMOTE_NAME: ${{ inputs.remote_name }}
|
||||
CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.remote_username }}
|
||||
|
||||
@@ -60,7 +60,7 @@ repos:
|
||||
types_or: [c++, c]
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: a9a8a861f30ed207ead7d5a3b7e8032283ba5da7 # frozen: v23.1.2
|
||||
rev: e2b496dc2bd8340c2524cb9a2d2a943cde1bb6df # frozen: v23.1.1
|
||||
hooks:
|
||||
- id: clang-format
|
||||
args: [--style=file]
|
||||
@@ -82,10 +82,9 @@ repos:
|
||||
files: ^crates/.*\.rs$
|
||||
|
||||
- repo: https://github.com/BlankSpruce/gersemi-pre-commit
|
||||
rev: 28010ddd6016e1a0f7bd232acb6536ef996ae897 # frozen: 0.29.2
|
||||
rev: f1c4833f8cf23c6d952673abc73525411a5719e8 # frozen: 0.29.1
|
||||
hooks:
|
||||
- id: gersemi
|
||||
args: [-i, --warnings-as-errors]
|
||||
|
||||
- repo: https://github.com/rbubley/mirrors-prettier
|
||||
rev: ef4a397f916211b4a39ccf9d3d9cbb6562157251 # frozen: v3.9.9
|
||||
@@ -96,19 +95,19 @@ repos:
|
||||
# Scoped to package/: the rest of the repo's Python has pre-existing findings,
|
||||
# so widening these is its own change.
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: f12be1ebaa5351c1fc76472de98db2c3446c8253 # frozen: v0.16.10
|
||||
rev: a56c0b927e6465d37cae3e97d35d4d18ab2b96cd # frozen: v0.16.9
|
||||
hooks:
|
||||
- id: ruff-check
|
||||
args: [--fix]
|
||||
files: ^package/.*\.py$
|
||||
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 96ae3e5802f3fe2d551e703e18f0a367d1a81ac2 # frozen: 26.10.0
|
||||
rev: 4160603246a6b365d4a2af661c6d71b0a0f50478 # frozen: 26.5.1
|
||||
hooks:
|
||||
- id: black
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: 2834ec6639549dd6796205c8f011dedcd587288b # frozen: v2.4.0
|
||||
rev: 7ff8d35ae36a7d2b968f2f90b4c723e292e594ee # frozen: v2.3.1
|
||||
hooks:
|
||||
- id: mypy
|
||||
args: [--strict]
|
||||
|
||||
@@ -29,17 +29,12 @@ Version 3.5.0 is not yet released.
|
||||
### Additions in 3.5.0
|
||||
|
||||
- `subscribe`, `unsubscribe`: Added an optional `mpt_issuances` request field, an array of MPT issuance IDs (hex strings). Subscribers receive a message with `type` `mptTransaction` for each validated transaction whose metadata affects a subscribed issuance; the message has the same fields as the `transactions` stream. MPT issuance subscriptions count toward the per-connection subscription limit. An empty array, a non-array value, or an invalid ID returns `invalidParams`. ([#5671](https://github.com/XRPLF/rippled/pull/5671))
|
||||
- `ledger_entry`: Add full support for checks, NFT offers, payment channels, and signer lists. ([#6319](https://github.com/XRPLF/rippled/pull/6319))
|
||||
|
||||
### Bugfixes in 3.5.0
|
||||
|
||||
- `channel_authorize`: The `channel_id` field now returns an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
|
||||
- `channel_verify`: The `channel_id` and `signature` fields now return an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
|
||||
|
||||
### Bugfixes in 3.5.0
|
||||
|
||||
- `feature`: The admin-only `vetoed` field now returns `invalidParams` unless its value is a boolean. [#7583](https://github.com/XRPLF/rippled/pull/7583)
|
||||
|
||||
## XRP Ledger server version 3.4.0
|
||||
|
||||
Version 3.4.0 is not yet released. These changes are available in the 3.4.0 beta releases.
|
||||
@@ -60,7 +55,6 @@ Version 3.4.0 is not yet released. These changes are available in the 3.4.0 beta
|
||||
- `account_lines`: The `peer` field now returns an error if the value is not a string. [#7728](https://github.com/XRPLF/rippled/pull/7728)
|
||||
- `ledger`: `delivered_amount` is now included in the metadata of successful `AccountDelete` transactions when transactions are expanded (`expand`, or admin-only `full`). Previously it was only added for `Payment` and `CheckCash`, which made `ledger` inconsistent with `tx` and `account_tx`. [#5706](https://github.com/XRPLF/rippled/pull/5706)
|
||||
- `noripple_check`: The `transactions` field is no longer included in error responses; it is still returned (possibly as an empty array) whenever `transactions` is `true` and the request succeeds. A malformed `account` is now rejected before the ledger is looked up, so that error response no longer carries the `ledger_hash`, `ledger_index`, and `validated` fields ([#6303](https://github.com/XRPLF/rippled/pull/6303)).
|
||||
- `transaction_entry`: An object or an array in `tx_hash` now returns `malformedRequest`, like any other value that is not a hex hash, instead of an `internal` error.
|
||||
|
||||
## XRP Ledger server version 3.3.0
|
||||
|
||||
@@ -82,7 +76,6 @@ This release contains bug fixes only and no API changes.
|
||||
|
||||
### Additions in 3.2.0
|
||||
|
||||
- `tx`: A validated `Batch` transaction now includes `inner_results`, an array in `RawTransactions` order with one entry per inner transaction that was evaluated, whether or not it was applied: `hash`, `result` (the transaction result code) and `applied` (whether its changes ended up in the ledger; `false` for an inner transaction that failed with a `ter`/`tem`/`tef` code, and for every inner transaction of a `tfAllOrNothing` batch that rolled back). `tfOnlyOne` stops evaluating after the first inner that returns `tesSUCCESS`, not merely applies (an applied `tec` does not stop it), and `tfUntilFailure` stops after the first inner that fails, so later `RawTransactions` entries have no corresponding `inner_results` entry. Inner transactions that fail are not in the ledger, so this is the only record of them. The field is present only when this node built the validated ledger itself and has `[ledger_tx_tables]` enabled; a node that acquired the ledger from the network omits it.
|
||||
- `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.
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Fail if a binary of a build-context Conan package loads anything from the Nix
|
||||
# store other than glibc, or cannot resolve a library at all.
|
||||
#
|
||||
# Only binaries linked by the Nix toolchain are checked, i.e. those recording a
|
||||
# store path as their interpreter or RUNPATH. Prebuilt upstream binaries (such
|
||||
# as the ones the cmake package ships) use the system loader instead.
|
||||
#
|
||||
# Build-context packages provide the tools that run during the build (protoc,
|
||||
# grpc_cpp_plugin, ...). Their package ID does not change when a Nix toolchain
|
||||
# update moves the GCC runtime to a new store path, so a cached binary has to
|
||||
# get by with the pinned glibc alone. See docs/build/nix.md.
|
||||
#
|
||||
# Usage: bin/check-build-context-runtime.sh <graph.json>
|
||||
# <graph.json> is the output of `conan install --format=json`.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "usage: $0 <graph.json>" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ "$(uname -s)" != "Linux" ]; then
|
||||
echo "$0: Linux only" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
folders="$(jq -r '.graph.nodes[] | select(.context == "build" and .package_folder) | .package_folder' "$1" | sort -u)"
|
||||
|
||||
checked=0
|
||||
failed=0
|
||||
|
||||
while IFS= read -r file; do
|
||||
case "$(file -b "${file}")" in
|
||||
ELF*) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
[[ "$(readelf -ldW "${file}")" == */nix/store/* ]] || continue
|
||||
checked=$((checked + 1))
|
||||
|
||||
# `ldd` lists the interpreter and every library as the loader resolves them.
|
||||
if deps="$(ldd "${file}" 2>&1)"; then
|
||||
bad="$(printf '%s\n' "${deps}" |
|
||||
grep -E 'not found|/nix/store/' |
|
||||
grep -vE '/nix/store/[^/]+-glibc-[^/]+/' || true)"
|
||||
else
|
||||
case "${deps}" in
|
||||
*"not a dynamic executable"*) continue ;;
|
||||
esac
|
||||
bad="${deps}"
|
||||
fi
|
||||
if [ -n "${bad}" ]; then
|
||||
failed=$((failed + 1))
|
||||
echo "::error file=${file}::loads a library from the Nix store other than glibc"
|
||||
echo "${file}"
|
||||
echo "${bad}" | sed 's/^/ /'
|
||||
fi
|
||||
done < <(
|
||||
# shellcheck disable=SC2086 # one folder per line, no spaces in Conan paths
|
||||
[ -z "${folders}" ] || find ${folders} -type f \( -perm -u+x -o -name '*.so*' \)
|
||||
)
|
||||
|
||||
echo "Build-context packages: checked ${checked} binaries, ${failed} failed."
|
||||
[ "${failed}" -eq 0 ]
|
||||
@@ -20,11 +20,9 @@
|
||||
# development setups, but not in the macOS CI environment. They are checked
|
||||
# everywhere except when running in CI on macOS.
|
||||
#
|
||||
# Tools that Nix also exposes under a version-suffixed name
|
||||
# (`clang-tidy-<v>`, `g++-<v>`, ...) are probed under both names:
|
||||
# a suffixed name can break while the plain one still works
|
||||
# (see mkVersionedToolLinks in nix/packages.nix).
|
||||
# The suffix is the major version of the plain `clang` / `gcc` on PATH.
|
||||
# Tools that Nix also exposes under a version-suffixed name (`clang-tidy-22`,
|
||||
# `g++-15`, ...) are probed under both names: a suffixed name can break while
|
||||
# the plain one still works (see mkVersionedToolLinks in nix/packages.nix).
|
||||
#
|
||||
# Tools scoped to a single dev shell rather than to commonPackages are checked
|
||||
# only in that shell, keyed off XRPL_DEVSHELL.
|
||||
@@ -36,16 +34,9 @@
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
# major_version <compiler>
|
||||
# Major version of a compiler on PATH, or "unknown" when it isn't there.
|
||||
major_version() {
|
||||
local version
|
||||
version="$("$1" -dumpversion 2>/dev/null)" || version=""
|
||||
version="${version%%.*}"
|
||||
printf '%s' "${version:-unknown}"
|
||||
}
|
||||
|
||||
llvm_version="$(major_version clang)"
|
||||
# Version suffixes of the Nix tool links, tracking nix/packages.nix.
|
||||
gcc_version=15
|
||||
llvm_version=22
|
||||
|
||||
missing=()
|
||||
checked=0
|
||||
@@ -121,7 +112,6 @@ if [ "${os}" = "linux" ] || [ "${os}" = "macos" ]; then
|
||||
check ClangBuildAnalyzer
|
||||
check curl
|
||||
check file
|
||||
check jq
|
||||
check less
|
||||
check make
|
||||
# net-tools netstat reports "net-tools X.Y"; macOS ships BSD netstat with no
|
||||
@@ -190,7 +180,6 @@ fi
|
||||
if [ "${os}" = "linux" ]; then
|
||||
echo
|
||||
echo "GCC toolchain:"
|
||||
gcc_version="$(major_version gcc)"
|
||||
check gcc
|
||||
check "gcc-${gcc_version}"
|
||||
check g++
|
||||
|
||||
@@ -23,7 +23,7 @@ apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
EOF
|
||||
|
||||
ARG PRE_COMMIT_VERSION=4.6.2
|
||||
ARG PRE_COMMIT_VERSION=4.6.0
|
||||
RUN pip install --no-cache --break-system-packages \
|
||||
pre-commit==${PRE_COMMIT_VERSION}
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
CLANG_TIDY_VERSION = 22
|
||||
|
||||
# Extensions run-clang-tidy can analyse: `.cpp` translation units and, thanks to
|
||||
# the `verify_headers` build option, `.h`/`.hpp` headers (each has its own
|
||||
# compile_commands.json entry). `.ipp` fragments have no entry and are skipped.
|
||||
@@ -37,21 +39,8 @@ TIDY_EXTENSIONS = {".cpp", ".h", ".hpp"}
|
||||
FILEPATH_RE = re.compile(r"^(\s*(?:-\s+)?FilePath:\s*)'((?:[^']|'')*)'\s*$")
|
||||
|
||||
|
||||
def clang_tidy_major() -> str | None:
|
||||
"""Major version of the `clang-tidy` on PATH, which run-clang-tidy invokes."""
|
||||
if not (clang_tidy := shutil.which("clang-tidy")):
|
||||
return None
|
||||
output = subprocess.run(
|
||||
[clang_tidy, "--version"], capture_output=True, text=True
|
||||
).stdout
|
||||
m = re.search(r"LLVM version (\d+)", output)
|
||||
return m.group(1) if m else None
|
||||
|
||||
|
||||
def find_tool(name: str, version: str | None) -> str | None:
|
||||
"""Prefer `<name>-<version>`, so a host tool of another version can't win."""
|
||||
candidates = ([f"{name}-{version}"] if version else []) + [name]
|
||||
for candidate in candidates:
|
||||
def find_tool(name: str) -> str | None:
|
||||
for candidate in (f"{name}-{CLANG_TIDY_VERSION}", name):
|
||||
if path := shutil.which(candidate):
|
||||
return path
|
||||
return None
|
||||
@@ -114,9 +103,8 @@ def main():
|
||||
if not files:
|
||||
return 0
|
||||
|
||||
version = clang_tidy_major()
|
||||
run_clang_tidy = find_tool("run-clang-tidy", version)
|
||||
clang_apply_replacements = find_tool("clang-apply-replacements", version)
|
||||
run_clang_tidy = find_tool("run-clang-tidy")
|
||||
clang_apply_replacements = find_tool("clang-apply-replacements")
|
||||
missing = [
|
||||
name
|
||||
for name, path in (
|
||||
@@ -126,10 +114,9 @@ def main():
|
||||
if not path
|
||||
]
|
||||
if missing:
|
||||
tried = f" (tried the '-{version}' suffix too)" if version else ""
|
||||
print(
|
||||
f"clang-tidy check failed: TIDY is enabled but {' and '.join(missing)} "
|
||||
f"was not found in PATH{tried}.",
|
||||
f"was not found in PATH (tried the '-{CLANG_TIDY_VERSION}' suffix too).",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
@@ -292,14 +292,6 @@ if(xrpld)
|
||||
)
|
||||
target_sources(xrpld PRIVATE ${sources})
|
||||
|
||||
rpcspec_generate_instantiations(
|
||||
OUT_VAR rpcspec_instantiations
|
||||
VALUE_TYPE "::json::Value"
|
||||
VIEW_HEADER "xrpld/rpc/detail/JsonObjectView.hpp"
|
||||
HANDLERS book_changes ledger transaction_entry
|
||||
)
|
||||
target_sources(xrpld PRIVATE ${rpcspec_instantiations})
|
||||
|
||||
if(tests)
|
||||
file(
|
||||
GLOB_RECURSE sources
|
||||
@@ -330,7 +322,6 @@ if(xrpld)
|
||||
# antithesis_instrumentation.h, which is not exported as INTERFACE
|
||||
target_include_directories(
|
||||
xrpld
|
||||
SYSTEM
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/external/antithesis-sdk
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -77,24 +77,19 @@ if(is_clang)
|
||||
message(STATUS " Ignorelist: ${ignorelist_path}")
|
||||
endif()
|
||||
|
||||
# Define the SANITIZERS macro for BuildInfo.cpp, plus one of XRPL_ASAN,
|
||||
# XRPL_TSAN and XRPL_UBSAN per active sanitizer, so that code can test for a
|
||||
# specific one with #ifdef instead of parsing the dot-joined SANITIZERS string.
|
||||
# Define SANITIZERS macro for BuildInfo.cpp
|
||||
set(sanitizers_list)
|
||||
if(SANITIZERS MATCHES "address")
|
||||
set(enable_asan ON)
|
||||
list(APPEND sanitizers_list "ASAN")
|
||||
target_compile_definitions(common INTERFACE XRPL_ASAN)
|
||||
endif()
|
||||
if(SANITIZERS MATCHES "thread")
|
||||
set(enable_tsan ON)
|
||||
list(APPEND sanitizers_list "TSAN")
|
||||
target_compile_definitions(common INTERFACE XRPL_TSAN)
|
||||
endif()
|
||||
if(SANITIZERS MATCHES "undefinedbehavior")
|
||||
set(enable_ubsan ON)
|
||||
list(APPEND sanitizers_list "UBSAN")
|
||||
target_compile_definitions(common INTERFACE XRPL_UBSAN)
|
||||
endif()
|
||||
|
||||
if(sanitizers_list)
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace xrpl::ledger_entries {
|
||||
// builder's STObject and the wrapper's SLE.
|
||||
TEST(${name}Tests, BuilderSettersRoundTrip)
|
||||
{
|
||||
UInt256 const index{1u};
|
||||
constexpr UInt256 index{1};
|
||||
|
||||
% for field in fields:
|
||||
auto const ${field["paramName"]}Value = ${canonical_expr(field)};
|
||||
@@ -85,7 +85,7 @@ TEST(${name}Tests, BuilderSettersRoundTrip)
|
||||
// from that SLE, build a new wrapper, and verify all fields (and validate()).
|
||||
TEST(${name}Tests, BuilderFromSleRoundTrip)
|
||||
{
|
||||
UInt256 const index{2u};
|
||||
constexpr UInt256 index{2};
|
||||
|
||||
% for field in fields:
|
||||
auto const ${field["paramName"]}Value = ${canonical_expr(field)};
|
||||
@@ -146,7 +146,7 @@ TEST(${name}Tests, BuilderFromSleRoundTrip)
|
||||
// 3) Verify wrapper throws when constructed from wrong ledger entry type.
|
||||
TEST(${name}Tests, WrapperThrowsOnWrongEntryType)
|
||||
{
|
||||
UInt256 const index{3u};
|
||||
constexpr UInt256 index{3};
|
||||
|
||||
// Build a valid ledger entry of a different type
|
||||
// Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq
|
||||
@@ -177,7 +177,7 @@ TEST(${name}Tests, WrapperThrowsOnWrongEntryType)
|
||||
// 4) Verify builder throws when constructed from wrong ledger entry type.
|
||||
TEST(${name}Tests, BuilderThrowsOnWrongEntryType)
|
||||
{
|
||||
UInt256 const index{4u};
|
||||
constexpr UInt256 index{4};
|
||||
|
||||
// Build a valid ledger entry of a different type
|
||||
% if wrong_le_include == "Ticket":
|
||||
@@ -207,7 +207,7 @@ TEST(${name}Tests, BuilderThrowsOnWrongEntryType)
|
||||
// 5) Build with only required fields and verify optional fields return nullopt.
|
||||
TEST(${name}Tests, OptionalFieldsReturnNullopt)
|
||||
{
|
||||
UInt256 const index{3u};
|
||||
constexpr UInt256 index{3};
|
||||
|
||||
% for field in required_fields:
|
||||
auto const ${field["paramName"]}Value = ${canonical_expr(field)};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"requires": [
|
||||
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
|
||||
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1782392402.420688",
|
||||
"xrpl-rpc-spec/0.1.21#d536f87a2ae7d313452746cfa3ac4404%1790869005.122975",
|
||||
"xrpl-rpc-spec/0.1.19#870b2d3abcfbbf13b61c2d3c69495060%1790348286.187549",
|
||||
"sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1782392403.185447",
|
||||
"soci/4.0.3#e726491a03468795453f7c83fc924a96%1782392402.679521",
|
||||
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1782307151.633168",
|
||||
@@ -20,7 +20,7 @@
|
||||
"libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1782392403.066892",
|
||||
"jemalloc/5.3.1#1fc58d55316041f10fbc1e8a2eae632a%1776700028.228",
|
||||
"gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1782392402.791979",
|
||||
"grpc/1.81.1#aaa93ab6cda2f2baa6a84490582c8adf%1791284951.826256",
|
||||
"grpc/1.81.1#b87796a4269034856cbc1a2522db16eb%1788275071.530512",
|
||||
"fast_float/8.2.10#f6f28d6bb22112078e7dbda611caf681%1785888854.601666",
|
||||
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1782307148.15562",
|
||||
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1782392402.538492",
|
||||
@@ -34,15 +34,11 @@
|
||||
"build_requires": [
|
||||
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
|
||||
"strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1782395692.540639",
|
||||
"re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1782392402.431897",
|
||||
"protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933",
|
||||
"openssl/3.6.3#f806de8933e3bf6f01016c6a888cee2e%1783945160.863288",
|
||||
"nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1782395690.33162",
|
||||
"msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649",
|
||||
"m4/1.4.19#1727f439cf74e83826ec96d0b4904eee%1784541921.659",
|
||||
"grpc/1.81.1#aaa93ab6cda2f2baa6a84490582c8adf%1791284951.826256",
|
||||
"cmake/4.3.3#840cf00ea09777e05c2050a50a82c722%1782392418.696091",
|
||||
"c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1782392402.681654",
|
||||
"b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1782392402.624226",
|
||||
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
|
||||
"autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86",
|
||||
|
||||
@@ -3,13 +3,5 @@
|
||||
core:non_interactive=True
|
||||
core.download:parallel={{ os.cpu_count() }}
|
||||
core.upload:parallel={{ os.cpu_count() }}
|
||||
# Fall back to Conan Center's source backups when a recipe's upstream URL is down
|
||||
# (e.g. the GNU FTP mirrors), see
|
||||
# https://github.com/conan-io/conan-center-index/issues/28147#issuecomment-3183544772
|
||||
# The backups are only tried once every upstream URL has used up its retries,
|
||||
# so keep the retries low.
|
||||
core.sources:download_urls=["origin", "https://c3i.jfrog.io/artifactory/conan-center-backup-sources"]
|
||||
tools.files.download:retry=1
|
||||
tools.files.download:retry=5
|
||||
tools.files.download:retry_wait=10
|
||||
# Fail fast on unreachable hosts (default connect timeout is 30s), keep the 60s read timeout.
|
||||
core.net.http:timeout=(5, 60)
|
||||
|
||||
@@ -29,9 +29,9 @@ os.version={{ min_macos_version }}
|
||||
[conf]
|
||||
{# The Boost recipe builds with b2, which doesn't use Conan's toolchain files. #}
|
||||
{# Instead it hand-rolls the compiler for user-config.jam, #}
|
||||
{# and its fallback probes a version-suffixed binary (e.g. `g++-<major>`) before plain `g++`. #}
|
||||
{# Inside the Nix shell the wrapper only provides `g++`/`gcc` (no `-<major>` suffix), #}
|
||||
{# so on a host that also has a system `g++-<major>` the probe escapes Nix #}
|
||||
{# and its fallback probes a version-suffixed binary (e.g. `g++-15`) before plain `g++`. #}
|
||||
{# Inside the Nix shell the wrapper only provides `g++`/`gcc` (no `-15` suffix), #}
|
||||
{# so on a host that also has a system `g++-15` the probe escapes Nix #}
|
||||
{# and picks the system compiler, which is mismatched with the Nix libraries #}
|
||||
{# and breaks the build (e.g. Boost.Stacktrace link checks fail). #}
|
||||
{# Pinning the executables here short-circuits that probe so Boost (and the rest of the toolchain) #}
|
||||
@@ -49,17 +49,6 @@ tools.build:compiler_executables={'c':'{{ cc_exe }}','cpp':'{{ cxx_exe }}'}
|
||||
user.package:cppstd_version=23
|
||||
tools.info.package_id:confs+=["user.package:cppstd_version"]
|
||||
|
||||
{% if os == "Linux" and context == "build" %}
|
||||
{# Build-context executables (protoc, grpc_cpp_plugin, build tools) run during the build #}
|
||||
{# and would otherwise load libstdc++/libgcc from a Nix store path #}
|
||||
{# that might change with a Nix toolchain update. #}
|
||||
{# --as-needed drops the ones they link but don't use, #}
|
||||
{# such as libatomic for grpc_cpp_plugin on arm64. #}
|
||||
{% set static_runtime_flags = ["-static-libstdc++", "-static-libgcc", "-Wl,--as-needed"] %}
|
||||
tools.build:exelinkflags+={{ static_runtime_flags }}
|
||||
tools.info.package_id:confs+=["tools.build:exelinkflags"]
|
||||
{% endif %}
|
||||
|
||||
{% if os == "Macos" %}
|
||||
[buildenv]
|
||||
{# os.version adds -mmacosx-version-min to compiler command lines, #}
|
||||
@@ -69,13 +58,3 @@ tools.info.package_id:confs+=["tools.build:exelinkflags"]
|
||||
{# Scoped to boost/* since it is the only gap. #}
|
||||
boost/*:MACOSX_DEPLOYMENT_TARGET={{ min_macos_version }}
|
||||
{% endif %}
|
||||
|
||||
{% if os == "Linux" and context == "build" %}
|
||||
{# b2 links itself with its own script, which ignores exelinkflags #}
|
||||
{# and only takes CXXFLAGS when use_cxx_env is set. #}
|
||||
[options]
|
||||
b2/*:use_cxx_env=True
|
||||
|
||||
[buildenv]
|
||||
b2/*:CXXFLAGS={{ static_runtime_flags | join(" ") }}
|
||||
{% endif %}
|
||||
|
||||
@@ -5,9 +5,6 @@ include(default)
|
||||
|
||||
{% if not sanitizers %}
|
||||
{# Sanitizers not configured; no additional settings needed #}
|
||||
{% elif context == "build" %}
|
||||
{# Build-context packages are tools we run, not code we test, #}
|
||||
{# so don't instrument them #}
|
||||
{% else %}
|
||||
|
||||
{% if compiler == "msvc" %}
|
||||
|
||||
@@ -40,7 +40,7 @@ class Xrpl(ConanFile):
|
||||
"nudb/2.0.9",
|
||||
"openssl/3.6.3",
|
||||
"soci/4.0.3",
|
||||
"xrpl-rpc-spec/0.1.21",
|
||||
"xrpl-rpc-spec/0.1.19",
|
||||
"zlib/1.3.2",
|
||||
]
|
||||
|
||||
@@ -49,8 +49,7 @@ class Xrpl(ConanFile):
|
||||
]
|
||||
|
||||
tool_requires = [
|
||||
"grpc/<host_version>",
|
||||
"protobuf/<host_version>",
|
||||
"protobuf/6.33.5",
|
||||
]
|
||||
|
||||
default_options = {
|
||||
@@ -124,10 +123,6 @@ class Xrpl(ConanFile):
|
||||
"xxhash/*:shared": False,
|
||||
}
|
||||
|
||||
# default_options only reach the host context;
|
||||
# give tool_requires (and their dependencies) the same dependency options.
|
||||
default_build_options = {k: v for k, v in default_options.items() if "/" in k}
|
||||
|
||||
def set_version(self):
|
||||
self.version = self.version or DEV_VERSION
|
||||
|
||||
|
||||
@@ -80,12 +80,13 @@ function(add_xrpl_crate name)
|
||||
# `cc` picks its runtime flag from `crt-static` alone, so it compiles a
|
||||
# crate's C++ with `-MT`; Debug needs `-MTd` (to match cmake/XrplCompiler.cmake).
|
||||
if(is_msvc)
|
||||
corrosion_set_env_vars(${ARG_CRATE} "$<$<CONFIG:Debug>:CXXFLAGS=-MTd>")
|
||||
corrosion_set_env_vars(
|
||||
${ARG_CRATE}
|
||||
"$<$<CONFIG:Debug>:CXXFLAGS=-MTd>"
|
||||
)
|
||||
endif()
|
||||
corrosion_add_cxxbridge(
|
||||
${name}_cxxbridge
|
||||
CRATE ${ARG_CRATE}
|
||||
FILES ${ARG_FILES}
|
||||
corrosion_add_cxxbridge(${name}_cxxbridge CRATE ${ARG_CRATE} FILES
|
||||
${ARG_FILES}
|
||||
)
|
||||
# Generated cxxbridge headers don't exist at configure time; CMake 3.28+
|
||||
# validates INTERFACE_SOURCES on consuming targets. Clear it to skip the
|
||||
|
||||
16
docs/build/environment.md
vendored
16
docs/build/environment.md
vendored
@@ -10,15 +10,14 @@ This document explains how to set one up.
|
||||
support it — see [compiler support for C++23][cpp23-support].
|
||||
The versions currently tested in CI are:
|
||||
|
||||
| Compiler | Version |
|
||||
| ----------- | ------------------------------- |
|
||||
| GCC | `gccVersion` in [packages.nix] |
|
||||
| Clang | `llvmVersion` in [packages.nix] |
|
||||
| Apple Clang | 21 |
|
||||
| MSVC | Visual Studio 2026 |
|
||||
| Compiler | Version |
|
||||
| ----------- | ------------------ |
|
||||
| GCC | 15.2 |
|
||||
| Clang | 22 |
|
||||
| Apple Clang | 21 |
|
||||
| MSVC | Visual Studio 2026 |
|
||||
|
||||
LLVM tools (`clang-tidy` and `clang-format`)
|
||||
come from the same LLVM release as Clang.
|
||||
LLVM tools (`clang-tidy` and `clang-format`) are also pinned to version 22.
|
||||
|
||||
### Older compilers
|
||||
|
||||
@@ -157,4 +156,3 @@ version out of the box — run it via `run-clang-tidy`. No separate installation
|
||||
is needed.
|
||||
|
||||
[cpp23-support]: https://en.cppreference.com/w/cpp/compiler_support/23
|
||||
[packages.nix]: ../../nix/packages.nix
|
||||
|
||||
20
docs/build/nix.md
vendored
20
docs/build/nix.md
vendored
@@ -194,22 +194,10 @@ 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`. That is fine for the pinned
|
||||
glibc, whose path does not move, but not for the GCC runtime, which moves with
|
||||
every GCC update. So [`conan/profiles/default`](../../conan/profiles/default)
|
||||
links build-context packages, whose executables run during the build, with
|
||||
`-static-libstdc++ -static-libgcc -Wl,--as-needed`, and
|
||||
[`conan/profiles/sanitizers`](../../conan/profiles/sanitizers) does not
|
||||
instrument them. CI checks that they load nothing from the store but glibc, from
|
||||
the graph `conan install --format=json` writes:
|
||||
|
||||
```bash
|
||||
bin/check-build-context-runtime.sh graph.json
|
||||
```
|
||||
|
||||
Only the binaries [`PatchNixBinary.cmake`](../../cmake/PatchNixBinary.cmake)
|
||||
retargets to the system loader have to be fully clean, and those are what CI
|
||||
checks:
|
||||
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
|
||||
|
||||
2
external/antithesis-sdk/CMakeLists.txt
vendored
2
external/antithesis-sdk/CMakeLists.txt
vendored
@@ -6,7 +6,7 @@ project(antithesis-sdk-cpp VERSION 0.4.4 LANGUAGES CXX)
|
||||
add_library(antithesis-sdk-cpp INTERFACE antithesis_sdk.h)
|
||||
|
||||
# Note, both sections below created by xrpld project
|
||||
target_include_directories(antithesis-sdk-cpp SYSTEM INTERFACE
|
||||
target_include_directories(antithesis-sdk-cpp INTERFACE
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
)
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/type_name.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
|
||||
#include <boost/core/type_name.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* Manages all counted object types.
|
||||
*
|
||||
* Counters register themselves on a lock-free intrusive list maintained
|
||||
* by this object when constructed. Because counters are never destroyed
|
||||
* or removed, the ABA problem does not apply.
|
||||
*
|
||||
* The registry is iterable as a forward range.
|
||||
*/
|
||||
class CountedObjects
|
||||
{
|
||||
public:
|
||||
static CountedObjects&
|
||||
getInstance() noexcept;
|
||||
|
||||
using Entry = std::pair<std::string, int>;
|
||||
using List = std::vector<Entry>;
|
||||
|
||||
[[nodiscard]] List
|
||||
getCounts(int minimumThreshold) const;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Implementation for @ref CountedObject.
|
||||
@@ -33,68 +35,147 @@ public:
|
||||
class Counter
|
||||
{
|
||||
public:
|
||||
Counter(std::string name) noexcept : name_(std::move(name)), count_(0)
|
||||
{
|
||||
// Insert ourselves at the front of the lock-free linked list
|
||||
CountedObjects& instance = CountedObjects::getInstance();
|
||||
Counter* head = nullptr;
|
||||
Counter(std::string name) noexcept;
|
||||
|
||||
do
|
||||
{
|
||||
head = instance.head_.load();
|
||||
next_ = head;
|
||||
} while (instance.head_.exchange(this) != head);
|
||||
// Counters are intrusive list nodes whose addresses are published
|
||||
// in the registry; they must never be copied or moved. The atomic
|
||||
// members already force this, but we make it explicit.
|
||||
Counter(Counter const&) = delete;
|
||||
Counter&
|
||||
operator=(Counter const&) = delete;
|
||||
Counter(Counter&&) = delete;
|
||||
Counter&
|
||||
operator=(Counter&&) = delete;
|
||||
|
||||
++instance.count_;
|
||||
}
|
||||
|
||||
~Counter() noexcept = default;
|
||||
|
||||
int
|
||||
std::uint32_t
|
||||
increment() noexcept
|
||||
{
|
||||
return ++count_;
|
||||
auto const newCount = count_.fetch_add(1, std::memory_order::relaxed) + 1;
|
||||
XRPL_ASSERT(newCount != 0, "xrpl::CountedObjects::Counter::increment : no overflow");
|
||||
|
||||
auto maxCount = maxCount_.load(std::memory_order::relaxed);
|
||||
|
||||
while (newCount > maxCount &&
|
||||
!maxCount_.compare_exchange_weak(maxCount, newCount, std::memory_order::relaxed))
|
||||
{
|
||||
}
|
||||
|
||||
return newCount;
|
||||
}
|
||||
|
||||
int
|
||||
std::uint32_t
|
||||
decrement() noexcept
|
||||
{
|
||||
return --count_;
|
||||
auto const prev = count_.fetch_sub(1, std::memory_order::relaxed);
|
||||
XRPL_ASSERT(prev != 0, "xrpl::CountedObjects::Counter::decrement : no underflow");
|
||||
return prev - 1;
|
||||
}
|
||||
|
||||
[[nodiscard]] int
|
||||
getCount() const noexcept
|
||||
[[nodiscard]] std::uint32_t
|
||||
count() const noexcept
|
||||
{
|
||||
return count_.load();
|
||||
return count_.load(std::memory_order::relaxed);
|
||||
}
|
||||
|
||||
[[nodiscard]] Counter*
|
||||
getNext() const noexcept
|
||||
[[nodiscard]] std::uint32_t
|
||||
max() const noexcept
|
||||
{
|
||||
return next_;
|
||||
return std::max(
|
||||
count_.load(std::memory_order::relaxed),
|
||||
maxCount_.load(std::memory_order::relaxed));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string const&
|
||||
getName() const noexcept
|
||||
name() const noexcept
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class CountedObjects;
|
||||
|
||||
Counter* next_ = nullptr;
|
||||
std::atomic<std::uint32_t> count_ = 0;
|
||||
std::atomic<std::uint32_t> maxCount_ = 0;
|
||||
std::string const name_;
|
||||
std::atomic<int> count_;
|
||||
Counter* next_;
|
||||
};
|
||||
|
||||
private:
|
||||
CountedObjects() noexcept;
|
||||
~CountedObjects() noexcept = default;
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
using value_type = Counter const;
|
||||
using reference = value_type&;
|
||||
using pointer = value_type*;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
explicit Iterator(Counter* c = nullptr) noexcept : current_(c)
|
||||
{
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const noexcept
|
||||
{
|
||||
return *current_;
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const noexcept
|
||||
{
|
||||
return current_;
|
||||
}
|
||||
|
||||
Iterator&
|
||||
operator++() noexcept
|
||||
{
|
||||
current_ = current_->next_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator
|
||||
operator++(int) noexcept
|
||||
{
|
||||
auto tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(Iterator const&) const noexcept = default;
|
||||
|
||||
private:
|
||||
Counter* current_;
|
||||
};
|
||||
|
||||
constexpr CountedObjects() noexcept = default;
|
||||
|
||||
[[nodiscard]] auto
|
||||
begin() const noexcept
|
||||
{
|
||||
return Iterator{head_.load(std::memory_order::acquire)};
|
||||
}
|
||||
|
||||
[[nodiscard]] auto
|
||||
end() const noexcept
|
||||
{
|
||||
return Iterator{};
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<int> count_;
|
||||
std::atomic<Counter*> head_;
|
||||
std::atomic<Counter*> head_ = nullptr;
|
||||
};
|
||||
|
||||
/** The global counted object registry. */
|
||||
inline constinit CountedObjects gCountedObjects;
|
||||
|
||||
inline CountedObjects::Counter::Counter(std::string name) noexcept
|
||||
: next_(gCountedObjects.head_.load(std::memory_order::relaxed)), name_(std::move(name))
|
||||
{
|
||||
while (!gCountedObjects.head_.compare_exchange_weak(
|
||||
next_, this, std::memory_order::release, std::memory_order::relaxed))
|
||||
;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -103,27 +184,37 @@ private:
|
||||
* Derived classes have their instances counted automatically. This is used
|
||||
* for reporting purposes.
|
||||
*
|
||||
* The constructors are private and `Object` is befriended so that the
|
||||
* CRTP parameter must be the deriving class itself: a copy-paste error
|
||||
* like `class B : public CountedObject<A>` fails to compile instead of
|
||||
* silently polluting A's count.
|
||||
*
|
||||
* @note This class has no move operations by design: a derived class's
|
||||
* move constructor falls back to the copy constructor for this
|
||||
* base, so the newly created instance is counted. This keeps the
|
||||
* invariant that count is the number of outstanding subobjects.
|
||||
*
|
||||
* @warning Counted objects constructed during dynamic initialization of
|
||||
* other translation units may have their increments discarded when
|
||||
* counter itself is dynamically initialized. Do not create counted
|
||||
* objects before main() begins.
|
||||
*
|
||||
* @ingroup basics
|
||||
*/
|
||||
template <class Object>
|
||||
requires std::is_class_v<Object>
|
||||
class CountedObject
|
||||
{
|
||||
private:
|
||||
static auto&
|
||||
getCounter() noexcept
|
||||
{
|
||||
static CountedObjects::Counter kC{beast::typeName<Object>()};
|
||||
return kC;
|
||||
}
|
||||
static inline CountedObjects::Counter counter{boost::core::type_name<Object>()};
|
||||
|
||||
CountedObject() noexcept
|
||||
{
|
||||
getCounter().increment();
|
||||
counter.increment();
|
||||
}
|
||||
|
||||
CountedObject(CountedObject const&) noexcept
|
||||
{
|
||||
getCounter().increment();
|
||||
counter.increment();
|
||||
}
|
||||
|
||||
CountedObject&
|
||||
@@ -132,7 +223,7 @@ private:
|
||||
public:
|
||||
~CountedObject() noexcept
|
||||
{
|
||||
getCounter().decrement();
|
||||
counter.decrement();
|
||||
}
|
||||
|
||||
friend Object;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -253,4 +253,27 @@ makeSlice(std::basic_string_view<char, Traits> s)
|
||||
return Slice(s.data(), s.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether two byte ranges share at least one byte of storage.
|
||||
*
|
||||
* Each slice is treated as the half-open range [data, data + size), so
|
||||
* ranges that merely touch do not overlap. An empty slice overlaps
|
||||
* nothing, wherever it points.
|
||||
*
|
||||
* @param a The first range.
|
||||
* @param b The second range.
|
||||
* @return true if the ranges overlap, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] inline bool
|
||||
overlap(Slice a, Slice b) noexcept
|
||||
{
|
||||
if (a.empty() || b.empty())
|
||||
return false;
|
||||
|
||||
auto const a0 = reinterpret_cast<std::uintptr_t>(a.data());
|
||||
auto const b0 = reinterpret_cast<std::uintptr_t>(b.data());
|
||||
|
||||
return a0 < b0 + b.size() && b0 < a0 + a.size();
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/Blob.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
|
||||
#include <boost/utility/string_view.hpp>
|
||||
|
||||
@@ -28,7 +29,7 @@ namespace xrpl {
|
||||
* @return The input, encoded as a blob literal.
|
||||
*/
|
||||
std::string
|
||||
sqlBlobLiteral(Blob const& blob);
|
||||
sqlBlobLiteral(Slice blob);
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/sanitizers.h>
|
||||
#include <xrpl/beast/type_name.h>
|
||||
|
||||
#include <boost/core/type_name.hpp>
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
@@ -55,7 +56,7 @@ Throw(Args&&... args)
|
||||
std::is_convertible_v<E*, std::exception*>, "Exception must derive from std::exception.");
|
||||
|
||||
E e(std::forward<Args>(args)...);
|
||||
logThrow(std::string("Throwing exception of type " + beast::typeName<E>() + ": ") + e.what());
|
||||
logThrow("Throwing exception of type " + boost::core::type_name<E>() + ": " + e.what());
|
||||
throw std::move(e);
|
||||
}
|
||||
|
||||
|
||||
200
include/xrpl/basics/enum_bitops.h
Normal file
200
include/xrpl/basics/enum_bitops.h
Normal file
@@ -0,0 +1,200 @@
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* Opt-in bitwise operators for scoped enumerations.
|
||||
*
|
||||
* Provides `&`, `|`, `^`, `~` and the corresponding compound assignment forms
|
||||
* for any scoped enumeration with an unsigned underlying type that opts in by
|
||||
* specializing @ref OptIn:
|
||||
*
|
||||
* @code
|
||||
* namespace xrpl {
|
||||
*
|
||||
* enum class MyFlags : std::uint32_t { a = 1, b = 2, c = 4 };
|
||||
*
|
||||
* template <>
|
||||
* struct enum_bitops::OptIn<MyFlags> : std::true_type {};
|
||||
*
|
||||
* } // namespace xrpl
|
||||
* @endcode
|
||||
*
|
||||
* The operators are constexpr and noexcept, and return the enumeration type.
|
||||
*
|
||||
* @par Where the specialization may be declared
|
||||
* In namespace xrpl, or at global scope with full qualification, and after
|
||||
* the enumeration is defined but before the operators are first used. This
|
||||
* cannot be done in a nested namespace or at class scope; for enumerations
|
||||
* nested in a class this means after the class definition.
|
||||
*
|
||||
* @par Where the operators are found
|
||||
* The operators are declared in namespace xrpl, so argument-dependent lookup
|
||||
* will find them only for enumerations declared in xrpl or nested in a class
|
||||
* declared directly in xrpl. Enumerations in a nested namespace will only be
|
||||
* found from code inside xrpl, and only if no enclosing scope declares an
|
||||
* operator of the same name; elsewhere they require using-declarations.
|
||||
*/
|
||||
namespace enum_bitops {
|
||||
|
||||
/**
|
||||
* Types that may be opted in to the bitwise operators.
|
||||
*
|
||||
* Satisfied by a scoped enumeration whose underlying type is an unsigned
|
||||
* integer type.
|
||||
*
|
||||
* @tparam T The type to test.
|
||||
*/
|
||||
template <typename T>
|
||||
concept Eligible = std::is_scoped_enum_v<T> && std::unsigned_integral<std::underlying_type_t<T>>;
|
||||
|
||||
/**
|
||||
* Opt-in switch for the bitwise operators.
|
||||
*
|
||||
* The primary template derives from std::false_type. Specialize it to derive
|
||||
* from std::true_type to enable the operators for an @ref Eligible enumeration.
|
||||
*
|
||||
* @tparam T The scoped enumeration to opt in.
|
||||
*/
|
||||
template <Eligible T>
|
||||
struct OptIn : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* Enumerations for which the bitwise operators are enabled.
|
||||
*
|
||||
* Satisfied when @p T satisfies @ref Eligible and @ref OptIn has been
|
||||
* specialized for it to derive from std::true_type.
|
||||
*
|
||||
* @tparam T The type to test.
|
||||
*/
|
||||
template <typename T>
|
||||
concept Candidate = Eligible<T> && OptIn<T>::value;
|
||||
|
||||
} // namespace enum_bitops
|
||||
|
||||
// These are declared in xrpl, not in enum_bitops, so that argument-dependent
|
||||
// lookup finds them for enumerations whose associated namespace is xrpl.
|
||||
|
||||
/**
|
||||
* @name Bitwise operators for opted-in scoped enumerations
|
||||
*
|
||||
* Each operator applies the corresponding built-in operator to the
|
||||
* underlying values and converts the result back to the enumeration type.
|
||||
* Both operands must have the same enumeration type; there is no implicit
|
||||
* conversion to or from the underlying type.
|
||||
*/
|
||||
/** @{ */
|
||||
|
||||
/**
|
||||
* Bitwise AND.
|
||||
*
|
||||
* @param lhs The left operand.
|
||||
* @param rhs The right operand.
|
||||
* @return The bits set in both @p lhs and @p rhs.
|
||||
*/
|
||||
template <enum_bitops::Candidate T>
|
||||
constexpr T
|
||||
operator&(T lhs, T rhs) noexcept
|
||||
{
|
||||
return static_cast<T>(std::to_underlying(lhs) & std::to_underlying(rhs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Bitwise OR.
|
||||
*
|
||||
* @param lhs The left operand.
|
||||
* @param rhs The right operand.
|
||||
* @return The bits set in @p lhs, in @p rhs, or in both.
|
||||
*/
|
||||
template <enum_bitops::Candidate T>
|
||||
constexpr T
|
||||
operator|(T lhs, T rhs) noexcept
|
||||
{
|
||||
return static_cast<T>(std::to_underlying(lhs) | std::to_underlying(rhs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Bitwise exclusive OR.
|
||||
*
|
||||
* @param lhs The left operand.
|
||||
* @param rhs The right operand.
|
||||
* @return The bits set in exactly one of @p lhs and @p rhs.
|
||||
*/
|
||||
template <enum_bitops::Candidate T>
|
||||
constexpr T
|
||||
operator^(T lhs, T rhs) noexcept
|
||||
{
|
||||
return static_cast<T>(std::to_underlying(lhs) ^ std::to_underlying(rhs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Bitwise complement.
|
||||
*
|
||||
* The result has every bit of the underlying type that is clear in
|
||||
* @p val, including bits that no enumerator names. It is intended for
|
||||
* clearing flags, as in `flags & ~flag`.
|
||||
*
|
||||
* @param val The operand.
|
||||
* @return The complement of @p val.
|
||||
*/
|
||||
template <enum_bitops::Candidate T>
|
||||
constexpr T
|
||||
operator~(T val) noexcept
|
||||
{
|
||||
return static_cast<T>(~std::to_underlying(val));
|
||||
}
|
||||
|
||||
/**
|
||||
* Bitwise AND assignment.
|
||||
*
|
||||
* @param lhs The value to modify.
|
||||
* @param rhs The right operand.
|
||||
* @return A reference to @p lhs.
|
||||
*/
|
||||
template <enum_bitops::Candidate T>
|
||||
constexpr T&
|
||||
operator&=(T& lhs, T rhs) noexcept
|
||||
{
|
||||
lhs = lhs & rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bitwise OR assignment.
|
||||
*
|
||||
* @param lhs The value to modify.
|
||||
* @param rhs The right operand.
|
||||
* @return A reference to @p lhs.
|
||||
*/
|
||||
template <enum_bitops::Candidate T>
|
||||
constexpr T&
|
||||
operator|=(T& lhs, T rhs) noexcept
|
||||
{
|
||||
lhs = lhs | rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bitwise exclusive OR assignment.
|
||||
*
|
||||
* @param lhs The value to modify.
|
||||
* @param rhs The right operand.
|
||||
* @return A reference to @p lhs.
|
||||
*/
|
||||
template <enum_bitops::Candidate T>
|
||||
constexpr T&
|
||||
operator^=(T& lhs, T rhs) noexcept
|
||||
{
|
||||
lhs = lhs ^ rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -17,7 +17,7 @@
|
||||
namespace xrpl {
|
||||
|
||||
template <typename Key>
|
||||
std::size_t
|
||||
static std::size_t
|
||||
extract(Key const& key)
|
||||
{
|
||||
return key;
|
||||
|
||||
@@ -2,107 +2,212 @@
|
||||
|
||||
#include <xrpl/beast/utility/instrumentation.h> // IWYU pragma: keep
|
||||
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// safe_cast adds compile-time checks to a static_cast to ensure that
|
||||
// the destination can hold all values of the source. This is particularly
|
||||
// handy when the source or destination is an enumeration type.
|
||||
/** Every value of @p Src can be represented by @p Dest.
|
||||
|
||||
template <class Src, class Dest>
|
||||
concept SafeToCast = (std::is_integral_v<Src> && std::is_integral_v<Dest>) &&
|
||||
(std::is_signed_v<Src> || std::is_unsigned_v<Dest>) &&
|
||||
(std::is_signed_v<Src> != std::is_signed_v<Dest> ? sizeof(Dest) > sizeof(Src)
|
||||
: sizeof(Dest) >= sizeof(Src));
|
||||
Given two integral types, the cast is safe when the destination can
|
||||
hold every possible value of the source.
|
||||
|
||||
template <class Dest, class Src>
|
||||
Comparing the bounds requires care: we use @c std::cmp_less_equal and
|
||||
@c std::cmp_greater_equal; the plain relational operators would apply
|
||||
arithmetic conversions, resulting in incorrect results when comparing
|
||||
across signedness.
|
||||
|
||||
Because @c std::cmp_* requires standard signed or unsigned integer
|
||||
arguments, which excludes character types and bool, we first widen
|
||||
all type bounds to the maximum-width integer type while preserving
|
||||
signedness.
|
||||
|
||||
@note Extended integer types, like __int128 on gcc, cannot be safely
|
||||
widened to a standard integer type, so the concept will reject
|
||||
them.
|
||||
*/
|
||||
template <typename Src, typename Dest>
|
||||
concept SafeToCast = std::is_integral_v<Src> && std::is_integral_v<Dest> && []() consteval {
|
||||
using WideSrc = std::conditional_t<std::is_signed_v<Src>, std::intmax_t, std::uintmax_t>;
|
||||
using WideDest = std::conditional_t<std::is_signed_v<Dest>, std::intmax_t, std::uintmax_t>;
|
||||
|
||||
// Note: this guard must be an evaluated branch, and not a
|
||||
// static_assert. The lambda body is outside the immediate
|
||||
// context, so a substitution-time failure here would be a
|
||||
// hard error rather than leaving the concept unsatisfied.
|
||||
if constexpr (sizeof(Src) > sizeof(WideSrc) || sizeof(Dest) > sizeof(WideDest))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::cmp_less_equal(
|
||||
static_cast<WideDest>(std::numeric_limits<Dest>::min()),
|
||||
static_cast<WideSrc>(std::numeric_limits<Src>::min())) &&
|
||||
std::cmp_greater_equal(
|
||||
static_cast<WideDest>(std::numeric_limits<Dest>::max()),
|
||||
static_cast<WideSrc>(std::numeric_limits<Src>::max()));
|
||||
}
|
||||
}();
|
||||
|
||||
/** Compile-time-checked static_cast that rejects non-value preserving casts.
|
||||
|
||||
@note There is deliberately no enum-to-enum overload, and no overload
|
||||
returning the underlying type of an enum. For the latter, use
|
||||
@c std::to_underlying.
|
||||
*/
|
||||
/** @{ */
|
||||
template <typename Dest, typename Src>
|
||||
requires(std::is_integral_v<Dest> && std::is_integral_v<Src>)
|
||||
constexpr Dest
|
||||
safeCast(Src s) noexcept
|
||||
requires(std::is_integral_v<Dest> && std::is_integral_v<Src>)
|
||||
{
|
||||
static_assert(
|
||||
std::is_signed_v<Dest> || std::is_unsigned_v<Src>, "Cannot cast signed to unsigned");
|
||||
constexpr unsigned kNotSame = std::is_signed_v<Dest> != std::is_signed_v<Src>;
|
||||
static_assert(
|
||||
sizeof(Dest) >= sizeof(Src) + kNotSame,
|
||||
"Destination is too small to hold all values of source");
|
||||
SafeToCast<Src, Dest>, "This cast is not value-preserving. Please use unsafeCast instead.");
|
||||
return static_cast<Dest>(s);
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
template <typename Dest, typename Src>
|
||||
requires(std::is_enum_v<Dest> && std::is_integral_v<Src>)
|
||||
constexpr Dest
|
||||
safeCast(Src s) noexcept
|
||||
requires(std::is_enum_v<Dest> && std::is_integral_v<Src>)
|
||||
{
|
||||
return static_cast<Dest>(safeCast<std::underlying_type_t<Dest>>(s));
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
template <typename Dest, typename Src>
|
||||
requires(std::is_integral_v<Dest> && std::is_enum_v<Src>)
|
||||
constexpr Dest
|
||||
safeCast(Src s) noexcept
|
||||
requires(std::is_integral_v<Dest> && std::is_enum_v<Src>)
|
||||
{
|
||||
return safeCast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
|
||||
return safeCast<Dest>(std::to_underlying(s));
|
||||
}
|
||||
/** @} */
|
||||
|
||||
// unsafe_cast explicitly flags a static_cast as not necessarily able to hold
|
||||
// all values of the source. It includes a compile-time check so that if
|
||||
// underlying types become safe, it can be converted to a safe_cast.
|
||||
/** Integral-to-integral cast that is known to be narrowing or sign-erasing.
|
||||
|
||||
template <class Dest, class Src>
|
||||
This explicitly flags a conversion that can lose information for some
|
||||
values of the source type, where the call site accepts that loss (or
|
||||
truncation is the intended behavior).
|
||||
|
||||
The compile-time check ensures the cast remains "unsafe": if the types
|
||||
involved later change such that the conversion becomes inherently
|
||||
value-preserving, the static assertion fires with instructions to
|
||||
migrate the call site to @ref safeCast.
|
||||
|
||||
If the conversion's safety depends on a runtime precondition rather
|
||||
than on the types, or varies across instantiations of generic code,
|
||||
use @ref checkedCast instead.
|
||||
*/
|
||||
/** @{ */
|
||||
template <typename Dest, typename Src>
|
||||
requires(std::is_integral_v<Dest> && std::is_integral_v<Src>)
|
||||
constexpr Dest
|
||||
unsafeCast(Src s) noexcept
|
||||
requires(std::is_integral_v<Dest> && std::is_integral_v<Src>)
|
||||
{
|
||||
static_assert(
|
||||
!SafeToCast<Src, Dest>,
|
||||
"Only unsafe if casting signed to unsigned or "
|
||||
"destination is too small");
|
||||
!SafeToCast<Src, Dest>, "This cast is value-preserving. Please use safeCast instead.");
|
||||
return static_cast<Dest>(s);
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
template <typename Dest, typename Src>
|
||||
requires(std::is_enum_v<Dest> && std::is_integral_v<Src>)
|
||||
constexpr Dest
|
||||
unsafeCast(Src s) noexcept
|
||||
requires(std::is_enum_v<Dest> && std::is_integral_v<Src>)
|
||||
{
|
||||
return static_cast<Dest>(unsafeCast<std::underlying_type_t<Dest>>(s));
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
template <typename Dest, typename Src>
|
||||
requires(std::is_integral_v<Dest> && std::is_enum_v<Src>)
|
||||
constexpr Dest
|
||||
unsafeCast(Src s) noexcept
|
||||
requires(std::is_integral_v<Dest> && std::is_enum_v<Src>)
|
||||
{
|
||||
return unsafeCast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
|
||||
return unsafeCast<Dest>(std::to_underlying(s));
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Integral-to-integral cast when the caller has performed a bounds check.
|
||||
|
||||
This documents that a runtime precondition or external invariant, which
|
||||
is not necessarily visible to the compiler, guarantees that the requested
|
||||
conversion is value-preserving for the values that can actually occur.
|
||||
|
||||
This is primarily meant for generic code, where the same expression may
|
||||
be value-preserving for one instantiation but not for another, making
|
||||
both @ref safeCast and @ref unsafeCast unusable.
|
||||
|
||||
Unlike @ref safeCast and @ref unsafeCast, this imposes no static check
|
||||
on the type relationship: the caller's claim is about runtime values,
|
||||
not about types.
|
||||
*/
|
||||
/** @{ */
|
||||
template <typename Dest, typename Src>
|
||||
requires(std::is_integral_v<Dest> && std::is_integral_v<Src>)
|
||||
constexpr Dest
|
||||
checkedCast(Src s) noexcept
|
||||
{
|
||||
return static_cast<Dest>(s);
|
||||
}
|
||||
|
||||
template <typename Dest, typename Src>
|
||||
requires(std::is_enum_v<Dest> && std::is_integral_v<Src>)
|
||||
constexpr Dest
|
||||
checkedCast(Src s) noexcept
|
||||
{
|
||||
return static_cast<Dest>(checkedCast<std::underlying_type_t<Dest>>(s));
|
||||
}
|
||||
|
||||
template <typename Dest, typename Src>
|
||||
requires(std::is_integral_v<Dest> && std::is_enum_v<Src>)
|
||||
constexpr Dest
|
||||
checkedCast(Src s) noexcept
|
||||
{
|
||||
return checkedCast<Dest>(std::to_underlying(s));
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Downcast within a class hierarchy, verified in debug builds.
|
||||
|
||||
Performs a static_cast down a hierarchy, but in debug builds verifies
|
||||
via dynamic_cast that the object's dynamic type actually permits the
|
||||
downcast. Both build modes execute the same conversion; debug builds
|
||||
merely add the check.
|
||||
|
||||
The pointer form passes null through unchanged, as dynamic_cast does.
|
||||
|
||||
@note The check requires @p Src to be polymorphic; in release builds
|
||||
an invalid downcast is undefined behavior on use, exactly as
|
||||
with a bare static_cast.
|
||||
*/
|
||||
/** @{ */
|
||||
template <class Dest, class Src>
|
||||
requires std::is_pointer_v<Dest>
|
||||
requires(
|
||||
std::is_pointer_v<Dest> && std::is_polymorphic_v<Src> &&
|
||||
std::derived_from<std::remove_pointer_t<Dest>, Src> &&
|
||||
(std::is_const_v<std::remove_pointer_t<Dest>> || !std::is_const_v<Src>) &&
|
||||
(std::is_volatile_v<std::remove_pointer_t<Dest>> || !std::is_volatile_v<Src>))
|
||||
inline Dest
|
||||
safeDowncast(Src* s) noexcept
|
||||
{
|
||||
#ifdef NDEBUG
|
||||
XRPL_ASSERT(
|
||||
s == nullptr || dynamic_cast<Dest>(s) != nullptr, "xrpl::safeDowncast : valid downcast");
|
||||
return static_cast<Dest>(s); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||
#else
|
||||
auto* result = dynamic_cast<Dest>(s);
|
||||
XRPL_ASSERT(result != nullptr, "xrpl::safeDowncast : pointer downcast is valid");
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
requires std::is_lvalue_reference_v<Dest>
|
||||
requires(
|
||||
std::is_lvalue_reference_v<Dest> && std::is_polymorphic_v<Src> &&
|
||||
std::derived_from<std::remove_reference_t<Dest>, Src>)
|
||||
inline Dest
|
||||
safeDowncast(Src& s) noexcept
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
XRPL_ASSERT(
|
||||
dynamic_cast<std::add_pointer_t<std::remove_reference_t<Dest>>>(&s) != nullptr,
|
||||
"xrpl::safeDowncast : reference downcast is valid");
|
||||
#endif
|
||||
return static_cast<Dest>(s); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||
return *safeDowncast<std::add_pointer_t<std::remove_reference_t<Dest>>>(std::addressof(s));
|
||||
}
|
||||
/** @} */
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -4,88 +4,215 @@
|
||||
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
|
||||
#include <boost/predef/architecture.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <concepts>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#ifndef __aarch64__
|
||||
#if BOOST_ARCH_X86
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/** An unsigned integral type suitable for use as a spinlock.
|
||||
|
||||
The type must be always lock-free when wrapped in std::atomic, so
|
||||
that lock operations cannot themselves take a (library-level) lock.
|
||||
*/
|
||||
template <typename T>
|
||||
concept SpinlockValueType = std::is_unsigned_v<T> && std::atomic<T>::is_always_lock_free;
|
||||
|
||||
/** A spinlock value type that additionally supports the atomic bitwise
|
||||
operations required to pack multiple locks into a single integer.
|
||||
*/
|
||||
template <typename T>
|
||||
concept PackedSpinlockValueType = SpinlockValueType<T> && requires(std::atomic<T>& a, T v) {
|
||||
{ a.fetch_or(v) } -> std::same_as<T>;
|
||||
{ a.fetch_and(v) } -> std::same_as<T>;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
/**
|
||||
* Inform the processor that we are in a tight spin-wait loop.
|
||||
*
|
||||
* Spinlocks caught in tight loops can result in the processor's pipeline
|
||||
* filling up with comparison operations, resulting in a misprediction at
|
||||
* the time the lock is finally acquired, necessitating pipeline flushing
|
||||
* which is ridiculously expensive and results in very high latency.
|
||||
*
|
||||
* This function instructs the processor to "pause" for some architecture
|
||||
* specific amount of time, to prevent this.
|
||||
|
||||
/** Inform the processor that we are in a tight spin-wait loop.
|
||||
|
||||
Spinlocks caught in tight loops can result in the processor's pipeline
|
||||
filling up with comparison operations, resulting in a misprediction at
|
||||
the time the lock is finally acquired, necessitating pipeline flushing
|
||||
which is ridiculously expensive and results in very high latency.
|
||||
|
||||
This function instructs the processor to "pause" for some architecture
|
||||
specific amount of time, to prevent this.
|
||||
*/
|
||||
inline void
|
||||
spinPause() noexcept
|
||||
{
|
||||
#ifdef __aarch64__
|
||||
asm volatile("yield");
|
||||
#else
|
||||
#if BOOST_ARCH_X86
|
||||
_mm_pause();
|
||||
#elif BOOST_ARCH_ARM
|
||||
asm volatile("yield" ::: "memory");
|
||||
#else
|
||||
#error No implementation available for spinPause to use
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** @{ */
|
||||
/**
|
||||
* Classes to handle arrays of spinlocks packed into a single atomic integer:
|
||||
*
|
||||
* Packed spinlocks allow for tremendously space-efficient lock-sharding
|
||||
* but they come at a cost.
|
||||
*
|
||||
* First, the implementation is necessarily low-level and uses advanced
|
||||
* features like memory ordering and highly platform-specific tricks to
|
||||
* maximize performance. This imposes a significant and ongoing cost to
|
||||
* developers.
|
||||
*
|
||||
* Second, and perhaps most important, is that the packing of multiple
|
||||
* locks into a single integer which, albeit space-efficient, also has
|
||||
* performance implications stemming from data dependencies, increased
|
||||
* cache-coherency traffic between processors and heavier loads on the
|
||||
* processor's load/store units.
|
||||
*
|
||||
* To be sure, these locks can have advantages but they are definitely
|
||||
* not general purpose locks and should not be thought of or used that
|
||||
* way. The use cases for them are likely few and far between; without
|
||||
* a compelling reason to use them, backed by profiling data, it might
|
||||
* be best to use one of the standard locking primitives instead. Note
|
||||
* that in most common platforms, `std::mutex` is so heavily optimized
|
||||
* that it can, usually, outperform spinlocks.
|
||||
*
|
||||
* @tparam T An unsigned integral type (e.g. std::uint16_t)
|
||||
*/
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A class that grabs a single packed spinlock from an atomic integer.
|
||||
*
|
||||
* This class meets the requirements of Lockable:
|
||||
* https://en.cppreference.com/w/cpp/named_req/Lockable
|
||||
/** Attempt to acquire a spinlock without blocking.
|
||||
|
||||
@note This interface is primarily intended for one-shot attempts to
|
||||
acquire the lock. Avoid calling this function directly from a
|
||||
loop and use @ref spinLock instead.
|
||||
|
||||
@tparam T An unsigned integral type.
|
||||
@param lock The atomic variable used as the lock.
|
||||
@return true if the lock was acquired, false if it was already held.
|
||||
*/
|
||||
template <class T>
|
||||
template <SpinlockValueType T>
|
||||
[[nodiscard]] bool
|
||||
spinTryLock(std::atomic<T>& lock) noexcept
|
||||
{
|
||||
// A compare-exchange is required here, not an unconditional exchange:
|
||||
// a failed attempt must not modify the lock word, in case the atomic
|
||||
// is shared with PackedSpinlock).
|
||||
T expected = 0;
|
||||
|
||||
return lock.compare_exchange_strong(
|
||||
expected,
|
||||
std::numeric_limits<T>::max(),
|
||||
std::memory_order::acquire,
|
||||
std::memory_order::relaxed);
|
||||
;
|
||||
}
|
||||
|
||||
/** Acquire a spinlock, blocking until available.
|
||||
|
||||
Uses a TTAS (test-and-test-and-set) pattern, so waiters share the cache
|
||||
line read-only, helping to avoid unnecessary coherency traffic.
|
||||
|
||||
@tparam T An unsigned integral type.
|
||||
@param lock The atomic variable used as the lock.
|
||||
*/
|
||||
template <SpinlockValueType T>
|
||||
void
|
||||
spinLock(std::atomic<T>& lock) noexcept
|
||||
{
|
||||
do
|
||||
{
|
||||
// Relaxed ordering is sufficient for the spin: this load is only
|
||||
// a filter. The acquire on the successful exchange in spinTryLock
|
||||
// is what synchronizes the critical section.
|
||||
while (lock.load(std::memory_order::relaxed) != 0)
|
||||
detail::spinPause();
|
||||
} while (!spinTryLock(lock));
|
||||
}
|
||||
|
||||
/** Release a spinlock.
|
||||
|
||||
@tparam T An unsigned integral type.
|
||||
@param lock The atomic variable used as the lock.
|
||||
*/
|
||||
template <SpinlockValueType T>
|
||||
void
|
||||
spinUnlock(std::atomic<T>& lock) noexcept
|
||||
{
|
||||
lock.store(0, std::memory_order::release);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** A Lockable interface to a spinlock implemented on top of an atomic.
|
||||
|
||||
@tparam T An unsigned integral type.
|
||||
|
||||
@note Using `PackedSpinlock` and `Spinlock` against the same underlying
|
||||
atomic integer is possible but can result in `Spinlock` not being
|
||||
able to acquire the lock during periods of high contention due to
|
||||
the way the two locks operate: `Spinlock` spins and tries to grab
|
||||
all the bits at once, whereas any given `PackedSpinlock` instance
|
||||
only tries to grab one bit at a time. Caveat emptor.
|
||||
|
||||
This class meets the requirements of Lockable:
|
||||
https://en.cppreference.com/w/cpp/named_req/Lockable
|
||||
*/
|
||||
template <SpinlockValueType T>
|
||||
class Spinlock
|
||||
{
|
||||
std::atomic<T>& lock_;
|
||||
|
||||
public:
|
||||
Spinlock(Spinlock const&) = delete;
|
||||
Spinlock&
|
||||
operator=(Spinlock const&) = delete;
|
||||
|
||||
/** Construct a spinlock handle.
|
||||
|
||||
@param lock The atomic integer to spin against.
|
||||
|
||||
@note For performance reasons, you should strive to have `lock` be
|
||||
on a cacheline by itself.
|
||||
*/
|
||||
explicit Spinlock(std::atomic<T>& lock) noexcept : lock_(lock)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
try_lock() noexcept // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return spinTryLock(lock_);
|
||||
}
|
||||
|
||||
void
|
||||
lock() noexcept
|
||||
{
|
||||
spinLock(lock_);
|
||||
}
|
||||
|
||||
void
|
||||
unlock() noexcept
|
||||
{
|
||||
spinUnlock(lock_);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** A Lockable interface to a packed spinlock implemented on top of an atomic.
|
||||
|
||||
Packed spinlocks offer tremendous space-efficient lock-sharding but
|
||||
they come at a cost.
|
||||
|
||||
First, the implementation is necessarily low-level and uses advanced
|
||||
features like memory ordering and highly platform-specific tricks to
|
||||
maximize performance. This imposes a significant and ongoing cost to
|
||||
developers.
|
||||
|
||||
Second, and perhaps most important, is that the packing of multiple
|
||||
locks into a single integer which, albeit space-efficient, also has
|
||||
performance implications stemming from data dependencies, increased
|
||||
cache-coherency traffic between processors and heavier loads on the
|
||||
processor's load/store units.
|
||||
|
||||
To be sure, these locks can have advantages but they are definitely
|
||||
not general purpose locks and should not be thought of or used that
|
||||
way. The use cases for them are likely few and far between; without
|
||||
a compelling reason to use them, backed by profiling data, it might
|
||||
be best to use one of the standard locking primitives instead. Note
|
||||
that in most common platforms, `std::mutex` is so heavily optimized
|
||||
that it can, usually, outperform spinlocks.
|
||||
|
||||
@tparam T An unsigned integral type (e.g. std::uint16_t)
|
||||
|
||||
This class meets the requirements of Lockable:
|
||||
https://en.cppreference.com/w/cpp/named_req/Lockable
|
||||
*/
|
||||
template <PackedSpinlockValueType T>
|
||||
class PackedSpinlock
|
||||
{
|
||||
// clang-format off
|
||||
static_assert(std::is_unsigned_v<T>);
|
||||
static_assert(std::atomic<T>::is_always_lock_free);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(std::declval<std::atomic<T>&>().fetch_or(0)), T> &&
|
||||
std::is_same_v<decltype(std::declval<std::atomic<T>&>().fetch_and(0)), T>,
|
||||
"std::atomic<T>::fetch_and(T) and std::atomic<T>::fetch_and(T) are required by packed_spinlock");
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
std::atomic<T>& bits_;
|
||||
T const mask_;
|
||||
|
||||
@@ -94,120 +221,49 @@ public:
|
||||
PackedSpinlock&
|
||||
operator=(PackedSpinlock const&) = delete;
|
||||
|
||||
/**
|
||||
* A single spinlock packed inside the specified atomic
|
||||
*
|
||||
* @param lock The atomic integer inside which the spinlock is packed.
|
||||
* @param index The index of the spinlock this object acquires.
|
||||
*
|
||||
* @note For performance reasons, you should strive to have `lock` be
|
||||
* on a cacheline by itself.
|
||||
/** Construct a packed spinlock handle for a single bit.
|
||||
|
||||
@param lock The atomic integer inside which the spinlock is packed.
|
||||
@param index The index of the spinlock this object acquires.
|
||||
|
||||
@note For performance reasons, you should strive to have `lock` be
|
||||
on a cacheline by itself.
|
||||
*/
|
||||
PackedSpinlock(std::atomic<T>& lock, int index) : bits_(lock), mask_(static_cast<T>(1) << index)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
index >= 0 && (mask_ != 0),
|
||||
"xrpl::PackedSpinlock::PackedSpinlock : valid index and mask");
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
try_lock() // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return (bits_.fetch_or(mask_, std::memory_order_acquire) & mask_) == 0;
|
||||
}
|
||||
|
||||
void
|
||||
lock()
|
||||
{
|
||||
while (!try_lock())
|
||||
{
|
||||
// The use of relaxed memory ordering here is intentional and
|
||||
// serves to help reduce cache coherency traffic during times
|
||||
// of contention by avoiding writes that would definitely not
|
||||
// result in the lock being acquired.
|
||||
while ((bits_.load(std::memory_order_relaxed) & mask_) != 0)
|
||||
detail::spinPause();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
unlock()
|
||||
{
|
||||
bits_.fetch_and(~mask_, std::memory_order_release);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A spinlock implemented on top of an atomic integer.
|
||||
*
|
||||
* @note Using `packed_spinlock` and `spinlock` against the same underlying
|
||||
* atomic integer can result in `spinlock` not being able to actually
|
||||
* acquire the lock during periods of high contention, because of how
|
||||
* the two locks operate: `spinlock` will spin trying to grab all the
|
||||
* bits at once, whereas any given `packed_spinlock` will only try to
|
||||
* grab one bit at a time. Caveat emptor.
|
||||
*
|
||||
* This class meets the requirements of Lockable:
|
||||
* https://en.cppreference.com/w/cpp/named_req/Lockable
|
||||
*/
|
||||
template <class T>
|
||||
class Spinlock
|
||||
{
|
||||
static_assert(std::is_unsigned_v<T>);
|
||||
static_assert(std::atomic<T>::is_always_lock_free);
|
||||
|
||||
private:
|
||||
std::atomic<T>& lock_;
|
||||
|
||||
public:
|
||||
Spinlock(Spinlock const&) = delete;
|
||||
Spinlock&
|
||||
operator=(Spinlock const&) = delete;
|
||||
|
||||
/**
|
||||
* Grabs the
|
||||
*
|
||||
* @param lock The atomic integer to spin against.
|
||||
*
|
||||
* @note For performance reasons, you should strive to have `lock` be
|
||||
* on a cacheline by itself.
|
||||
*/
|
||||
Spinlock(std::atomic<T>& lock) : lock_(lock)
|
||||
PackedSpinlock(std::atomic<T>& lock, int index) noexcept
|
||||
: bits_(lock), mask_([index]() {
|
||||
XRPL_ASSERT(
|
||||
index >= 0 && index < std::numeric_limits<T>::digits,
|
||||
"xrpl::PackedSpinlock::PackedSpinlock : valid index");
|
||||
return static_cast<T>(T{1} << index);
|
||||
}())
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
try_lock() // NOLINT(readability-identifier-naming)
|
||||
try_lock() noexcept // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
T expected = 0;
|
||||
|
||||
return lock_.compare_exchange_weak(
|
||||
expected,
|
||||
std::numeric_limits<T>::max(),
|
||||
std::memory_order_acquire,
|
||||
std::memory_order_relaxed);
|
||||
return (bits_.fetch_or(mask_, std::memory_order::acquire) & mask_) == 0;
|
||||
}
|
||||
|
||||
void
|
||||
lock()
|
||||
lock() noexcept
|
||||
{
|
||||
while (!try_lock())
|
||||
do
|
||||
{
|
||||
// The use of relaxed memory ordering here is intentional and
|
||||
// serves to help reduce cache coherency traffic during times
|
||||
// of contention by avoiding writes that would definitely not
|
||||
// result in the lock being acquired.
|
||||
while (lock_.load(std::memory_order_relaxed) != 0)
|
||||
// of contention by avoiding writes that are unlikely to grab
|
||||
// the requested lock.
|
||||
while ((bits_.load(std::memory_order::relaxed) & mask_) != 0)
|
||||
detail::spinPause();
|
||||
}
|
||||
} while (!try_lock());
|
||||
}
|
||||
|
||||
void
|
||||
unlock()
|
||||
unlock() noexcept
|
||||
{
|
||||
lock_.store(0, std::memory_order_release);
|
||||
bits_.fetch_and(~mask_, std::memory_order::release);
|
||||
}
|
||||
};
|
||||
/** @} */
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
namespace beast {
|
||||
|
||||
template <typename T>
|
||||
std::string
|
||||
typeName()
|
||||
{
|
||||
using TR = std::remove_reference_t<T>;
|
||||
|
||||
std::string name = typeid(TR).name();
|
||||
|
||||
#ifndef _MSC_VER
|
||||
if (auto s = abi::__cxa_demangle(name.c_str(), nullptr, nullptr, nullptr))
|
||||
{
|
||||
name = s;
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
|
||||
std::free(s);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (std::is_const_v<TR>)
|
||||
name += " const";
|
||||
if (std::is_volatile_v<TR>)
|
||||
name += " volatile";
|
||||
if (std::is_lvalue_reference_v<T>)
|
||||
{
|
||||
name += "&";
|
||||
}
|
||||
else if (std::is_rvalue_reference_v<T>)
|
||||
{
|
||||
name += "&&";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
} // namespace beast
|
||||
@@ -20,7 +20,7 @@ namespace beast::unit_test {
|
||||
namespace detail {
|
||||
|
||||
template <class String>
|
||||
std::string
|
||||
static std::string
|
||||
makeReason(String const& reason, char const* file, int line)
|
||||
{
|
||||
std::string s(reason);
|
||||
|
||||
@@ -2,26 +2,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <compare>
|
||||
#include <concepts>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/**
|
||||
* Zero allows classes to offer efficient comparisons to zero.
|
||||
*
|
||||
* Zero is a struct to allow classes to efficiently compare with zero without
|
||||
* requiring an rvalue construction.
|
||||
*
|
||||
* It's often the case that we have classes which combine a number and a unit.
|
||||
* In such cases, comparisons like t > 0 or t != 0 make sense, but comparisons
|
||||
* like t > 1 or t != 1 do not.
|
||||
* like t > 1 or t != 1 do not. Comparing against kZero expresses exactly that,
|
||||
* without constructing a T.
|
||||
*
|
||||
* The class Zero allows such comparisons to be easily made.
|
||||
*
|
||||
* The comparing class T either needs to have a method called signum() which
|
||||
* returns a positive number, 0, or a negative; or there needs to be a signum
|
||||
* function which resolves in the namespace which takes an instance of T and
|
||||
* returns a positive, zero or negative number.
|
||||
* A type T participates if either `t.signum()` or an unqualified `signum(t)`
|
||||
* found by argument-dependent lookup returns an integer that is negative,
|
||||
* zero, or positive according to the sign of t. Both `t == kZero` and
|
||||
* `kZero == t` work, as do all six relational operators in either order.
|
||||
*/
|
||||
|
||||
struct Zero
|
||||
{
|
||||
explicit Zero() = default;
|
||||
@@ -30,115 +28,44 @@ struct Zero
|
||||
inline constexpr Zero kZero{};
|
||||
|
||||
/**
|
||||
* Default implementation of signum calls the method on the class.
|
||||
* Default implementation of signum: call the member function.
|
||||
*/
|
||||
template <typename T>
|
||||
auto
|
||||
signum(T const& t)
|
||||
template <class T>
|
||||
requires requires(T const& t) {
|
||||
{ t.signum() } -> std::integral;
|
||||
}
|
||||
[[nodiscard]] constexpr auto
|
||||
signum(T const& t) noexcept(noexcept(t.signum()))
|
||||
{
|
||||
return t.signum();
|
||||
}
|
||||
|
||||
namespace detail::zero_helper {
|
||||
namespace detail {
|
||||
|
||||
// For argument dependent lookup to function properly, calls to signum must
|
||||
// be made from a namespace that does not include overloads of the function..
|
||||
/**
|
||||
* A type with a usable signum: either the member-based default above, or a
|
||||
* `signum(t)` overload in T's own namespace, found by ADL. A user overload
|
||||
* that is a better match than the template wins, as usual.
|
||||
*/
|
||||
template <class T>
|
||||
auto
|
||||
callSignum(T const& t)
|
||||
concept HasSignum = requires(T const& t) {
|
||||
{ signum(t) } -> std::integral;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <detail::HasSignum T>
|
||||
[[nodiscard]] constexpr bool
|
||||
operator==(T const& t, Zero) noexcept(noexcept(signum(t)))
|
||||
{
|
||||
return signum(t);
|
||||
return signum(t) == 0;
|
||||
}
|
||||
|
||||
} // namespace detail::zero_helper
|
||||
|
||||
// Handle operators where T is on the left side using signum.
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
operator==(T const& t, Zero)
|
||||
template <detail::HasSignum T>
|
||||
[[nodiscard]] constexpr std::strong_ordering
|
||||
operator<=>(T const& t, Zero) noexcept(noexcept(signum(t)))
|
||||
{
|
||||
return detail::zero_helper::callSignum(t) == 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
operator!=(T const& t, Zero)
|
||||
{
|
||||
return detail::zero_helper::callSignum(t) != 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
operator<(T const& t, Zero)
|
||||
{
|
||||
return detail::zero_helper::callSignum(t) < 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
operator>(T const& t, Zero)
|
||||
{
|
||||
return detail::zero_helper::callSignum(t) > 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
operator>=(T const& t, Zero)
|
||||
{
|
||||
return detail::zero_helper::callSignum(t) >= 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
operator<=(T const& t, Zero)
|
||||
{
|
||||
return detail::zero_helper::callSignum(t) <= 0;
|
||||
}
|
||||
|
||||
// Handle operators where T is on the right side by
|
||||
// reversing the operation, so that T is on the left side.
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
operator==(Zero, T const& t)
|
||||
{
|
||||
return t == kZero;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
operator!=(Zero, T const& t)
|
||||
{
|
||||
return t != kZero;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
operator<(Zero, T const& t)
|
||||
{
|
||||
return t > kZero;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
operator>(Zero, T const& t)
|
||||
{
|
||||
return t < kZero;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
operator>=(Zero, T const& t)
|
||||
{
|
||||
return t <= kZero;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
operator<=(Zero, T const& t)
|
||||
{
|
||||
return t >= kZero;
|
||||
return signum(t) <=> 0;
|
||||
}
|
||||
|
||||
} // namespace beast
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/basics/enum_bitops.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/OwnerCounts.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
@@ -22,80 +22,39 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// Bitwise flag enum with existing operator overloads
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
|
||||
enum ApplyFlags : std::uint32_t {
|
||||
TapNone = 0x00,
|
||||
enum class ApplyFlags : std::uint32_t {
|
||||
None = 0x00,
|
||||
|
||||
// This is a local transaction with the
|
||||
// fail_hard flag set.
|
||||
TapFailHard = 0x10,
|
||||
FailHard = 0x10,
|
||||
|
||||
// This is not the transaction's last pass
|
||||
// Transaction can be retried, soft failures allowed
|
||||
TapRetry = 0x20,
|
||||
Retry = 0x20,
|
||||
|
||||
// Transaction came from a privileged source
|
||||
TapUnlimited = 0x400,
|
||||
Unlimited = 0x400,
|
||||
|
||||
// Transaction is executing as part of a batch
|
||||
TapBatch = 0x800,
|
||||
Batch = 0x800,
|
||||
|
||||
// Transaction shouldn't be applied
|
||||
// Signatures shouldn't be checked
|
||||
TapDryRun = 0x1000,
|
||||
DryRun = 0x1000,
|
||||
|
||||
// Transaction is being preflighted as the payload of a
|
||||
// TransactionProposalCreate. Its signatures are collected on-ledger
|
||||
// afterward, so signature-presence checks (e.g. Batch signer matching)
|
||||
// are skipped at proposal-creation time (On-Chain Cosigner spec
|
||||
// §5.3.1.2).
|
||||
TapProposal = 0x2000
|
||||
Proposal = 0x2000
|
||||
};
|
||||
|
||||
constexpr ApplyFlags
|
||||
operator|(ApplyFlags const& lhs, ApplyFlags const& rhs)
|
||||
template <>
|
||||
struct enum_bitops::OptIn<ApplyFlags> : std::true_type
|
||||
{
|
||||
return safeCast<ApplyFlags>(
|
||||
safeCast<std::underlying_type_t<ApplyFlags>>(lhs) |
|
||||
safeCast<std::underlying_type_t<ApplyFlags>>(rhs));
|
||||
}
|
||||
|
||||
static_assert((TapFailHard | TapRetry) == safeCast<ApplyFlags>(0x30u), "ApplyFlags operator |");
|
||||
static_assert((TapRetry | TapFailHard) == safeCast<ApplyFlags>(0x30u), "ApplyFlags operator |");
|
||||
|
||||
constexpr ApplyFlags
|
||||
operator&(ApplyFlags const& lhs, ApplyFlags const& rhs)
|
||||
{
|
||||
return safeCast<ApplyFlags>(
|
||||
safeCast<std::underlying_type_t<ApplyFlags>>(lhs) &
|
||||
safeCast<std::underlying_type_t<ApplyFlags>>(rhs));
|
||||
}
|
||||
|
||||
static_assert((TapFailHard & TapRetry) == TapNone, "ApplyFlags operator &");
|
||||
static_assert((TapRetry & TapFailHard) == TapNone, "ApplyFlags operator &");
|
||||
|
||||
constexpr ApplyFlags
|
||||
operator~(ApplyFlags const& flags)
|
||||
{
|
||||
return safeCast<ApplyFlags>(~safeCast<std::underlying_type_t<ApplyFlags>>(flags));
|
||||
}
|
||||
|
||||
static_assert(~TapRetry == safeCast<ApplyFlags>(0xFFFFFFDFu), "ApplyFlags operator ~");
|
||||
|
||||
inline ApplyFlags
|
||||
operator|=(ApplyFlags& lhs, ApplyFlags const& rhs)
|
||||
{
|
||||
lhs = lhs | rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
inline ApplyFlags
|
||||
operator&=(ApplyFlags& lhs, ApplyFlags const& rhs)
|
||||
{
|
||||
lhs = lhs & rhs;
|
||||
return lhs;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/CachedView.h>
|
||||
#include <xrpl/ledger/RawView.h>
|
||||
#include <xrpl/protocol/BatchInnerResult.h>
|
||||
#include <xrpl/protocol/Fees.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/LedgerHeader.h>
|
||||
@@ -326,24 +325,6 @@ public:
|
||||
bool
|
||||
addSLE(SLE const& sle);
|
||||
|
||||
/**
|
||||
* @brief Inner Batch outcomes observed while this node built the ledger.
|
||||
*
|
||||
* Empty for a ledger acquired from the network or loaded from the database. Not part of
|
||||
* the ledger hash; persisted to the transaction tables when the ledger is saved.
|
||||
*/
|
||||
void
|
||||
setBatchInnerResults(std::vector<BatchInnerResult> results)
|
||||
{
|
||||
batchInnerResults_ = std::move(results);
|
||||
}
|
||||
|
||||
std::vector<BatchInnerResult> const&
|
||||
batchInnerResults() const
|
||||
{
|
||||
return batchInnerResults_;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
@@ -452,7 +433,6 @@ private:
|
||||
Rules rules_;
|
||||
LedgerHeader header_;
|
||||
beast::Journal j_;
|
||||
std::vector<BatchInnerResult> batchInnerResults_;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -31,52 +25,6 @@ public:
|
||||
: Base(keylet::amendments(), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of amendments this entry reports as enabled.
|
||||
*
|
||||
* @return the set of enabled amendments.
|
||||
*/
|
||||
[[nodiscard]] std::set<UInt256>
|
||||
enabledAmendments() const
|
||||
{
|
||||
std::set<UInt256> amendments;
|
||||
|
||||
if (this->exists() && (*this)->isFieldPresent(sfAmendments))
|
||||
{
|
||||
auto const& v = (*this)->getFieldV256(sfAmendments);
|
||||
amendments.insert_range(v);
|
||||
}
|
||||
|
||||
return amendments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map of amendments that have achieved majority, to the time
|
||||
* majority was reached.
|
||||
*
|
||||
* @return a map of amendment to the time majority was reached.
|
||||
*/
|
||||
[[nodiscard]] std::map<UInt256, NetClock::time_point>
|
||||
majorityAmendments() const
|
||||
{
|
||||
std::map<UInt256, NetClock::time_point> ret;
|
||||
|
||||
if (this->exists() && (*this)->isFieldPresent(sfMajorities))
|
||||
{
|
||||
using TimePoint = NetClock::time_point;
|
||||
using Duration = TimePoint::duration;
|
||||
|
||||
auto const majorities = (*this)->getFieldArray(sfMajorities);
|
||||
|
||||
for (auto const& m : majorities)
|
||||
{
|
||||
ret[m.getFieldH256(sfAmendment)] = TimePoint(Duration(m.getFieldU32(sfCloseTime)));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
using AmendmentsEntryR = AmendmentsEntry<ReadView>;
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||
@@ -29,291 +27,6 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* Validate that @p account may lock @p amount of a token for later delivery
|
||||
* to @p dest.
|
||||
*
|
||||
* The lock-side counterpart of escrowUnlockPreclaimHelper: every issuer
|
||||
* control (locking opt-in, authorization, freeze/lock, transferability,
|
||||
* spendable balance) that gates locking token value lives here, so any
|
||||
* transactor that locks funds applies the same rules. The signature is
|
||||
* view-based rather than PreclaimContext-based so it can also run from
|
||||
* doApply.
|
||||
*/
|
||||
template <ValidIssueType T>
|
||||
TER
|
||||
escrowLockPreclaimHelper(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
AccountID const& dest,
|
||||
STAmount const& amount,
|
||||
beast::Journal j);
|
||||
|
||||
template <>
|
||||
inline TER
|
||||
escrowLockPreclaimHelper<Issue>(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
AccountID const& dest,
|
||||
STAmount const& amount,
|
||||
beast::Journal j)
|
||||
{
|
||||
auto const& issue = amount.get<Issue>();
|
||||
auto const& issuer = amount.getIssuer();
|
||||
// If the issuer is the same as the account, return tecNO_PERMISSION
|
||||
if (issuer == account)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// If the lsfAllowTrustLineLocking is not enabled, return tecNO_PERMISSION
|
||||
auto const sleIssuer = view.read(keylet::account(issuer));
|
||||
if (!sleIssuer)
|
||||
return tecNO_ISSUER;
|
||||
if (!sleIssuer->isFlag(lsfAllowTrustLineLocking))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// If the account does not have a trustline to the issuer, return tecNO_LINE
|
||||
auto const sleRippleState = view.read(keylet::trustLine(account, issuer, issue.currency));
|
||||
if (!sleRippleState)
|
||||
return tecNO_LINE;
|
||||
|
||||
STAmount const balance = (*sleRippleState)[sfBalance];
|
||||
|
||||
// If balance is positive, issuer must have higher address than account
|
||||
if (balance > beast::kZero && issuer < account)
|
||||
return tecNO_PERMISSION; // LCOV_EXCL_LINE
|
||||
|
||||
// If balance is negative, issuer must have lower address than account
|
||||
if (balance < beast::kZero && issuer > account)
|
||||
return tecNO_PERMISSION; // LCOV_EXCL_LINE
|
||||
|
||||
// If the issuer has requireAuth set, check if the account is authorized
|
||||
if (auto const ter = requireAuth(view, issue, account); !isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
// If the issuer has requireAuth set, check if the destination is authorized
|
||||
if (auto const ter = requireAuth(view, issue, dest); !isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
// If the issuer has frozen the account, return tecFROZEN
|
||||
if (isFrozen(view, account, issue))
|
||||
return tecFROZEN;
|
||||
|
||||
// If the issuer has frozen the destination, return tecFROZEN
|
||||
if (isFrozen(view, dest, issue))
|
||||
return tecFROZEN;
|
||||
|
||||
STAmount const spendableAmount =
|
||||
accountHolds(view, account, issue.currency, issuer, FreezeHandling::IgnoreFreeze, j);
|
||||
|
||||
// If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
|
||||
if (spendableAmount <= beast::kZero)
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
// If the spendable amount is less than the amount, return
|
||||
// tecINSUFFICIENT_FUNDS
|
||||
if (spendableAmount < amount)
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
// If the amount is not addable to the balance, return tecPRECISION_LOSS
|
||||
if (!canAdd(spendableAmount, amount))
|
||||
return tecPRECISION_LOSS;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline TER
|
||||
escrowLockPreclaimHelper<MPTIssue>(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
AccountID const& dest,
|
||||
STAmount const& amount,
|
||||
beast::Journal j)
|
||||
{
|
||||
AccountID const issuer = amount.getIssuer();
|
||||
// If the issuer is the same as the account, return tecNO_PERMISSION
|
||||
if (issuer == account)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// If the mpt does not exist, return tecOBJECT_NOT_FOUND
|
||||
auto const issuanceKey = keylet::mptokenIssuance(amount.get<MPTIssue>().getMptID());
|
||||
auto const sleIssuance = view.read(issuanceKey);
|
||||
if (!sleIssuance)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
|
||||
// If the lsfMPTCanEscrow is not enabled, return tecNO_PERMISSION
|
||||
if (!sleIssuance->isFlag(lsfMPTCanEscrow))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// If the issuer is not the same as the issuer of the mpt, return
|
||||
// tecNO_PERMISSION
|
||||
if (sleIssuance->getAccountID(sfIssuer) != issuer)
|
||||
return tecNO_PERMISSION; // LCOV_EXCL_LINE
|
||||
|
||||
// If the account does not have the mpt, return tecOBJECT_NOT_FOUND
|
||||
if (!view.exists(keylet::mptoken(issuanceKey.key, account)))
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
|
||||
// If the issuer has requireAuth set, check if the account is
|
||||
// authorized
|
||||
auto const& mptIssue = amount.get<MPTIssue>();
|
||||
if (auto const ter = requireAuth(view, mptIssue, account, AuthType::WeakAuth);
|
||||
!isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
// If the issuer has requireAuth set, check if the destination is
|
||||
// authorized
|
||||
if (auto const ter = requireAuth(view, mptIssue, dest, AuthType::WeakAuth); !isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
// If the issuer has frozen the account, return tecLOCKED
|
||||
if (isFrozen(view, account, *sleIssuance))
|
||||
return tecLOCKED;
|
||||
|
||||
// If the issuer has frozen the destination, return tecLOCKED
|
||||
if (isFrozen(view, dest, *sleIssuance))
|
||||
return tecLOCKED;
|
||||
|
||||
// If the mpt cannot be transferred, return tecNO_AUTH
|
||||
if (auto const ter = canTransfer(view, mptIssue, account, dest); !isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
STAmount const spendableAmount = accountHolds(
|
||||
view,
|
||||
account,
|
||||
amount.get<MPTIssue>(),
|
||||
FreezeHandling::IgnoreFreeze,
|
||||
AuthHandling::IgnoreAuth,
|
||||
j);
|
||||
|
||||
// If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
|
||||
if (spendableAmount <= beast::kZero)
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
// If the spendable amount is less than the amount, return
|
||||
// tecINSUFFICIENT_FUNDS
|
||||
if (spendableAmount < amount)
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
template <ValidIssueType T>
|
||||
TER
|
||||
escrowLockApplyHelper(
|
||||
ApplyView& view,
|
||||
AccountID const& issuer,
|
||||
AccountID const& sender,
|
||||
STAmount const& amount,
|
||||
beast::Journal journal);
|
||||
|
||||
template <>
|
||||
inline TER
|
||||
escrowLockApplyHelper<Issue>(
|
||||
ApplyView& view,
|
||||
AccountID const& issuer,
|
||||
AccountID const& sender,
|
||||
STAmount const& amount,
|
||||
beast::Journal journal)
|
||||
{
|
||||
// Defensive: Issuer cannot create an escrow
|
||||
if (issuer == sender)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const ter =
|
||||
directSendNoFee(view, sender, issuer, amount, !amount.holds<MPTIssue>(), journal);
|
||||
if (!isTesSuccess(ter))
|
||||
return ter; // LCOV_EXCL_LINE
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline TER
|
||||
escrowLockApplyHelper<MPTIssue>(
|
||||
ApplyView& view,
|
||||
AccountID const& issuer,
|
||||
AccountID const& sender,
|
||||
STAmount const& amount,
|
||||
beast::Journal journal)
|
||||
{
|
||||
// Defensive: Issuer cannot create an escrow
|
||||
if (issuer == sender)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const ter = lockEscrowMPT(view, sender, amount, journal);
|
||||
if (!isTesSuccess(ter))
|
||||
return ter; // LCOV_EXCL_LINE
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
template <ValidIssueType T>
|
||||
TER
|
||||
escrowUnlockPreclaimHelper(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
STAmount const& amount,
|
||||
bool checkFreeze = true);
|
||||
|
||||
template <>
|
||||
inline TER
|
||||
escrowUnlockPreclaimHelper<Issue>(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
STAmount const& amount,
|
||||
bool checkFreeze)
|
||||
{
|
||||
AccountID const& issuer = amount.getIssuer();
|
||||
// If the issuer is the same as the account, return tesSUCCESS
|
||||
if (issuer == account)
|
||||
return tesSUCCESS;
|
||||
|
||||
// If the issuer has requireAuth set, check if the destination is authorized
|
||||
if (auto const ter = requireAuth(view, amount.get<Issue>(), account); !isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
// If the issuer has deep frozen the destination, return tecFROZEN
|
||||
if (checkFreeze &&
|
||||
isDeepFrozen(view, account, amount.get<Issue>().currency, amount.getIssuer()))
|
||||
return tecFROZEN;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline TER
|
||||
escrowUnlockPreclaimHelper<MPTIssue>(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
STAmount const& amount,
|
||||
bool checkFreeze)
|
||||
{
|
||||
AccountID const& issuer = amount.getIssuer();
|
||||
// If the issuer is the same as the account, return tesSUCCESS
|
||||
if (issuer == account)
|
||||
return tesSUCCESS;
|
||||
|
||||
// If the mpt does not exist, return tecOBJECT_NOT_FOUND
|
||||
auto const issuanceKey = keylet::mptokenIssuance(amount.get<MPTIssue>().getMptID());
|
||||
auto const sleIssuance = view.read(issuanceKey);
|
||||
if (!sleIssuance)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
|
||||
// If the issuer has requireAuth set, check if the account is
|
||||
// authorized
|
||||
auto const& mptIssue = amount.get<MPTIssue>();
|
||||
if (auto const ter = requireAuth(view, mptIssue, account, AuthType::WeakAuth);
|
||||
!isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
// If the issuer has frozen the account, return tecLOCKED
|
||||
if (checkFreeze && isFrozen(view, account, *sleIssuance))
|
||||
return tecLOCKED;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <ValidIssueType T>
|
||||
TER
|
||||
escrowUnlockApplyHelper(
|
||||
@@ -342,6 +55,9 @@ escrowUnlockApplyHelper<Issue>(
|
||||
bool createAsset,
|
||||
beast::Journal journal)
|
||||
{
|
||||
auto const& issue = amount.get<Issue>();
|
||||
Keylet const trustLineKey = keylet::trustLine(receiver, issue);
|
||||
bool const recvLow = issuer > receiver;
|
||||
bool const senderIssuer = issuer == sender;
|
||||
bool const receiverIssuer = issuer == receiver;
|
||||
|
||||
@@ -351,10 +67,6 @@ escrowUnlockApplyHelper<Issue>(
|
||||
if (receiverIssuer)
|
||||
return tesSUCCESS;
|
||||
|
||||
auto const& issue = amount.get<Issue>();
|
||||
Keylet const trustLineKey = keylet::trustLine(receiver, issue);
|
||||
bool const recvLow = issuer > receiver;
|
||||
|
||||
if (!ctx.view.exists(trustLineKey) && createAsset)
|
||||
{
|
||||
// Can the account cover the trust line's reserve?
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/nodestore/NodeObject.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::node_store {
|
||||
|
||||
@@ -23,7 +25,7 @@ public:
|
||||
/**
|
||||
* Construct the decoded blob from raw data.
|
||||
*/
|
||||
DecodedBlob(void const* key, void const* value, int valueBytes);
|
||||
DecodedBlob(std::optional<uint256> key, void const* value, int valueBytes);
|
||||
|
||||
/**
|
||||
* Determine if the decoding was successful.
|
||||
@@ -43,10 +45,10 @@ public:
|
||||
private:
|
||||
bool success_{false};
|
||||
|
||||
void const* key_;
|
||||
uint256 key_;
|
||||
NodeObjectType objectType_{NodeObjectType::Unknown};
|
||||
unsigned char const* objectData_{nullptr};
|
||||
int dataBytes_;
|
||||
int dataBytes_ = 0;
|
||||
};
|
||||
|
||||
} // namespace xrpl::node_store
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/nodestore/NodeObject.h>
|
||||
|
||||
@@ -37,11 +38,6 @@ namespace xrpl::node_store {
|
||||
|
||||
class EncodedBlob
|
||||
{
|
||||
/**
|
||||
* The 32-byte key of the serialized object.
|
||||
*/
|
||||
std::array<std::uint8_t, 32> key_{};
|
||||
|
||||
/**
|
||||
* A pre-allocated buffer for the serialized object.
|
||||
*
|
||||
@@ -65,6 +61,11 @@ class EncodedBlob
|
||||
*/
|
||||
std::uint8_t* const ptr_;
|
||||
|
||||
/**
|
||||
* The 32-byte key of the serialized object.
|
||||
*/
|
||||
uint256 key_;
|
||||
|
||||
public:
|
||||
explicit EncodedBlob(std::shared_ptr<NodeObject> const& obj)
|
||||
: size_([&obj]() {
|
||||
@@ -76,11 +77,12 @@ public:
|
||||
return obj->getData().size() + 9;
|
||||
}())
|
||||
, ptr_((size_ <= payload_.size()) ? payload_.data() : new std::uint8_t[size_])
|
||||
, key_(obj->getHash())
|
||||
{
|
||||
std::fill_n(ptr_, 8, std::uint8_t{0});
|
||||
ptr_[8] = static_cast<std::uint8_t>(obj->getType());
|
||||
|
||||
std::copy_n(obj->getData().data(), obj->getData().size(), ptr_ + 9);
|
||||
std::copy_n(obj->getHash().data(), obj->getHash().size(), key_.data());
|
||||
}
|
||||
|
||||
~EncodedBlob()
|
||||
@@ -95,10 +97,10 @@ public:
|
||||
delete[] ptr_;
|
||||
}
|
||||
|
||||
[[nodiscard]] void const*
|
||||
[[nodiscard]] uint256 const&
|
||||
getKey() const noexcept
|
||||
{
|
||||
return static_cast<void const*>(key_.data());
|
||||
return key_;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::size_t
|
||||
|
||||
@@ -61,14 +61,22 @@ parseBase58(std::string const& s);
|
||||
/**
|
||||
* A special account that's used as the "issuer" for XRP.
|
||||
*/
|
||||
AccountID const&
|
||||
xrpAccount();
|
||||
constexpr inline AccountID const&
|
||||
xrpAccount() noexcept
|
||||
{
|
||||
static constexpr AccountID kAccount(beast::kZero);
|
||||
return kAccount;
|
||||
}
|
||||
|
||||
/**
|
||||
* A placeholder for empty accounts.
|
||||
*/
|
||||
AccountID const&
|
||||
noAccount();
|
||||
constexpr inline AccountID const&
|
||||
noAccount() noexcept
|
||||
{
|
||||
static constexpr AccountID kAccount = xrpAccount().next();
|
||||
return kAccount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hex or base58 string to AccountID.
|
||||
@@ -80,10 +88,10 @@ bool
|
||||
toIssuer(AccountID&, std::string const&);
|
||||
|
||||
// DEPRECATED Should be checking the currency or native flag
|
||||
inline bool
|
||||
isXRP(AccountID const& c)
|
||||
constexpr inline bool
|
||||
isXRP(AccountID const& c) noexcept
|
||||
{
|
||||
return c == beast::kZero;
|
||||
return c == xrpAccount();
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
@@ -101,22 +109,6 @@ operator<<(std::ostream& os, AccountID const& x)
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the global cache used to map AccountID to base58 conversions.
|
||||
*
|
||||
* The cache is optional and need not be initialized. But because conversion
|
||||
* is expensive (it requires a SHA-256 operation) in most cases the overhead
|
||||
* of the cache is worth the benefit.
|
||||
*
|
||||
* @param count The number of entries the cache should accommodate. Zero will
|
||||
* disable the cache, releasing any memory associated with it.
|
||||
*
|
||||
* @note The function will only initialize the cache the first time it is
|
||||
* invoked. Subsequent invocations do nothing.
|
||||
*/
|
||||
void
|
||||
initAccountIdCache(std::size_t count);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* @brief Outcome of one inner transaction of a Batch, recorded while the outer Batch was
|
||||
* applied.
|
||||
*
|
||||
* Inner transactions that fail with a ter/tem/tef result are never applied and leave no
|
||||
* metadata in the ledger, and a tfAllOrNothing rollback discards the ones that did apply.
|
||||
* This record is the only place those outcomes survive. It is node-local and not part of
|
||||
* the ledger hash.
|
||||
*/
|
||||
struct BatchInnerResult
|
||||
{
|
||||
uint256 parentBatchId;
|
||||
uint256 innerTxId;
|
||||
|
||||
/**
|
||||
* @brief Position in the outer transaction's RawTransactions.
|
||||
*/
|
||||
std::uint32_t index = 0;
|
||||
|
||||
TER ter = tesSUCCESS;
|
||||
|
||||
/**
|
||||
* @brief True if the inner transaction's changes ended up in the ledger.
|
||||
*/
|
||||
bool applied = false;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/beast/type_name.h>
|
||||
#include <xrpl/protocol/SOTemplate.h>
|
||||
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/core/type_name.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
* Derived classes will load the object with all the known formats.
|
||||
*/
|
||||
private:
|
||||
KnownFormats() : name_(beast::typeName<Derived>())
|
||||
KnownFormats() : name_(boost::core::type_name<Derived>())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -75,12 +75,6 @@ addRaw(LedgerHeader const&, Serializer&, bool includeHash = false);
|
||||
LedgerHeader
|
||||
deserializeHeader(Slice data, bool hasHash = false);
|
||||
|
||||
/**
|
||||
* Deserialize a ledger header (prefixed with 4 bytes) from a byte array.
|
||||
*/
|
||||
LedgerHeader
|
||||
deserializePrefixedHeader(Slice data, bool hasHash = false);
|
||||
|
||||
/**
|
||||
* Calculate the hash of a ledger header.
|
||||
*/
|
||||
|
||||
28
include/xrpl/protocol/LedgerShortcut.h
Normal file
28
include/xrpl/protocol/LedgerShortcut.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* @brief Enumeration of ledger shortcuts for specifying which ledger to use.
|
||||
*
|
||||
* These shortcuts provide a convenient way to reference commonly used ledgers
|
||||
* without needing to specify their exact hash or sequence number.
|
||||
*/
|
||||
enum class LedgerShortcut {
|
||||
/**
|
||||
* The current working ledger (open, not yet closed)
|
||||
*/
|
||||
Current,
|
||||
|
||||
/**
|
||||
* The most recently closed ledger (may not be validated)
|
||||
*/
|
||||
Closed,
|
||||
|
||||
/**
|
||||
* The most recently validated ledger
|
||||
*/
|
||||
Validated
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -19,8 +19,8 @@ private:
|
||||
// But an STAccount is always 160 bits, so we can store it with less
|
||||
// overhead in an xrpl::UInt160. However, so the serialized format of the
|
||||
// STAccount stays unchanged, we serialize and deserialize like an STBlob.
|
||||
AccountID value_;
|
||||
bool default_;
|
||||
AccountID value_{};
|
||||
bool default_{true};
|
||||
|
||||
public:
|
||||
using value_type = AccountID;
|
||||
@@ -28,7 +28,6 @@ public:
|
||||
STAccount();
|
||||
|
||||
STAccount(SField const& n);
|
||||
STAccount(SField const& n, Buffer const& v);
|
||||
STAccount(SerialIter& sit, SField const& name);
|
||||
STAccount(SField const& n, AccountID const& v);
|
||||
|
||||
|
||||
@@ -33,7 +33,20 @@ public:
|
||||
|
||||
STBitString(SField const& n);
|
||||
STBitString(value_type const& v);
|
||||
|
||||
template <typename Tag>
|
||||
requires(!std::is_void_v<Tag>)
|
||||
STBitString(BaseUInt<Bits, Tag> const& v) : value_(v)
|
||||
{
|
||||
}
|
||||
|
||||
STBitString(SField const& n, value_type const& v);
|
||||
template <typename Tag>
|
||||
requires(!std::is_void_v<Tag>)
|
||||
STBitString(SField const& n, BaseUInt<Bits, Tag> const& v) : STBase(n), value_(v)
|
||||
{
|
||||
}
|
||||
|
||||
STBitString(SerialIter& sit, SField const& name);
|
||||
|
||||
[[nodiscard]] SerializedTypeID
|
||||
@@ -91,7 +104,7 @@ inline STBitString<Bits>::STBitString(SField const& n, value_type const& v) : ST
|
||||
|
||||
template <int Bits>
|
||||
inline STBitString<Bits>::STBitString(SerialIter& sit, SField const& name)
|
||||
: STBitString(name, sit.getBitString<Bits>())
|
||||
: STBitString(name, sit.getBitString<value_type>())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -158,7 +171,7 @@ STBitString<Bits>::add(Serializer& s) const
|
||||
{
|
||||
XRPL_ASSERT(getFName().isBinary(), "xrpl::STBitString::add : field is binary");
|
||||
XRPL_ASSERT(getFName().fieldType == getSType(), "xrpl::STBitString::add : field type match");
|
||||
s.addBitString<Bits>(value_);
|
||||
s.addBitString(value_);
|
||||
}
|
||||
|
||||
template <int Bits>
|
||||
@@ -166,7 +179,7 @@ template <typename Tag>
|
||||
void
|
||||
STBitString<Bits>::setValue(BaseUInt<Bits, Tag> const& v)
|
||||
{
|
||||
value_ = v;
|
||||
value_ = value_type{v};
|
||||
}
|
||||
|
||||
template <int Bits>
|
||||
|
||||
@@ -16,12 +16,13 @@ namespace xrpl {
|
||||
template <typename Integer>
|
||||
class STInteger : public STBase, public CountedObject<STInteger<Integer>>
|
||||
{
|
||||
static_assert(
|
||||
SerializableInteger<Integer>,
|
||||
"STInteger requires an integer type that Serializer can append");
|
||||
|
||||
public:
|
||||
using value_type = Integer;
|
||||
|
||||
private:
|
||||
Integer value_;
|
||||
|
||||
public:
|
||||
explicit STInteger(Integer v);
|
||||
STInteger(SField const& n, Integer v = 0);
|
||||
@@ -62,6 +63,8 @@ private:
|
||||
move(std::size_t n, void* buf) override;
|
||||
|
||||
friend class xrpl::detail::STVar;
|
||||
|
||||
Integer value_;
|
||||
};
|
||||
|
||||
using STUInt8 = STInteger<unsigned char>;
|
||||
@@ -101,7 +104,15 @@ STInteger<Integer>::add(Serializer& s) const
|
||||
{
|
||||
XRPL_ASSERT(getFName().isBinary(), "xrpl::STInteger::add : field is binary");
|
||||
XRPL_ASSERT(getFName().fieldType == getSType(), "xrpl::STInteger::add : field type match");
|
||||
s.addInteger(value_);
|
||||
|
||||
if constexpr (sizeof(Integer) == 1)
|
||||
s.add8(value_);
|
||||
else if constexpr (sizeof(Integer) == 2)
|
||||
s.add16(value_);
|
||||
else if constexpr (sizeof(Integer) == 4)
|
||||
s.add32(value_);
|
||||
else
|
||||
s.add64(value_);
|
||||
}
|
||||
|
||||
template <typename Integer>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <xrpl/basics/CountedObject.h>
|
||||
#include <xrpl/basics/UnorderedContainers.h>
|
||||
#include <xrpl/basics/enum_bitops.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
@@ -15,6 +16,7 @@
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -22,18 +24,8 @@ namespace xrpl {
|
||||
|
||||
class STPathElement final : public CountedObject<STPathElement>
|
||||
{
|
||||
unsigned int type_;
|
||||
AccountID accountID_;
|
||||
PathAsset assetID_;
|
||||
AccountID issuerID_;
|
||||
|
||||
bool isOffer_;
|
||||
std::size_t hashValue_;
|
||||
|
||||
public:
|
||||
// Bitwise values (typeCurrency | typeMPT)
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
|
||||
enum Type {
|
||||
enum class Type : std::uint8_t {
|
||||
TypeNone = 0x00,
|
||||
TypeAccount = 0x01, // Rippling through an account (vs taking an offer).
|
||||
TypeCurrency = 0x10, // Currency follows.
|
||||
@@ -45,6 +37,8 @@ public:
|
||||
// Combination of all types.
|
||||
};
|
||||
|
||||
using enum Type;
|
||||
|
||||
STPathElement();
|
||||
STPathElement(STPathElement const&) = default;
|
||||
STPathElement&
|
||||
@@ -62,42 +56,42 @@ public:
|
||||
bool forceAsset = false);
|
||||
|
||||
STPathElement(
|
||||
unsigned int uType,
|
||||
Type type,
|
||||
AccountID const& account,
|
||||
PathAsset const& asset,
|
||||
AccountID const& issuer);
|
||||
|
||||
[[nodiscard]] std::uint32_t
|
||||
getNodeType() const;
|
||||
[[nodiscard]] Type
|
||||
getNodeType() const noexcept;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isOffer() const;
|
||||
isOffer() const noexcept;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isAccount() const;
|
||||
isAccount() const noexcept;
|
||||
|
||||
[[nodiscard]] bool
|
||||
hasIssuer() const;
|
||||
hasIssuer() const noexcept;
|
||||
|
||||
[[nodiscard]] bool
|
||||
hasCurrency() const;
|
||||
hasCurrency() const noexcept;
|
||||
|
||||
[[nodiscard]] bool
|
||||
hasMPT() const;
|
||||
hasMPT() const noexcept;
|
||||
|
||||
[[nodiscard]] bool
|
||||
hasAsset() const;
|
||||
hasAsset() const noexcept;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isNone() const;
|
||||
isNone() const noexcept;
|
||||
|
||||
// Nodes are either an account ID or a offer prefix. Offer prefixs denote a
|
||||
// class of offers.
|
||||
[[nodiscard]] AccountID const&
|
||||
getAccountID() const;
|
||||
getAccountID() const noexcept;
|
||||
|
||||
[[nodiscard]] PathAsset const&
|
||||
getPathAsset() const;
|
||||
getPathAsset() const noexcept;
|
||||
|
||||
[[nodiscard]] Currency const&
|
||||
getCurrency() const;
|
||||
@@ -106,17 +100,35 @@ public:
|
||||
getMPTID() const;
|
||||
|
||||
[[nodiscard]] AccountID const&
|
||||
getIssuerID() const;
|
||||
getIssuerID() const noexcept;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isType(Type const& pe) const;
|
||||
isType(Type pe) const noexcept;
|
||||
|
||||
bool
|
||||
operator==(STPathElement const& t) const;
|
||||
friend bool
|
||||
operator==(STPathElement const& lhs, STPathElement const& rhs) noexcept
|
||||
{
|
||||
return lhs.isType(TypeAccount) == rhs.isType(TypeAccount) &&
|
||||
lhs.hashValue_ == rhs.hashValue_ && lhs.accountID_ == rhs.accountID_ &&
|
||||
lhs.assetID_ == rhs.assetID_ && lhs.issuerID_ == rhs.issuerID_;
|
||||
}
|
||||
|
||||
private:
|
||||
static std::size_t
|
||||
getHash(STPathElement const& element);
|
||||
|
||||
Type type_;
|
||||
AccountID accountID_;
|
||||
PathAsset assetID_;
|
||||
AccountID issuerID_;
|
||||
|
||||
bool isOffer_;
|
||||
std::size_t hashValue_;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct enum_bitops::OptIn<STPathElement::Type> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class Hasher>
|
||||
@@ -124,7 +136,7 @@ void
|
||||
hash_append(Hasher& h, STPathElement const& e) noexcept
|
||||
{
|
||||
using beast::hash_append;
|
||||
hash_append(h, (e.getNodeType() & STPathElement::TypeAccount) != 0u);
|
||||
hash_append(h, e.isType(STPathElement::TypeAccount));
|
||||
hash_append(h, e.getAccountID());
|
||||
hash_append(h, e.getPathAsset());
|
||||
hash_append(h, e.getIssuerID());
|
||||
@@ -404,11 +416,11 @@ inline STPathElement::STPathElement(
|
||||
}
|
||||
|
||||
inline STPathElement::STPathElement(
|
||||
unsigned int uType,
|
||||
Type type,
|
||||
AccountID const& account,
|
||||
PathAsset const& asset,
|
||||
AccountID const& issuer)
|
||||
: type_(uType)
|
||||
: type_(type)
|
||||
, accountID_(account)
|
||||
, assetID_(asset)
|
||||
, issuerID_(issuer)
|
||||
@@ -423,56 +435,56 @@ inline STPathElement::STPathElement(
|
||||
hashValue_ = getHash(*this);
|
||||
}
|
||||
|
||||
inline std::uint32_t
|
||||
STPathElement::getNodeType() const
|
||||
inline STPathElement::Type
|
||||
STPathElement::getNodeType() const noexcept
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
inline bool
|
||||
STPathElement::isOffer() const
|
||||
STPathElement::isOffer() const noexcept
|
||||
{
|
||||
return isOffer_;
|
||||
}
|
||||
|
||||
inline bool
|
||||
STPathElement::isAccount() const
|
||||
STPathElement::isAccount() const noexcept
|
||||
{
|
||||
return !isOffer();
|
||||
}
|
||||
|
||||
inline bool
|
||||
STPathElement::isType(Type const& pe) const
|
||||
STPathElement::isType(Type pe) const noexcept
|
||||
{
|
||||
return (type_ & pe) != 0u;
|
||||
return (type_ & pe) != STPathElement::TypeNone;
|
||||
}
|
||||
|
||||
inline bool
|
||||
STPathElement::hasIssuer() const
|
||||
STPathElement::hasIssuer() const noexcept
|
||||
{
|
||||
return isType(STPathElement::TypeIssuer);
|
||||
}
|
||||
|
||||
inline bool
|
||||
STPathElement::hasCurrency() const
|
||||
STPathElement::hasCurrency() const noexcept
|
||||
{
|
||||
return isType(STPathElement::TypeCurrency);
|
||||
}
|
||||
|
||||
inline bool
|
||||
STPathElement::hasMPT() const
|
||||
STPathElement::hasMPT() const noexcept
|
||||
{
|
||||
return isType(STPathElement::TypeMpt);
|
||||
}
|
||||
|
||||
inline bool
|
||||
STPathElement::hasAsset() const
|
||||
STPathElement::hasAsset() const noexcept
|
||||
{
|
||||
return isType(STPathElement::TypeAsset);
|
||||
}
|
||||
|
||||
inline bool
|
||||
STPathElement::isNone() const
|
||||
STPathElement::isNone() const noexcept
|
||||
{
|
||||
return getNodeType() == STPathElement::TypeNone;
|
||||
}
|
||||
@@ -480,13 +492,13 @@ STPathElement::isNone() const
|
||||
// Nodes are either an account ID or a offer prefix. Offer prefixs denote a
|
||||
// class of offers.
|
||||
inline AccountID const&
|
||||
STPathElement::getAccountID() const
|
||||
STPathElement::getAccountID() const noexcept
|
||||
{
|
||||
return accountID_;
|
||||
}
|
||||
|
||||
inline PathAsset const&
|
||||
STPathElement::getPathAsset() const
|
||||
STPathElement::getPathAsset() const noexcept
|
||||
{
|
||||
return assetID_;
|
||||
}
|
||||
@@ -504,18 +516,11 @@ STPathElement::getMPTID() const
|
||||
}
|
||||
|
||||
inline AccountID const&
|
||||
STPathElement::getIssuerID() const
|
||||
STPathElement::getIssuerID() const noexcept
|
||||
{
|
||||
return issuerID_;
|
||||
}
|
||||
|
||||
inline bool
|
||||
STPathElement::operator==(STPathElement const& t) const
|
||||
{
|
||||
return (type_ & TypeAccount) == (t.type_ & TypeAccount) && hashValue_ == t.hashValue_ &&
|
||||
accountID_ == t.accountID_ && assetID_ == t.assetID_ && issuerID_ == t.issuerID_;
|
||||
}
|
||||
|
||||
// ------------ STPath ------------
|
||||
|
||||
inline STPath::STPath(std::vector<STPathElement> p) : path_(std::move(p))
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <xrpl/basics/Blob.h>
|
||||
#include <xrpl/basics/CountedObject.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
@@ -153,13 +154,6 @@ public:
|
||||
[[nodiscard]] std::string
|
||||
getMetaSQL(std::uint32_t inLedger, std::string const& escapedMetaData) const;
|
||||
|
||||
[[nodiscard]] std::string
|
||||
getMetaSQL(
|
||||
Serializer rawTxn,
|
||||
std::uint32_t inLedger,
|
||||
TxnSql status,
|
||||
std::string const& escapedMetaData) const;
|
||||
|
||||
/**
|
||||
* The IDs of the inner transactions of a Batch.
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@ namespace xrpl {
|
||||
// Various protocol and system specific constant globals.
|
||||
|
||||
/* The name of the system. */
|
||||
static inline std::string const&
|
||||
inline std::string const&
|
||||
systemName()
|
||||
{
|
||||
static std::string const kName = "xrpld";
|
||||
@@ -52,11 +52,10 @@ isLegalAmountSigned(XRPAmount const& amount)
|
||||
}
|
||||
|
||||
/* The currency code for the native currency. */
|
||||
static inline std::string const&
|
||||
inline std::string
|
||||
systemCurrencyCode()
|
||||
{
|
||||
static std::string const kCode = "XRP";
|
||||
return kCode;
|
||||
return "XRP";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,26 +61,40 @@ using Domain = BaseUInt<256>;
|
||||
/**
|
||||
* XRP currency.
|
||||
*/
|
||||
Currency const&
|
||||
xrpCurrency();
|
||||
constexpr inline Currency const&
|
||||
xrpCurrency() noexcept
|
||||
{
|
||||
static constexpr Currency const kCurrency(beast::kZero);
|
||||
return kCurrency;
|
||||
}
|
||||
|
||||
/**
|
||||
* A placeholder for empty currencies.
|
||||
*/
|
||||
Currency const&
|
||||
noCurrency();
|
||||
constexpr inline Currency const&
|
||||
noCurrency() noexcept
|
||||
{
|
||||
static constexpr Currency const kCurrency(xrpCurrency().next());
|
||||
return kCurrency;
|
||||
}
|
||||
|
||||
/**
|
||||
* We deliberately disallow the currency that looks like "XRP" because too
|
||||
* many people were using it instead of the correct XRP currency.
|
||||
*
|
||||
* Note that this doesn't catch "xRP" or "xrp" or other case variations.
|
||||
*/
|
||||
Currency const&
|
||||
badCurrency();
|
||||
|
||||
inline bool
|
||||
isXRP(Currency const& c)
|
||||
constexpr inline Currency const&
|
||||
badCurrency() noexcept
|
||||
{
|
||||
return c == beast::kZero;
|
||||
static constexpr Currency kCurrency{"0000000000000000000000005852500000000000"};
|
||||
return kCurrency;
|
||||
}
|
||||
|
||||
constexpr inline bool
|
||||
isXRP(Currency const& c) noexcept
|
||||
{
|
||||
return c == xrpCurrency();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,7 +112,7 @@ to_string(Currency const& c);
|
||||
* to rewrite some unit test code.
|
||||
*/
|
||||
bool
|
||||
toCurrency(Currency&, std::string const&);
|
||||
toCurrency(Currency&, std::string_view);
|
||||
|
||||
/**
|
||||
* Tries to convert a string to a Currency, returns noCurrency() on failure.
|
||||
@@ -107,8 +121,7 @@ toCurrency(Currency&, std::string const&);
|
||||
* unfortunate; changing this will require very careful checking
|
||||
* everywhere and may mean having to rewrite some unit test code.
|
||||
*/
|
||||
Currency
|
||||
toCurrency(std::string const&);
|
||||
Currency toCurrency(std::string_view);
|
||||
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& os, Currency const& x)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -182,7 +183,7 @@ public:
|
||||
operator result_type() noexcept
|
||||
{
|
||||
auto const digest = Sha512Hasher::result_type(h_);
|
||||
return result_type::fromVoid(digest.data());
|
||||
return result_type{std::span{digest}.first<result_type::size()>()};
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -300,7 +300,6 @@ JSS(in); // out: OverlayImpl
|
||||
JSS(inLedger); // out: tx/Transaction
|
||||
JSS(inbound); // out: PeerImp
|
||||
JSS(index); // in: LedgerEntry
|
||||
JSS(inner_results); // out: Tx
|
||||
// out: STLedgerEntry, LedgerEntry, TxHistory, LedgerData
|
||||
JSS(info); // out: ServerInfo, ConsensusInfo, FetchInfo
|
||||
JSS(initial_sync_duration_us); //
|
||||
@@ -393,6 +392,7 @@ JSS(max_ledger); // in/out: LedgerCleaner
|
||||
JSS(max_queue_size); // out: TxQ
|
||||
JSS(max_spend_drops); // out: AccountInfo
|
||||
JSS(max_spend_drops_total); // out: AccountInfo
|
||||
JSS(maximum);
|
||||
JSS(mean); // out: get_aggregate_price
|
||||
JSS(median); // out: get_aggregate_price
|
||||
JSS(median_fee); // out: TxQ
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <span>
|
||||
|
||||
namespace xrpl::nft {
|
||||
|
||||
@@ -98,7 +99,8 @@ getTaxon(UInt256 const& id)
|
||||
inline AccountID
|
||||
getIssuer(UInt256 const& id)
|
||||
{
|
||||
return AccountID::fromVoid(id.data() + 4);
|
||||
return AccountID{
|
||||
std::span<unsigned char const, uint256::size()>{id}.subspan<4, AccountID::size()>()};
|
||||
}
|
||||
|
||||
} // namespace xrpl::nft
|
||||
|
||||
@@ -2,13 +2,10 @@
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace xrpl::nft {
|
||||
|
||||
// NFT directory pages order their contents based only on the low 96 bits of
|
||||
// the NFToken value. This mask provides easy access to the necessary mask.
|
||||
constexpr UInt256 kPageMask(
|
||||
std::string_view("0000000000000000000000000000000000000000ffffffffffffffffffffffff"));
|
||||
constexpr UInt256 kPageMask{"0000000000000000000000000000000000000000ffffffffffffffffffffffff"};
|
||||
|
||||
} // namespace xrpl::nft
|
||||
|
||||
@@ -18,7 +18,7 @@ serializeBlob(Object const& o)
|
||||
{
|
||||
Serializer s;
|
||||
o.add(s);
|
||||
return s.peekData();
|
||||
return s.takeData();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -72,7 +72,7 @@ inline constexpr std::array<char const*, 5> kLgrDbInit{
|
||||
// Transaction database holds transactions and public keys
|
||||
inline constexpr auto kTxDbName{"transaction.db"};
|
||||
|
||||
inline constexpr std::array<char const*, 10> kTxDbInit{
|
||||
inline constexpr std::array<char const*, 8> kTxDbInit{
|
||||
{"BEGIN TRANSACTION;",
|
||||
|
||||
"CREATE TABLE IF NOT EXISTS Transactions ( \
|
||||
@@ -101,21 +101,6 @@ inline constexpr std::array<char const*, 10> kTxDbInit{
|
||||
"CREATE INDEX IF NOT EXISTS AcctLgrIndex ON \
|
||||
AccountTransactions(LedgerSeq, Account, TransID);",
|
||||
|
||||
// Outcome of each inner transaction of a Batch this node applied while building a
|
||||
// validated ledger. Inner transactions that failed are not in the ledger, so this is
|
||||
// the only record of them. See BatchInnerResult.
|
||||
"CREATE TABLE IF NOT EXISTS BatchInnerResults ( \
|
||||
ParentBatchID CHARACTER(64) NOT NULL, \
|
||||
InnerTxnID CHARACTER(64) NOT NULL, \
|
||||
TxnIndex INTEGER NOT NULL, \
|
||||
LedgerSeq BIGINT UNSIGNED NOT NULL, \
|
||||
TERResult INTEGER NOT NULL, \
|
||||
Applied INTEGER NOT NULL, \
|
||||
PRIMARY KEY (ParentBatchID, InnerTxnID) \
|
||||
);",
|
||||
"CREATE INDEX IF NOT EXISTS BatchInnerLgrIndex ON \
|
||||
BatchInnerResults(LedgerSeq);",
|
||||
|
||||
"END TRANSACTION;"}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/BatchInnerResult.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/LedgerHeader.h>
|
||||
#include <xrpl/protocol/LedgerShortcut.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/TxMeta.h>
|
||||
#include <xrpl/protocol/TxSearched.h>
|
||||
@@ -105,6 +105,21 @@ public:
|
||||
using TxnMetaLedgerType = std::tuple<Blob, Blob, std::uint32_t>;
|
||||
using MetaTxsList = std::vector<TxnMetaLedgerType>;
|
||||
|
||||
using LedgerSequence = uint32_t;
|
||||
using LedgerHash = UInt256;
|
||||
using LedgerSpecifier = std::variant<LedgerRange, LedgerShortcut, LedgerSequence, LedgerHash>;
|
||||
|
||||
struct AccountTxArgs
|
||||
{
|
||||
AccountID account;
|
||||
std::optional<LedgerSpecifier> ledger;
|
||||
bool binary = false;
|
||||
bool forward = false;
|
||||
uint32_t limit = 0;
|
||||
std::optional<AccountTxMarker> marker;
|
||||
std::optional<DelegateFilter> delegate;
|
||||
};
|
||||
|
||||
struct AccountTxResult
|
||||
{
|
||||
std::variant<AccountTxs, MetaTxsList> transactions;
|
||||
@@ -213,18 +228,6 @@ public:
|
||||
virtual std::optional<LedgerIndex>
|
||||
getAccountTransactionsMinLedgerSeq() = 0;
|
||||
|
||||
/**
|
||||
* @brief getBatchInnerResults Returns the recorded inner-transaction outcomes of a
|
||||
* Batch this node applied while building a validated ledger.
|
||||
* @param parentBatchId Hash of the outer Batch transaction.
|
||||
* @param ledgerSeq Ledger sequence the outer Batch transaction is validated in; rows
|
||||
* recorded for any other sequence are not this ledger's and are excluded.
|
||||
* @return Outcomes in RawTransactions order; empty if the tx tables are disabled or
|
||||
* nothing was recorded (a ledger acquired from the network records nothing).
|
||||
*/
|
||||
virtual std::vector<BatchInnerResult>
|
||||
getBatchInnerResults(uint256 const& parentBatchId, LedgerIndex ledgerSeq) = 0;
|
||||
|
||||
/**
|
||||
* @brief deleteTransactionByLedgerSeq Deletes transactions from the ledger
|
||||
* with the given sequence.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/ByteUtilities.h>
|
||||
#include <xrpl/basics/CountedObject.h>
|
||||
#include <xrpl/basics/SlabAllocator.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
@@ -15,12 +14,13 @@
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// an item stored in a SHAMap
|
||||
class SHAMapItem : public CountedObject<SHAMapItem>
|
||||
class alignas(8) SHAMapItem : public CountedObject<SHAMapItem>
|
||||
{
|
||||
// These are used to support boost::intrusive_ptr reference counting
|
||||
// These functions are used internally by boost::intrusive_ptr to handle
|
||||
@@ -101,15 +101,15 @@ namespace detail {
|
||||
// The slab cutoffs and the number of megabytes per allocation are customized
|
||||
// based on the number of objects of each size we expect to need at any point
|
||||
// in time and with an eye to minimize the number of slack bytes in a block.
|
||||
inline SlabAllocatorSet<SHAMapItem> gSlabber({
|
||||
{ 128, megabytes(std::size_t(60)) },
|
||||
{ 192, megabytes(std::size_t(46)) },
|
||||
{ 272, megabytes(std::size_t(60)) },
|
||||
{ 384, megabytes(std::size_t(56)) },
|
||||
{ 564, megabytes(std::size_t(40)) },
|
||||
{ 772, megabytes(std::size_t(46)) },
|
||||
{ 1052, megabytes(std::size_t(60)) },
|
||||
});
|
||||
inline constinit slab::Allocator<SHAMapItem, slab::HeapFallback,
|
||||
slab::Config<1000000, 128>,
|
||||
slab::Config<1000000, 296>,
|
||||
slab::Config<125000, 392>,
|
||||
slab::Config<125000, 520>,
|
||||
slab::Config<62500, 760>,
|
||||
slab::Config<62500, 856>,
|
||||
slab::Config<31250, 1048>
|
||||
> gSlabber;
|
||||
// clang-format on
|
||||
|
||||
} // namespace detail
|
||||
@@ -150,23 +150,13 @@ makeShamapitem(UInt256 const& tag, Slice data)
|
||||
XRPL_ASSERT(
|
||||
data.size() <= megabytes<std::size_t>(16), "xrpl::makeShamapitem : maximum input size");
|
||||
|
||||
// NOLINTNEXTLINE(misc-const-correctness)
|
||||
std::uint8_t* raw = detail::gSlabber.allocate(data.size());
|
||||
|
||||
// If we can't grab memory from the slab allocators, we fall back to
|
||||
// the standard library and try to grab a precisely-sized memory block:
|
||||
if (raw == nullptr)
|
||||
raw = new std::uint8_t[sizeof(SHAMapItem) + data.size()];
|
||||
|
||||
// We do not increment the reference count here on purpose: the
|
||||
// constructor of SHAMapItem explicitly sets it to 1. We use the fact
|
||||
// that the refcount can never be zero before incrementing as an
|
||||
// invariant.
|
||||
return {new (raw) SHAMapItem{tag, data}, false};
|
||||
}
|
||||
// constructor of SHAMapItem explicitly sets it to 1.
|
||||
if (auto raw = detail::gSlabber.allocate(data.size())) [[likely]]
|
||||
return {new (raw) SHAMapItem{tag, data}, false};
|
||||
|
||||
static_assert(alignof(SHAMapItem) != 40);
|
||||
static_assert(alignof(SHAMapItem) == 8 || alignof(SHAMapItem) == 4);
|
||||
Throw<std::bad_alloc>();
|
||||
}
|
||||
|
||||
inline boost::intrusive_ptr<SHAMapItem>
|
||||
makeShamapitem(SHAMapItem const& other)
|
||||
|
||||
@@ -51,7 +51,8 @@ public:
|
||||
beast::Journal journal = beast::Journal{beast::Journal::getNullSink()})
|
||||
: ApplyContext(registry, base, std::nullopt, tx, preclaimResult, baseFee, flags, journal)
|
||||
{
|
||||
XRPL_ASSERT((flags & TapBatch) == 0, "Batch apply flag should not be set");
|
||||
XRPL_ASSERT(
|
||||
(flags & ApplyFlags::Batch) == ApplyFlags::None, "Batch apply flag should not be set");
|
||||
}
|
||||
|
||||
std::reference_wrapper<ServiceRegistry> registry;
|
||||
|
||||
@@ -59,10 +59,11 @@ public:
|
||||
, parentBatchId(parentBatchId)
|
||||
, j(j)
|
||||
{
|
||||
XRPL_ASSERT((flags & TapBatch) == TapBatch, "Batch apply flag should be set");
|
||||
XRPL_ASSERT(
|
||||
(flags & ApplyFlags::Batch) == ApplyFlags::Batch, "Batch apply flag should be set");
|
||||
XRPL_ASSERT_IF(
|
||||
(flags & TapProposal) != TapNone,
|
||||
(flags & TapDryRun) != TapNone,
|
||||
(flags & ApplyFlags::Proposal) != ApplyFlags::None,
|
||||
(flags & ApplyFlags::DryRun) != ApplyFlags::None,
|
||||
"xrpl::PreflightContext : proposal preflight implies dry run");
|
||||
}
|
||||
|
||||
@@ -74,10 +75,11 @@ public:
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: registry(registry), tx(tx), rules(std::move(rules)), flags(flags), j(j)
|
||||
{
|
||||
XRPL_ASSERT((flags & TapBatch) == 0, "Batch apply flag should not be set");
|
||||
XRPL_ASSERT(
|
||||
(flags & ApplyFlags::Batch) == ApplyFlags::None, "Batch apply flag should not be set");
|
||||
XRPL_ASSERT_IF(
|
||||
(flags & TapProposal) != TapNone,
|
||||
(flags & TapDryRun) != TapNone,
|
||||
(flags & ApplyFlags::Proposal) != ApplyFlags::None,
|
||||
(flags & ApplyFlags::DryRun) != ApplyFlags::None,
|
||||
"xrpl::PreflightContext : proposal preflight implies dry run");
|
||||
}
|
||||
|
||||
@@ -116,7 +118,7 @@ public:
|
||||
, j(j)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
parentBatchId.has_value() == ((flags & TapBatch) == TapBatch),
|
||||
parentBatchId.has_value() == ((flags & ApplyFlags::Batch) == ApplyFlags::Batch),
|
||||
"Parent Batch ID should be set if batch apply flag is set");
|
||||
}
|
||||
|
||||
@@ -129,7 +131,8 @@ public:
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: PreclaimContext(registry, view, preflightResult, tx, flags, std::nullopt, j)
|
||||
{
|
||||
XRPL_ASSERT((flags & TapBatch) == 0, "Batch apply flag should not be set");
|
||||
XRPL_ASSERT(
|
||||
(flags & ApplyFlags::Batch) == ApplyFlags::None, "Batch apply flag should not be set");
|
||||
}
|
||||
|
||||
PreclaimContext&
|
||||
|
||||
@@ -4,14 +4,12 @@
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/OpenView.h>
|
||||
#include <xrpl/protocol/BatchInnerResult.h>
|
||||
#include <xrpl/protocol/Rules.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/tx/applySteps.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -144,7 +142,6 @@ enum class ApplyTransactionResult {
|
||||
* Provides more detailed logging and decodes the
|
||||
* correct behavior based on the `TER` type
|
||||
*
|
||||
* @param innerResults If set, receives one entry per inner transaction the outer Batch ran.
|
||||
* @see ApplyTransactionResult
|
||||
*/
|
||||
ApplyTransactionResult
|
||||
@@ -154,7 +151,6 @@ applyTransaction(
|
||||
STTx const& tx,
|
||||
bool retryAssured,
|
||||
ApplyFlags flags,
|
||||
beast::Journal journal,
|
||||
std::vector<BatchInnerResult>* innerResults = nullptr);
|
||||
beast::Journal journal);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -41,7 +41,7 @@ struct ApplyResult
|
||||
inline bool
|
||||
isTecClaimHardFail(TER ter, ApplyFlags flags)
|
||||
{
|
||||
return isTecClaim(ter) && ((flags & TapRetry) == 0u);
|
||||
return isTecClaim(ter) && ((flags & ApplyFlags::Retry) == ApplyFlags::None);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,14 +42,6 @@ class ValidMPTIssuance
|
||||
*/
|
||||
bool referenceHoldingMutated_ = false;
|
||||
|
||||
/**
|
||||
* Flags cleared on an existing MPTokenIssuance, except lsfMPTLocked,
|
||||
* which tfMPTUnlock clears legitimately. Every other issuance flag is
|
||||
* fixed at creation or set-once via MPTokenIssuanceSet, so any bit
|
||||
* accumulated here is a bug. Enforced post-fixCleanup3_5_0.
|
||||
*/
|
||||
std::uint32_t issuanceFlagsCleared_ = 0;
|
||||
|
||||
/**
|
||||
* MPTokens and RippleStates deleted during apply. finalize() checks each
|
||||
* holder's AccountRoot to detect vault pseudo-account holdings deleted
|
||||
|
||||
@@ -57,12 +57,6 @@ public:
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
|
||||
/**
|
||||
* Inner transaction types that preflight rejects before LendingProtocolV1_2.
|
||||
*
|
||||
* Once the amendment is enabled the list only matters when replaying older
|
||||
* ledgers. Remove it when LendingProtocolV1_2 is retired.
|
||||
*/
|
||||
static constexpr auto kDisabledTxTypes = std::to_array<TxType>({
|
||||
ttVAULT_CREATE,
|
||||
ttVAULT_SET,
|
||||
|
||||
@@ -5,8 +5,8 @@ Core build tools:
|
||||
cmake version 4.4.3
|
||||
/nix/store/q85csxf4s4shx89zif097h1ql4ax1rrz-cmake-4.4.3/bin/cmake
|
||||
✅ conan
|
||||
Conan version 2.33.0
|
||||
/nix/store/rp0zf22rx3iwnhxp4d53ncirn4lzg68j-conan-2.33.0/bin/conan
|
||||
Conan version 2.32.0
|
||||
/nix/store/921jqsgbilixmr3xchj95si0jl8pi13z-conan-2.32.0/bin/conan
|
||||
✅ git
|
||||
git version 2.55.0
|
||||
/nix/store/gw7c7m0dwca5lg4152x9lpmxpj171bzw-git-2.55.0/bin/git
|
||||
@@ -19,17 +19,17 @@ Development tooling:
|
||||
ccache version 4.13.6
|
||||
/nix/store/ydr5nlzxp1djb5256y0zzqa87vz55gsk-ccache-4.13.6/bin/ccache
|
||||
✅ clang
|
||||
clang version 23.1.0
|
||||
/nix/store/2c16z6akvv65znb8330sl5qpklaf3194-clang-wrapper-23.1.0/bin/clang
|
||||
✅ clang-23
|
||||
clang version 23.1.0
|
||||
/nix/store/vfd0q2395vyn0bsjsh1b4068icy1x9ph-clang-23/bin/clang-23
|
||||
clang version 22.1.8
|
||||
/nix/store/dakcxgwz4ixkk6ps50b7vn3dvblyzsnf-clang-wrapper-22.1.8/bin/clang
|
||||
✅ clang-22
|
||||
clang version 22.1.8
|
||||
/nix/store/w826sqb98nnym6kzackg829664iqdlxj-clang-22/bin/clang-22
|
||||
✅ clang++
|
||||
clang version 23.1.0
|
||||
/nix/store/2c16z6akvv65znb8330sl5qpklaf3194-clang-wrapper-23.1.0/bin/clang++
|
||||
✅ clang++-23
|
||||
clang version 23.1.0
|
||||
/nix/store/0i6kfnif2v4sqyv5fzfg8a9n09rw9lkp-clang++-23/bin/clang++-23
|
||||
clang version 22.1.8
|
||||
/nix/store/dakcxgwz4ixkk6ps50b7vn3dvblyzsnf-clang-wrapper-22.1.8/bin/clang++
|
||||
✅ clang++-22
|
||||
clang version 22.1.8
|
||||
/nix/store/wnwyw3yfqrhpxij65bl3pa1x65q2zg3m-clang++-22/bin/clang++-22
|
||||
✅ ClangBuildAnalyzer
|
||||
ClangBuildAnalyzer 1.6.0
|
||||
/nix/store/c7jjnw29ra78jdlzjww2m374izhy05n8-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
|
||||
@@ -39,9 +39,6 @@ Development tooling:
|
||||
✅ file
|
||||
file-5.48
|
||||
/nix/store/y44vpziwbzfm8020dzlqqbybyyy7lb6g-file-5.48/bin/file
|
||||
✅ jq
|
||||
jq-1.8.2
|
||||
/nix/store/wm7v59a2lhj1w2k8jz53spcs1iizm9lv-jq-1.8.2-bin/bin/jq
|
||||
✅ less
|
||||
less 710 (PCRE2 regular expressions)
|
||||
/nix/store/3yn3dx5fwg5i0inqqzwnxq7f6lwhpjqa-less-710/bin/less
|
||||
@@ -67,23 +64,23 @@ Development tooling:
|
||||
Zip 3.0
|
||||
/nix/store/dvawr36npnad4xa6dxi2ss0fw44aa82r-zip-3.0/bin/zip
|
||||
✅ clang-apply-replacements
|
||||
clang-apply-replacements version 23.1.0
|
||||
/nix/store/mva6ngy45m9in3m2lsfccj1y0z6n1f5s-clang-tools-23.1.0/bin/clang-apply-replacements
|
||||
✅ clang-apply-replacements-23
|
||||
clang-apply-replacements version 23.1.0
|
||||
/nix/store/872k02mqr21hxwcpfwaqkxljfj60aak0-clang-apply-replacements-23/bin/clang-apply-replacements-23
|
||||
clang-apply-replacements version 22.1.8
|
||||
/nix/store/5bij4zn161lagwyndmrr21vmxjg054nv-clang-tools-22.1.8/bin/clang-apply-replacements
|
||||
✅ clang-apply-replacements-22
|
||||
clang-apply-replacements version 22.1.8
|
||||
/nix/store/w4bz034k4l0w719rrmbwnqcgyjbswy81-clang-apply-replacements-22/bin/clang-apply-replacements-22
|
||||
✅ clang-format
|
||||
clang-format version 23.1.0
|
||||
/nix/store/mva6ngy45m9in3m2lsfccj1y0z6n1f5s-clang-tools-23.1.0/bin/clang-format
|
||||
✅ clang-format-23
|
||||
clang-format version 23.1.0
|
||||
/nix/store/wf30x6lcya44n2y1fagd6q7x7p4gyl6f-clang-format-23/bin/clang-format-23
|
||||
clang-format version 22.1.8
|
||||
/nix/store/5bij4zn161lagwyndmrr21vmxjg054nv-clang-tools-22.1.8/bin/clang-format
|
||||
✅ clang-format-22
|
||||
clang-format version 22.1.8
|
||||
/nix/store/w7z346l0r8y36b6lc5i7jzj3w0581l2y-clang-format-22/bin/clang-format-22
|
||||
✅ clang-tidy
|
||||
LLVM version 23.1.0
|
||||
/nix/store/mva6ngy45m9in3m2lsfccj1y0z6n1f5s-clang-tools-23.1.0/bin/clang-tidy
|
||||
✅ clang-tidy-23
|
||||
LLVM version 23.1.0
|
||||
/nix/store/kgx00aass66g02p1s4gqqf65kq39m4ci-clang-tidy-23/bin/clang-tidy-23
|
||||
LLVM version 22.1.8
|
||||
/nix/store/5bij4zn161lagwyndmrr21vmxjg054nv-clang-tools-22.1.8/bin/clang-tidy
|
||||
✅ clang-tidy-22
|
||||
LLVM version 22.1.8
|
||||
/nix/store/0lv25qd3ddgjm3ndn70q61jfr6krlkl7-clang-tidy-22/bin/clang-tidy-22
|
||||
✅ dot
|
||||
dot - graphviz version 15.1.1 (0)
|
||||
/nix/store/mc99a6bpbk2waym2cnw6ifmxli4ndb4x-graphviz-15.1.1/bin/dot
|
||||
@@ -110,10 +107,10 @@ Development tooling:
|
||||
/nix/store/ivh54xypg9qvd3ha9lis0i8p4nkf8n7a-pre-commit-4.6.2/bin/pre-commit
|
||||
✅ run-clang-tidy
|
||||
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
|
||||
/nix/store/zjbzr154xan5xg9pmjiv0zkwklyb94wv-run-clang-tidy/bin/run-clang-tidy
|
||||
✅ run-clang-tidy-23
|
||||
/nix/store/3xss1mm3mh1hzcmg182na6ki1p5rnxf1-run-clang-tidy/bin/run-clang-tidy
|
||||
✅ run-clang-tidy-22
|
||||
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
|
||||
/nix/store/svhfrpgx2j581brsqmkpav9b286v22yy-run-clang-tidy-23/bin/run-clang-tidy-23
|
||||
/nix/store/w68r9z07hcq4fwbfyq3yvc7qxm8aqfbl-run-clang-tidy-22/bin/run-clang-tidy-22
|
||||
|
||||
Rust toolchain:
|
||||
✅ cargo
|
||||
@@ -146,4 +143,4 @@ Rust toolchain:
|
||||
|
||||
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
|
||||
|
||||
✅ All 46 checked tools are present and runnable.
|
||||
✅ All 45 checked tools are present and runnable.
|
||||
|
||||
@@ -2,176 +2,173 @@ Detected OS: linux (Linux x86_64)
|
||||
|
||||
Core build tools:
|
||||
✅ cmake
|
||||
cmake version 4.4.3
|
||||
/nix/store/jcvvpih1046akxcwh9hdiak5q24jqcf0-cmake-4.4.3/bin/cmake
|
||||
cmake version 4.1.2
|
||||
/nix/store/r9941n32g4wyvggz2703dlplbdq8a6rd-cmake-4.1.2/bin/cmake
|
||||
✅ conan
|
||||
Conan version 2.33.0
|
||||
/nix/store/b4lnzrqc60glhl9al1nakfc0vd20kdna-conan-2.33.0/bin/conan
|
||||
Conan version 2.28.1
|
||||
/nix/store/lxny9y4jvjdws7hgz1mygvb7hjrpmna5-conan-2.28.1/bin/conan
|
||||
✅ git
|
||||
git version 2.55.0
|
||||
/nix/store/lg46w7hrjx7kylsh6645c9l975i8h43b-git-2.55.0/bin/git
|
||||
git version 2.54.0
|
||||
/nix/store/bcnisk3ydfgv26v2gw3zlky24g00yww2-git-2.54.0/bin/git
|
||||
✅ python3
|
||||
Python 3.14.7
|
||||
/nix/store/lb41b0anx1f98y9y5s9mdv97gjgsq740-python3-3.14.7/bin/python3.14
|
||||
Python 3.13.13
|
||||
/nix/store/60m4rxhg2fldqaak400c0lry96ijrzqn-python3-3.13.13/bin/python3.13
|
||||
|
||||
Development tooling:
|
||||
✅ ccache
|
||||
ccache version 4.13.6
|
||||
/nix/store/p1a1s700dqsw1b3b8d2ba64nqw68zgpy-ccache-4.13.6/bin/ccache
|
||||
/nix/store/c9wwl7s5i6rsfwvf4v0xbbmzx5m6jgfr-ccache-4.13.6/bin/ccache
|
||||
✅ clang
|
||||
clang version 23.1.0
|
||||
/nix/store/mlqh1xrp0zi3i5g9b0zjcz6zlbbzdgb8-clang-wrapper-23.1.0/bin/clang
|
||||
✅ clang-23
|
||||
clang version 23.1.0
|
||||
/nix/store/xgi7q1bady9dk89zvjmiicjzzp1gvm7x-clang-23/bin/clang-23
|
||||
clang version 22.1.7
|
||||
/nix/store/ff0hrp9r9i3pa5arkdw0sgmzp8d576qi-clang-wrapper-22.1.7/bin/clang
|
||||
✅ clang-22
|
||||
clang version 22.1.7
|
||||
/nix/store/dagc2rq44gfbr7w7yvvqca3yqpc9gqbq-clang-22/bin/clang-22
|
||||
✅ clang++
|
||||
clang version 23.1.0
|
||||
/nix/store/mlqh1xrp0zi3i5g9b0zjcz6zlbbzdgb8-clang-wrapper-23.1.0/bin/clang++
|
||||
✅ clang++-23
|
||||
clang version 23.1.0
|
||||
/nix/store/4slsaz29v72xgc4g36cp94f0p41a81pv-clang++-23/bin/clang++-23
|
||||
clang version 22.1.7
|
||||
/nix/store/ff0hrp9r9i3pa5arkdw0sgmzp8d576qi-clang-wrapper-22.1.7/bin/clang++
|
||||
✅ clang++-22
|
||||
clang version 22.1.7
|
||||
/nix/store/l5m8clin1npl605wdkd8mr18ggxww3z4-clang++-22/bin/clang++-22
|
||||
✅ ClangBuildAnalyzer
|
||||
ClangBuildAnalyzer 1.6.0
|
||||
/nix/store/gvx8im1c89vspwb8ixa91lr1dagbi241-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
|
||||
/nix/store/bshlmn8fqw55nsnm581xqlfbahfkykxx-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
|
||||
✅ curl
|
||||
curl 8.22.0 (x86_64-pc-linux-gnu) libcurl/8.22.0 OpenSSL/3.5.8 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.70.0 mit-krb5/1.22.2
|
||||
/nix/store/305w9ipyg497mz9dq31abdf61qk58k29-curl-8.22.0-bin/bin/curl
|
||||
curl 8.20.0 (x86_64-pc-linux-gnu) libcurl/8.20.0 OpenSSL/3.6.2 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.69.0 mit-krb5/1.22.1
|
||||
/nix/store/zbwymrp4lcfjc4kkk0n4779v0kjjz58z-curl-8.20.0-bin/bin/curl
|
||||
✅ file
|
||||
file-5.48
|
||||
/nix/store/g0fbnccaan8q0rxlw43xnbyb90i94vlc-file-5.48/bin/file
|
||||
✅ jq
|
||||
jq-1.8.2
|
||||
/nix/store/m3y7hqmy20nd1ps6qy8410a326255bf0-jq-1.8.2-bin/bin/jq
|
||||
file-5.47
|
||||
/nix/store/bizyfqdw0h67wzqmp10knmf9s2pqahdb-file-5.47/bin/file
|
||||
✅ less
|
||||
less 710 (PCRE2 regular expressions)
|
||||
/nix/store/zi4d0awnc6crz18s177bv9y2yz9al3lq-less-710/bin/less
|
||||
less 692 (PCRE2 regular expressions)
|
||||
/nix/store/c6bacbn93qg4a7g9n4czww8rg24dvysr-less-692/bin/less
|
||||
✅ make
|
||||
GNU Make 4.4.1
|
||||
/nix/store/z565rgmn9vccv2h0g87z725pw610jmm8-gnumake-4.4.1/bin/make
|
||||
/nix/store/d3bwqm6bymhy3pdgbvf7vxjqfp31m3j1-gnumake-4.4.1/bin/make
|
||||
✅ netstat
|
||||
net-tools 2.10
|
||||
/nix/store/9i6j9lrsliyz1ww2f8xx18z36wc9n38a-net-tools-2.10/bin/netstat
|
||||
/nix/store/jmyzqvgflnswmws7rnxx6g3zbj680xvd-net-tools-2.10/bin/netstat
|
||||
✅ ninja
|
||||
1.13.2
|
||||
/nix/store/4nsdla28c4177ssp0hlyv5l2yzj8wcba-ninja-1.13.2/bin/ninja
|
||||
/nix/store/7a235m7crqbb4h49sak20fqxpw3n7hr0-ninja-1.13.2/bin/ninja
|
||||
✅ perl
|
||||
v5.42.3
|
||||
/nix/store/8g4dmf7l8q1mf9w4wfmlcl8gvdgmhb8v-perl-5.42.3/bin/perl
|
||||
v5.42.0
|
||||
/nix/store/6plwsm6pkq79yjv4xvy8csk2pd4hzr67-perl-5.42.0/bin/perl
|
||||
✅ pkg-config
|
||||
0.29.2
|
||||
/nix/store/b9izmrfjp0qnnyahdwwrzdwi87s1h179-pkg-config-wrapper-0.29.2/bin/pkg-config
|
||||
/nix/store/1m05k7xgfnw6jc21xxk5681ni3ar97wf-pkg-config-wrapper-0.29.2/bin/pkg-config
|
||||
✅ vim
|
||||
VIM - Vi IMproved 9.2 (2026 Feb 14, compiled Jan 01 1980 00:00:00)
|
||||
/nix/store/9swnd5pf8p8w1gwcbhdpm2yx705kbp38-vim-9.2.1001/bin/vim
|
||||
/nix/store/hvyqx52g4g2fxhgpans3fksjj6lmlyaw-vim-9.2.0389/bin/vim
|
||||
✅ zip
|
||||
Zip 3.0
|
||||
/nix/store/5ypvkry3qra47dylc9kfk36r1q9vha80-zip-3.0/bin/zip
|
||||
/nix/store/qnd2ag67hrjj0b6vbmisdshf50r6s72n-zip-3.0/bin/zip
|
||||
✅ clang-apply-replacements
|
||||
clang-apply-replacements version 23.1.0
|
||||
/nix/store/ipnj8b3s6f00ngi26fi7p5h9lxv6a3s3-clang-tools-23.1.0/bin/clang-apply-replacements
|
||||
✅ clang-apply-replacements-23
|
||||
clang-apply-replacements version 23.1.0
|
||||
/nix/store/lbyc9hrkkymybah7b6n8c7sijlgldfz0-clang-apply-replacements-23/bin/clang-apply-replacements-23
|
||||
clang-apply-replacements version 22.1.7
|
||||
/nix/store/4zp1rjpj2xijrv4kqpwsy3ixwb2r6nlk-clang-tools-22.1.7/bin/clang-apply-replacements
|
||||
✅ clang-apply-replacements-22
|
||||
clang-apply-replacements version 22.1.7
|
||||
/nix/store/py2wihg0a96qcppv4hjmww547xabr0fb-clang-apply-replacements-22/bin/clang-apply-replacements-22
|
||||
✅ clang-format
|
||||
clang-format version 23.1.0
|
||||
/nix/store/ipnj8b3s6f00ngi26fi7p5h9lxv6a3s3-clang-tools-23.1.0/bin/clang-format
|
||||
✅ clang-format-23
|
||||
clang-format version 23.1.0
|
||||
/nix/store/40w351b7i7aqhpl5wmicfnp2ij8k12g9-clang-format-23/bin/clang-format-23
|
||||
clang-format version 22.1.7
|
||||
/nix/store/4zp1rjpj2xijrv4kqpwsy3ixwb2r6nlk-clang-tools-22.1.7/bin/clang-format
|
||||
✅ clang-format-22
|
||||
clang-format version 22.1.7
|
||||
/nix/store/kz820ccifjlwqnwqjsx7kbiajrgsmbrh-clang-format-22/bin/clang-format-22
|
||||
✅ clang-tidy
|
||||
LLVM version 23.1.0
|
||||
/nix/store/ipnj8b3s6f00ngi26fi7p5h9lxv6a3s3-clang-tools-23.1.0/bin/clang-tidy
|
||||
✅ clang-tidy-23
|
||||
LLVM version 23.1.0
|
||||
/nix/store/40rj38k5ygq7sawkiv0cdaljclbspwz9-clang-tidy-23/bin/clang-tidy-23
|
||||
LLVM version 22.1.7
|
||||
/nix/store/4zp1rjpj2xijrv4kqpwsy3ixwb2r6nlk-clang-tools-22.1.7/bin/clang-tidy
|
||||
✅ clang-tidy-22
|
||||
LLVM version 22.1.7
|
||||
/nix/store/gdrkvpw846lkyzh8y9p3zx50g6ml2v84-clang-tidy-22/bin/clang-tidy-22
|
||||
✅ dot
|
||||
dot - graphviz version 15.1.1 (0)
|
||||
/nix/store/f7r47nc0d13xa4c2xaaxa6dp3pzm9sp1-graphviz-15.1.1/bin/dot
|
||||
dot - graphviz version 12.2.1 (0)
|
||||
/nix/store/12rgns2296s4qcja778gvcbx61z77rc4-graphviz-12.2.1/bin/dot
|
||||
✅ doxygen
|
||||
1.17.0
|
||||
/nix/store/q6yx2nsimj9xmckmgw4br2cnapbgnqpk-doxygen-1.17.0/bin/doxygen
|
||||
1.16.1
|
||||
/nix/store/k0vzr5lvgq1byraknzwvk51wcgpnsrkh-doxygen-1.16.1/bin/doxygen
|
||||
✅ gcovr
|
||||
gcovr 8.4
|
||||
/nix/store/shx7mfl8n4kx11icvwyj5x7cmf6z5ahq-python3.14-gcovr-8.4/bin/gcovr
|
||||
/nix/store/iyzi7fpyclqrha054adnizvif02lg49x-python3.13-gcovr-8.4/bin/gcovr
|
||||
✅ gh
|
||||
gh version 2.102.0 (2026-09-30)
|
||||
/nix/store/66h5dr9v94x04myh2kabx06rq9763jfc-gh-2.102.0/bin/gh
|
||||
gh version 2.94.0 (nixpkgs)
|
||||
/nix/store/pidh15szlsb1vc41xdsa3xbdghdazvby-gh-2.94.0/bin/gh
|
||||
✅ git-cliff
|
||||
git-cliff 2.14.2
|
||||
/nix/store/sl19b42d69b3w2vb9pxp6jbqk841z8vj-git-cliff-2.14.2/bin/git-cliff
|
||||
git-cliff 2.13.1
|
||||
/nix/store/1q851fs62shgjhc03fxxdkpzxdjg7k11-git-cliff-2.13.1/bin/git-cliff
|
||||
✅ git-lfs
|
||||
git-lfs/3.8.0 (3.8.0; linux amd64; go 1.26.8)
|
||||
/nix/store/rp9ld1f6h83xmf2rb5fpib5wmr46fy9f-git-lfs-3.8.0/bin/git-lfs
|
||||
git-lfs/3.7.1 (3.7.1; linux amd64; go 1.26.3)
|
||||
/nix/store/6ljwpal7b1756708m33vj0crpral7mvl-git-lfs-3.7.1/bin/git-lfs
|
||||
✅ gpg
|
||||
gpg (GnuPG) 2.4.9
|
||||
/nix/store/8gm9aq3sspqmvvh7c0x7djcivj2x7yvn-gnupg-2.4.9/bin/gpg
|
||||
/nix/store/wx7vk8babxkgy813r70yc67vcwnmagbx-gnupg-2.4.9/bin/gpg
|
||||
✅ pre-commit
|
||||
pre-commit 4.6.2
|
||||
/nix/store/6blf72f7sdmlrqjggxvk5ij4cxb7fk4c-pre-commit-4.6.2/bin/pre-commit
|
||||
pre-commit 4.5.1
|
||||
/nix/store/bj6i9vl34cij5h0r165y40hrjqak0bmz-pre-commit-4.5.1/bin/pre-commit
|
||||
✅ run-clang-tidy
|
||||
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
|
||||
/nix/store/y7isn3dr8bildnp78vk5nhcav63g80dz-run-clang-tidy/bin/run-clang-tidy
|
||||
✅ run-clang-tidy-23
|
||||
/nix/store/sbg911hs9dbclrzlp04br3iyfpgnaj6r-run-clang-tidy/bin/run-clang-tidy
|
||||
✅ run-clang-tidy-22
|
||||
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
|
||||
/nix/store/pm5a8465hs9zb5i116b39i0y3xfpw6n3-run-clang-tidy-23/bin/run-clang-tidy-23
|
||||
/nix/store/n8yak1ap308gvi7gmrniw0ybsx80fjws-run-clang-tidy-22/bin/run-clang-tidy-22
|
||||
|
||||
Rust toolchain:
|
||||
✅ cargo
|
||||
cargo 1.97.1 (c980f4866 2026-06-30)
|
||||
/nix/store/60b0cz400q34wj2gzav5a41i7y6jzlw3-cargo-1.97.1-x86_64-unknown-linux-gnu/bin/cargo
|
||||
/nix/store/88abzp43ywyzql1rhf8jh5aj5n5j7xzr-cargo-1.97.1-x86_64-unknown-linux-gnu/bin/cargo
|
||||
✅ cargo-audit
|
||||
cargo-audit-audit 0.22.2
|
||||
/nix/store/kksgynfwir3pfii9qkbj3gcc61an0d4s-cargo-audit-0.22.2/bin/cargo-audit
|
||||
cargo-audit-audit 0.22.1
|
||||
/nix/store/2w9if868piw98xz057sz97jnjvf7hnvf-cargo-audit-0.22.1/bin/cargo-audit
|
||||
✅ cargo-llvm-cov
|
||||
cargo-llvm-cov 0.9.0
|
||||
/nix/store/4y8qxx0mlm22hnxlw2cmbcwpxispw02h-cargo-llvm-cov-0.9.0/bin/cargo-llvm-cov
|
||||
cargo-llvm-cov 0.8.5
|
||||
/nix/store/jjpdf1l6izz6607a346ykra9sndzaw7h-cargo-llvm-cov-0.8.5/bin/cargo-llvm-cov
|
||||
✅ cargo-nextest
|
||||
cargo-nextest 0.9.146
|
||||
/nix/store/q0anzqrazmdr8n1049ca28098q6lv2y8-cargo-nextest-0.9.146/bin/cargo-nextest
|
||||
cargo-nextest 0.9.137
|
||||
/nix/store/jhkr7gwyrchkml33gyns9cy0yn7b57qc-cargo-nextest-0.9.137/bin/cargo-nextest
|
||||
✅ clippy-driver
|
||||
clippy 0.1.97 (8bab26f4f6 2026-07-14)
|
||||
/nix/store/kk0kqdc4f7am21yp30rr8jcrnib5xqzy-rust-minimal-1.97.1/bin/clippy-driver
|
||||
/nix/store/40d3mzka7r1ps71l0yv2fs6616nbw85m-rust-minimal-1.97.1/bin/clippy-driver
|
||||
✅ rust-analyzer
|
||||
rust-analyzer 1.97.1 (8bab26f 2026-07-14)
|
||||
/nix/store/4mglk7qw9jqbv5nwlx9ahdnpcn5sz70r-rust-analyzer-preview-1.97.1-x86_64-unknown-linux-gnu/bin/rust-analyzer
|
||||
/nix/store/lr3m97p3hx1k22a7c44pb0wa7rbayhfi-rust-analyzer-preview-1.97.1-x86_64-unknown-linux-gnu/bin/rust-analyzer
|
||||
✅ rust-nightly
|
||||
rustc 1.101.0-nightly (282215592 2026-10-04)
|
||||
/nix/store/qwyzkvba3f9569wjj45b4iyb7nz7qbnr-rust-nightly/bin/rust-nightly
|
||||
rustc 1.99.0-nightly (87e5904f5 2026-07-20)
|
||||
/nix/store/j7kf7a5h4xypzp6x1skg4dsdx2k4fwb3-rust-nightly/bin/rust-nightly
|
||||
✅ rustc
|
||||
rustc 1.97.1 (8bab26f4f 2026-07-14)
|
||||
/nix/store/kk0kqdc4f7am21yp30rr8jcrnib5xqzy-rust-minimal-1.97.1/bin/rustc
|
||||
/nix/store/40d3mzka7r1ps71l0yv2fs6616nbw85m-rust-minimal-1.97.1/bin/rustc
|
||||
✅ rustfmt
|
||||
rustfmt 1.9.0-stable (8bab26f4f6 2026-07-14)
|
||||
/nix/store/y5gf8a3hix7pnwzdwcfpf3acqhzv3xy6-rustfmt-preview-1.97.1-x86_64-unknown-linux-gnu/bin/rustfmt
|
||||
/nix/store/6f1icmb2za20kxn30pgmbv5jq9fnbf4z-rustfmt-preview-1.97.1-x86_64-unknown-linux-gnu/bin/rustfmt
|
||||
|
||||
GCC toolchain:
|
||||
✅ gcc
|
||||
gcc (GCC) 15.3.0
|
||||
/nix/store/bslmkbaiymxxdc6lwcdb1qyw745nds5j-gcc-wrapper-15.3.0/bin/gcc
|
||||
gcc (GCC) 15.2.0
|
||||
/nix/store/3dd6y3pq00i3r85l45jvz63wjya403nl-gcc-wrapper-15.2.0/bin/gcc
|
||||
✅ gcc-15
|
||||
gcc (GCC) 15.3.0
|
||||
/nix/store/h6f2qc8kgwf7r81gwb10csvpjqfc2404-gcc-15/bin/gcc-15
|
||||
gcc (GCC) 15.2.0
|
||||
/nix/store/d6iri2s6bzqq5ac3fg25j6hgnn1lz44f-gcc-15/bin/gcc-15
|
||||
✅ g++
|
||||
g++ (GCC) 15.3.0
|
||||
/nix/store/bslmkbaiymxxdc6lwcdb1qyw745nds5j-gcc-wrapper-15.3.0/bin/g++
|
||||
g++ (GCC) 15.2.0
|
||||
/nix/store/3dd6y3pq00i3r85l45jvz63wjya403nl-gcc-wrapper-15.2.0/bin/g++
|
||||
✅ g++-15
|
||||
g++ (GCC) 15.3.0
|
||||
/nix/store/jwncv76v61ld9l99v0b1dkmf810if65s-g++-15/bin/g++-15
|
||||
g++ (GCC) 15.2.0
|
||||
/nix/store/gm3msmmxq055lm9gprkfjj9d2gdz1mpg-g++-15/bin/g++-15
|
||||
✅ cpp
|
||||
cpp (GCC) 15.3.0
|
||||
/nix/store/bslmkbaiymxxdc6lwcdb1qyw745nds5j-gcc-wrapper-15.3.0/bin/cpp
|
||||
cpp (GCC) 15.2.0
|
||||
/nix/store/3dd6y3pq00i3r85l45jvz63wjya403nl-gcc-wrapper-15.2.0/bin/cpp
|
||||
✅ cpp-15
|
||||
cpp (GCC) 15.3.0
|
||||
/nix/store/jmi558xj8v7lz2fm6wrradh40dp48zx9-cpp-15/bin/cpp-15
|
||||
cpp (GCC) 15.2.0
|
||||
/nix/store/bn3gmn0m7g4gn2i0yml46fljc7mghiq5-cpp-15/bin/cpp-15
|
||||
✅ gcov
|
||||
gcov (GCC) 15.3.0
|
||||
/nix/store/n2ab7kf7mm84hna35x463mizcy52pf1h-gcc-15.3.0/bin/gcov
|
||||
gcov (GCC) 15.2.0
|
||||
/nix/store/xvv5sm5i8x0ks6ypfkzl7c4j9srnxz7k-gcc-15.2.0/bin/gcov
|
||||
|
||||
Mold:
|
||||
✅ mold
|
||||
mold 2.42.1 (compatible with GNU ld)
|
||||
/nix/store/9dcddrfxlfl9n3wfibi5jkmp22bjkvkh-mold-unwrapped-wrapper-2.42.1/bin/mold
|
||||
mold 2.41.0 (compatible with GNU ld)
|
||||
/nix/store/2w6fpgxjzzyqmd25wzplm23dfa49a0p2-mold-unwrapped-wrapper-2.41.0/bin/mold
|
||||
|
||||
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
|
||||
|
||||
✅ All 54 checked tools are present and runnable.
|
||||
✅ All 53 checked tools are present and runnable.
|
||||
|
||||
@@ -2,176 +2,173 @@ Detected OS: linux (Linux aarch64)
|
||||
|
||||
Core build tools:
|
||||
✅ cmake
|
||||
cmake version 4.4.3
|
||||
/nix/store/39cq2g3d3flq2lmb6hc09grxs4xaax8p-cmake-4.4.3/bin/cmake
|
||||
cmake version 4.1.2
|
||||
/nix/store/nkcpxjifkambzlrwh27a8igvhnbchibg-cmake-4.1.2/bin/cmake
|
||||
✅ conan
|
||||
Conan version 2.33.0
|
||||
/nix/store/grz6a77mllqzzmg198qagx1r9zhvfijw-conan-2.33.0/bin/conan
|
||||
Conan version 2.28.1
|
||||
/nix/store/8i2gyqgc00xvxg9xm6y7n0ilncdv8imw-conan-2.28.1/bin/conan
|
||||
✅ git
|
||||
git version 2.55.0
|
||||
/nix/store/kj6aff4gmz3snpp35rl3gysbl9srd81a-git-2.55.0/bin/git
|
||||
git version 2.54.0
|
||||
/nix/store/ixp98f9avf8ikpdrmp40cj33g0dazyp9-git-2.54.0/bin/git
|
||||
✅ python3
|
||||
Python 3.14.7
|
||||
/nix/store/81ag9nxz1flw3xjkv1vvqg8y2ipx2ins-python3-3.14.7/bin/python3.14
|
||||
Python 3.13.13
|
||||
/nix/store/lqn6mbgzzdrqq2qkwddcmxj9z6amdd86-python3-3.13.13/bin/python3.13
|
||||
|
||||
Development tooling:
|
||||
✅ ccache
|
||||
ccache version 4.13.6
|
||||
/nix/store/nzb1lir9sw06fn4635kfx055myqanaz8-ccache-4.13.6/bin/ccache
|
||||
/nix/store/2q39xi2kbi04ibga7635f2sl148d1mzv-ccache-4.13.6/bin/ccache
|
||||
✅ clang
|
||||
clang version 23.1.0
|
||||
/nix/store/g8sc13kz6jarzip643hk01832x40v8ms-clang-wrapper-23.1.0/bin/clang
|
||||
✅ clang-23
|
||||
clang version 23.1.0
|
||||
/nix/store/j8qvcg9150s5n09qg8p62q5z3ci02hd9-clang-23/bin/clang-23
|
||||
clang version 22.1.7
|
||||
/nix/store/xjqffrq9i7la058s9865ig71l9sp1ys5-clang-wrapper-22.1.7/bin/clang
|
||||
✅ clang-22
|
||||
clang version 22.1.7
|
||||
/nix/store/vcf6ilfwn57828hwzyp6zlyr24j9j6yw-clang-22/bin/clang-22
|
||||
✅ clang++
|
||||
clang version 23.1.0
|
||||
/nix/store/g8sc13kz6jarzip643hk01832x40v8ms-clang-wrapper-23.1.0/bin/clang++
|
||||
✅ clang++-23
|
||||
clang version 23.1.0
|
||||
/nix/store/n62cn5w7fgbslamy3dgm8zhl5yly7zq0-clang++-23/bin/clang++-23
|
||||
clang version 22.1.7
|
||||
/nix/store/xjqffrq9i7la058s9865ig71l9sp1ys5-clang-wrapper-22.1.7/bin/clang++
|
||||
✅ clang++-22
|
||||
clang version 22.1.7
|
||||
/nix/store/xby0f6gamr7m27zp5cndsvghbp9lgb3c-clang++-22/bin/clang++-22
|
||||
✅ ClangBuildAnalyzer
|
||||
ClangBuildAnalyzer 1.6.0
|
||||
/nix/store/ml2991pbdhh0qcxqj9331lhpsg449vky-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
|
||||
/nix/store/h893hd4q1bb6ily2lby5dzyfrrzd2nvj-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
|
||||
✅ curl
|
||||
curl 8.22.0 (aarch64-unknown-linux-gnu) libcurl/8.22.0 OpenSSL/3.5.8 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.70.0 mit-krb5/1.22.2
|
||||
/nix/store/94c2x2bl3xb7mx43sg1bs1hd7pnw83ac-curl-8.22.0-bin/bin/curl
|
||||
curl 8.20.0 (aarch64-unknown-linux-gnu) libcurl/8.20.0 OpenSSL/3.6.2 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.69.0 mit-krb5/1.22.1
|
||||
/nix/store/i1s0lqwlrmjd2dxzgy2p84cxqqsb0bmk-curl-8.20.0-bin/bin/curl
|
||||
✅ file
|
||||
file-5.48
|
||||
/nix/store/66sd1x1hls0yijibn00iz08jh4fnas9z-file-5.48/bin/file
|
||||
✅ jq
|
||||
jq-1.8.2
|
||||
/nix/store/kr5py0dcqc9f3l9148qd1axh0z77lld3-jq-1.8.2-bin/bin/jq
|
||||
file-5.47
|
||||
/nix/store/dx973zg9km2w9albsib2vw9wyvacfrlw-file-5.47/bin/file
|
||||
✅ less
|
||||
less 710 (PCRE2 regular expressions)
|
||||
/nix/store/n6z9dv3yjlgvfx1nmrx6qzyv8vzim1l2-less-710/bin/less
|
||||
less 692 (PCRE2 regular expressions)
|
||||
/nix/store/1blb3s7hhsr77wqi598m6k1qkfp3ms0w-less-692/bin/less
|
||||
✅ make
|
||||
GNU Make 4.4.1
|
||||
/nix/store/q07jxvck60qgrg4p1ywypddh5zz6i9s2-gnumake-4.4.1/bin/make
|
||||
/nix/store/9ngw1ippk25jjj5fjxv36xbp6iq7rxdx-gnumake-4.4.1/bin/make
|
||||
✅ netstat
|
||||
net-tools 2.10
|
||||
/nix/store/rfmhd3f8drg3wqyr2mhyrlkd7vyp2pxv-net-tools-2.10/bin/netstat
|
||||
/nix/store/7vdsz21f0s499s5yyqzp5s4676q4yxdd-net-tools-2.10/bin/netstat
|
||||
✅ ninja
|
||||
1.13.2
|
||||
/nix/store/lfkdyggn1ffslfd830l35jrvapr5lzri-ninja-1.13.2/bin/ninja
|
||||
/nix/store/8ksx98gsbn5lmlizcmw57yd4sg0k2p58-ninja-1.13.2/bin/ninja
|
||||
✅ perl
|
||||
v5.42.3
|
||||
/nix/store/nyp5q4d2cb0pghi4i7nscb97bqkb6kp3-perl-5.42.3/bin/perl
|
||||
v5.42.0
|
||||
/nix/store/5wnly69vv1i3y97al4v3xrqymf9hlzgq-perl-5.42.0/bin/perl
|
||||
✅ pkg-config
|
||||
0.29.2
|
||||
/nix/store/h82n3d0wdrgskdc3yvmz5l3c50h2snvp-pkg-config-wrapper-0.29.2/bin/pkg-config
|
||||
/nix/store/c7vwy0gl1q0agl2h22gi0m9dg7xxad2l-pkg-config-wrapper-0.29.2/bin/pkg-config
|
||||
✅ vim
|
||||
VIM - Vi IMproved 9.2 (2026 Feb 14, compiled Jan 01 1980 00:00:00)
|
||||
/nix/store/h39h0qq4i80sp3yd7sxjn2wf497v5rln-vim-9.2.1001/bin/vim
|
||||
/nix/store/v8c7pvx26irvy9k5sbwd183cyvckzzb3-vim-9.2.0389/bin/vim
|
||||
✅ zip
|
||||
Zip 3.0
|
||||
/nix/store/lfwhq17wfcmjy823fldhlhxj1hjchdzc-zip-3.0/bin/zip
|
||||
/nix/store/5mh19mvbv9ym2sm9vymyyaac5l2cj2jq-zip-3.0/bin/zip
|
||||
✅ clang-apply-replacements
|
||||
clang-apply-replacements version 23.1.0
|
||||
/nix/store/jh9xhz6gwxyz3rfx7vy5g4j5d71w940r-clang-tools-23.1.0/bin/clang-apply-replacements
|
||||
✅ clang-apply-replacements-23
|
||||
clang-apply-replacements version 23.1.0
|
||||
/nix/store/1ajzrfr62m3cianfh9i97r30a7vp1xmb-clang-apply-replacements-23/bin/clang-apply-replacements-23
|
||||
clang-apply-replacements version 22.1.7
|
||||
/nix/store/s53p2m776iqaz7acgr5csgpsd18w15h7-clang-tools-22.1.7/bin/clang-apply-replacements
|
||||
✅ clang-apply-replacements-22
|
||||
clang-apply-replacements version 22.1.7
|
||||
/nix/store/bg4kn8z81hk7b9284rjqvr51wpfjqc24-clang-apply-replacements-22/bin/clang-apply-replacements-22
|
||||
✅ clang-format
|
||||
clang-format version 23.1.0
|
||||
/nix/store/jh9xhz6gwxyz3rfx7vy5g4j5d71w940r-clang-tools-23.1.0/bin/clang-format
|
||||
✅ clang-format-23
|
||||
clang-format version 23.1.0
|
||||
/nix/store/5nfddq7xgbp4zmj8jn7xk1pxyyn5wiwl-clang-format-23/bin/clang-format-23
|
||||
clang-format version 22.1.7
|
||||
/nix/store/s53p2m776iqaz7acgr5csgpsd18w15h7-clang-tools-22.1.7/bin/clang-format
|
||||
✅ clang-format-22
|
||||
clang-format version 22.1.7
|
||||
/nix/store/79v57mzcw8ng8kl7p961ck08ymhp31v7-clang-format-22/bin/clang-format-22
|
||||
✅ clang-tidy
|
||||
LLVM version 23.1.0
|
||||
/nix/store/jh9xhz6gwxyz3rfx7vy5g4j5d71w940r-clang-tools-23.1.0/bin/clang-tidy
|
||||
✅ clang-tidy-23
|
||||
LLVM version 23.1.0
|
||||
/nix/store/cawfgsx0vsslc1f007cavmy8md9drb1r-clang-tidy-23/bin/clang-tidy-23
|
||||
LLVM version 22.1.7
|
||||
/nix/store/s53p2m776iqaz7acgr5csgpsd18w15h7-clang-tools-22.1.7/bin/clang-tidy
|
||||
✅ clang-tidy-22
|
||||
LLVM version 22.1.7
|
||||
/nix/store/wdyd6cb9z1lyi37lbzvwldgcc7yv1n5c-clang-tidy-22/bin/clang-tidy-22
|
||||
✅ dot
|
||||
dot - graphviz version 15.1.1 (0)
|
||||
/nix/store/vz4zb8d1rfigzzdn3i0hd4kff28vk02l-graphviz-15.1.1/bin/dot
|
||||
dot - graphviz version 12.2.1 (0)
|
||||
/nix/store/58rrk4yzwpmyxvl8cqm18h3dhv24zf00-graphviz-12.2.1/bin/dot
|
||||
✅ doxygen
|
||||
1.17.0
|
||||
/nix/store/6q4z332wc9jnvad71wjj87lgjxidhgzl-doxygen-1.17.0/bin/doxygen
|
||||
1.16.1
|
||||
/nix/store/hq32kzwpl89wgr49iq0gmqn9r5n072zq-doxygen-1.16.1/bin/doxygen
|
||||
✅ gcovr
|
||||
gcovr 8.4
|
||||
/nix/store/v548fjz51k2nmr257vjnd0zp3bxpc2r1-python3.14-gcovr-8.4/bin/gcovr
|
||||
/nix/store/sml3xbbfhhlhk6h7jnlg19pdbx9b764b-python3.13-gcovr-8.4/bin/gcovr
|
||||
✅ gh
|
||||
gh version 2.102.0 (2026-09-30)
|
||||
/nix/store/vgg6gnq74h76b4r2ac2q9366f2s5qxwx-gh-2.102.0/bin/gh
|
||||
gh version 2.94.0 (nixpkgs)
|
||||
/nix/store/7hh2qi0gj2ifbxbl56cjzbiyfc379bji-gh-2.94.0/bin/gh
|
||||
✅ git-cliff
|
||||
git-cliff 2.14.2
|
||||
/nix/store/hrlgliq7l3fl2qrdlc197mvscs4n03rd-git-cliff-2.14.2/bin/git-cliff
|
||||
git-cliff 2.13.1
|
||||
/nix/store/bidn3pz53yd6qlg711917xx0q10hqmqv-git-cliff-2.13.1/bin/git-cliff
|
||||
✅ git-lfs
|
||||
git-lfs/3.8.0 (3.8.0; linux arm64; go 1.26.8)
|
||||
/nix/store/pa2g4xdvr4a73m6mv4cqs0pik1ka1xp5-git-lfs-3.8.0/bin/git-lfs
|
||||
git-lfs/3.7.1 (3.7.1; linux arm64; go 1.26.3)
|
||||
/nix/store/4rsklvkbac5bayy0zv12kxyvspi4sshd-git-lfs-3.7.1/bin/git-lfs
|
||||
✅ gpg
|
||||
gpg (GnuPG) 2.4.9
|
||||
/nix/store/3qc90b7qkxz7na3xnpd2qb8yvcq8zdp6-gnupg-2.4.9/bin/gpg
|
||||
/nix/store/ka4i8zz5ni3rzqnzcxbfvwr95fk8pn6q-gnupg-2.4.9/bin/gpg
|
||||
✅ pre-commit
|
||||
pre-commit 4.6.2
|
||||
/nix/store/5f3av75nc7n7xbf2hlvlagzpp2g8g562-pre-commit-4.6.2/bin/pre-commit
|
||||
pre-commit 4.5.1
|
||||
/nix/store/n981w6hjfar2l81kxbxs2wxl64vwa5kj-pre-commit-4.5.1/bin/pre-commit
|
||||
✅ run-clang-tidy
|
||||
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
|
||||
/nix/store/nlg35d9ccslsq5qny7raxyyyrxgk7vsq-run-clang-tidy/bin/run-clang-tidy
|
||||
✅ run-clang-tidy-23
|
||||
/nix/store/4z2fyklg78klallr7x9j02kz92hnxp4m-run-clang-tidy/bin/run-clang-tidy
|
||||
✅ run-clang-tidy-22
|
||||
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
|
||||
/nix/store/a50nf8hp8p8l8pgcf9fs0j25hij5acw3-run-clang-tidy-23/bin/run-clang-tidy-23
|
||||
/nix/store/f8m0p9ad40brp9ahy4i0h27kqjkya1j9-run-clang-tidy-22/bin/run-clang-tidy-22
|
||||
|
||||
Rust toolchain:
|
||||
✅ cargo
|
||||
cargo 1.97.1 (c980f4866 2026-06-30)
|
||||
/nix/store/nci0zxxj2fiq0dlkpqzbnqfh27wz4sq4-cargo-1.97.1-aarch64-unknown-linux-gnu/bin/cargo
|
||||
/nix/store/6hch2qrr86n2sa2m90lrpxrfxxwbkayl-cargo-1.97.1-aarch64-unknown-linux-gnu/bin/cargo
|
||||
✅ cargo-audit
|
||||
cargo-audit-audit 0.22.2
|
||||
/nix/store/zldaj03mfz9f21yiby5yymq7v8vqygd7-cargo-audit-0.22.2/bin/cargo-audit
|
||||
cargo-audit-audit 0.22.1
|
||||
/nix/store/9rxbrn9aa2r1z96186s69pc7vzizyfch-cargo-audit-0.22.1/bin/cargo-audit
|
||||
✅ cargo-llvm-cov
|
||||
cargo-llvm-cov 0.9.0
|
||||
/nix/store/iwpcfjah31fgn99ph32ajzz7i22j6al5-cargo-llvm-cov-0.9.0/bin/cargo-llvm-cov
|
||||
cargo-llvm-cov 0.8.5
|
||||
/nix/store/vwjsi159n89szrx4yh5pc3jlf2gp4fld-cargo-llvm-cov-0.8.5/bin/cargo-llvm-cov
|
||||
✅ cargo-nextest
|
||||
cargo-nextest 0.9.146
|
||||
/nix/store/p5svqr8x1rr7b1i8595pr8qafsr7s6fm-cargo-nextest-0.9.146/bin/cargo-nextest
|
||||
cargo-nextest 0.9.137
|
||||
/nix/store/qb6bcg2fjvm3r9s9j98nmffmf9xwh45s-cargo-nextest-0.9.137/bin/cargo-nextest
|
||||
✅ clippy-driver
|
||||
clippy 0.1.97 (8bab26f4f6 2026-07-14)
|
||||
/nix/store/ny64zks16ms5d70jk1qsiwsk0fr33ipp-rust-minimal-1.97.1/bin/clippy-driver
|
||||
/nix/store/a6p27cg6b8szfixfyvkssx6l0c345zw8-rust-minimal-1.97.1/bin/clippy-driver
|
||||
✅ rust-analyzer
|
||||
rust-analyzer 1.97.1 (8bab26f 2026-07-14)
|
||||
/nix/store/d9s5skhvi1qxj940mylwym2rjicnc2kq-rust-analyzer-preview-1.97.1-aarch64-unknown-linux-gnu/bin/rust-analyzer
|
||||
/nix/store/262830dlw2517lnagfx7i7agqgl4fmsd-rust-analyzer-preview-1.97.1-aarch64-unknown-linux-gnu/bin/rust-analyzer
|
||||
✅ rust-nightly
|
||||
rustc 1.101.0-nightly (282215592 2026-10-04)
|
||||
/nix/store/rbsf1gr6f9ikv2izlyh8im117w6hs7h5-rust-nightly/bin/rust-nightly
|
||||
rustc 1.99.0-nightly (87e5904f5 2026-07-20)
|
||||
/nix/store/c59pxk1yikdlf129qwyg4fplmxcrha0k-rust-nightly/bin/rust-nightly
|
||||
✅ rustc
|
||||
rustc 1.97.1 (8bab26f4f 2026-07-14)
|
||||
/nix/store/ny64zks16ms5d70jk1qsiwsk0fr33ipp-rust-minimal-1.97.1/bin/rustc
|
||||
/nix/store/a6p27cg6b8szfixfyvkssx6l0c345zw8-rust-minimal-1.97.1/bin/rustc
|
||||
✅ rustfmt
|
||||
rustfmt 1.9.0-stable (8bab26f4f6 2026-07-14)
|
||||
/nix/store/dplvgjikmv8909rk0dkqr90ryjg7xn0j-rustfmt-preview-1.97.1-aarch64-unknown-linux-gnu/bin/rustfmt
|
||||
/nix/store/nd8g81wv1smnvdpy4whpcyv2siwjmaan-rustfmt-preview-1.97.1-aarch64-unknown-linux-gnu/bin/rustfmt
|
||||
|
||||
GCC toolchain:
|
||||
✅ gcc
|
||||
gcc (GCC) 15.3.0
|
||||
/nix/store/g7z555pl99vnwif4jxa05nk1qdc33i1n-gcc-wrapper-15.3.0/bin/gcc
|
||||
gcc (GCC) 15.2.0
|
||||
/nix/store/rn6svg593xsmn8qcjzk8x9pa1i62c4kb-gcc-wrapper-15.2.0/bin/gcc
|
||||
✅ gcc-15
|
||||
gcc (GCC) 15.3.0
|
||||
/nix/store/vbdsfjk3j1xy5z329sl2d8vp6mq6x09i-gcc-15/bin/gcc-15
|
||||
gcc (GCC) 15.2.0
|
||||
/nix/store/h489d1rmjisfbxh5kmsb0a7c35j8qsdf-gcc-15/bin/gcc-15
|
||||
✅ g++
|
||||
g++ (GCC) 15.3.0
|
||||
/nix/store/g7z555pl99vnwif4jxa05nk1qdc33i1n-gcc-wrapper-15.3.0/bin/g++
|
||||
g++ (GCC) 15.2.0
|
||||
/nix/store/rn6svg593xsmn8qcjzk8x9pa1i62c4kb-gcc-wrapper-15.2.0/bin/g++
|
||||
✅ g++-15
|
||||
g++ (GCC) 15.3.0
|
||||
/nix/store/9ghl998ry4cxlsg6hnq5rn2iipnlkccm-g++-15/bin/g++-15
|
||||
g++ (GCC) 15.2.0
|
||||
/nix/store/9ywmhz8bmzknrn3pn84g46z8hj3vrmw5-g++-15/bin/g++-15
|
||||
✅ cpp
|
||||
cpp (GCC) 15.3.0
|
||||
/nix/store/g7z555pl99vnwif4jxa05nk1qdc33i1n-gcc-wrapper-15.3.0/bin/cpp
|
||||
cpp (GCC) 15.2.0
|
||||
/nix/store/rn6svg593xsmn8qcjzk8x9pa1i62c4kb-gcc-wrapper-15.2.0/bin/cpp
|
||||
✅ cpp-15
|
||||
cpp (GCC) 15.3.0
|
||||
/nix/store/wj0mv2fv2lhglvpjzhscqpbigkvik6br-cpp-15/bin/cpp-15
|
||||
cpp (GCC) 15.2.0
|
||||
/nix/store/vmjilh1b830qz9yh0a1jj5ads0jxizdk-cpp-15/bin/cpp-15
|
||||
✅ gcov
|
||||
gcov (GCC) 15.3.0
|
||||
/nix/store/mszfsj00qnv9ygqcqz3w02qzxxskhvlb-gcc-15.3.0/bin/gcov
|
||||
gcov (GCC) 15.2.0
|
||||
/nix/store/rmwf5hpi1y2m1wpnfvlxmrhksm4djk2j-gcc-15.2.0/bin/gcov
|
||||
|
||||
Mold:
|
||||
✅ mold
|
||||
mold 2.42.1 (compatible with GNU ld)
|
||||
/nix/store/gbq334xbibaz4gn184j7gs58m2spgwi7-mold-unwrapped-wrapper-2.42.1/bin/mold
|
||||
mold 2.41.0 (compatible with GNU ld)
|
||||
/nix/store/f5qh5a0bx1dslmnf5n5gx0s6aljbswq3-mold-unwrapped-wrapper-2.41.0/bin/mold
|
||||
|
||||
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
|
||||
|
||||
✅ All 54 checked tools are present and runnable.
|
||||
✅ All 53 checked tools are present and runnable.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (import ./packages.nix { inherit pkgs customGlibc; }) commonPackages;
|
||||
inherit (import ./packages.nix { inherit pkgs; }) commonPackages;
|
||||
|
||||
# Each forces something absent on the other platform, so both stay lazy.
|
||||
linux = import ./linux.nix { inherit pkgs customGlibc; };
|
||||
|
||||
@@ -31,9 +31,6 @@ let
|
||||
};
|
||||
customGccGcov = if pkgs.stdenv.hostPlatform.isLinux then linux.gcov else plainGcov;
|
||||
|
||||
# commonPackages whose clang tools parse with the custom toolchain's headers.
|
||||
customCommonPackages = (import ./packages.nix { inherit pkgs customGlibc; }).commonPackages;
|
||||
|
||||
# Whole directory: init.sh locates the profiles relative to itself.
|
||||
conanDir = ../conan;
|
||||
|
||||
@@ -89,11 +86,11 @@ let
|
||||
version ? null,
|
||||
versionedTools ? [ ],
|
||||
extraPackages ? [ ],
|
||||
# The stock nixpkgs toolchain: warn that it doesn't match CI, keep the
|
||||
# clang tools off the custom toolchain, and opt out of PatchNixBinary.cmake
|
||||
# retargeting binaries to the system loader (the plain toolchain links a
|
||||
# newer glibc, so it must not be patched).
|
||||
plain ? false,
|
||||
warningHook ? "",
|
||||
# Opt out of PatchNixBinary.cmake retargeting binaries to the system
|
||||
# loader. The plain toolchain links a newer glibc, so it must not be
|
||||
# patched; the custom toolchain patches by default.
|
||||
noPatchNixBinary ? false,
|
||||
}:
|
||||
let
|
||||
compilerVersionHook =
|
||||
@@ -113,8 +110,7 @@ let
|
||||
in
|
||||
(pkgs.mkShell.override { inherit stdenv; }) (
|
||||
{
|
||||
packages =
|
||||
(if plain then commonPackages else customCommonPackages) ++ versionedLinks ++ extraPackages;
|
||||
packages = commonPackages ++ versionedLinks ++ extraPackages;
|
||||
# Marks a managed dev shell, so the build (XrplSanity.cmake) can tell an
|
||||
# intentional Nix toolchain from one leaked into a bare shell.
|
||||
XRPL_DEVSHELL = shellName;
|
||||
@@ -123,10 +119,10 @@ let
|
||||
${compilerVersionHook}
|
||||
${darwinLibresolvHook}
|
||||
${conanHook}
|
||||
${pkgs.lib.optionalString plain plainWarningHook}
|
||||
${warningHook}
|
||||
'';
|
||||
}
|
||||
// pkgs.lib.optionalAttrs plain { XRPLD_NO_PATCH_NIX_BINARY = "1"; }
|
||||
// pkgs.lib.optionalAttrs noPatchNixBinary { XRPLD_NO_PATCH_NIX_BINARY = "1"; }
|
||||
);
|
||||
in
|
||||
rec {
|
||||
@@ -184,7 +180,8 @@ rec {
|
||||
version = gccVersion;
|
||||
versionedTools = gccVersionedTools;
|
||||
extraPackages = [ plainGcov ];
|
||||
plain = true;
|
||||
warningHook = plainWarningHook;
|
||||
noPatchNixBinary = true;
|
||||
};
|
||||
|
||||
clang-plain = makeShell {
|
||||
@@ -193,6 +190,7 @@ rec {
|
||||
compilerName = "clang";
|
||||
version = llvmVersion;
|
||||
versionedTools = clangVersionedTools;
|
||||
plain = true;
|
||||
warningHook = plainWarningHook;
|
||||
noPatchNixBinary = true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -146,7 +146,6 @@ in
|
||||
})
|
||||
];
|
||||
|
||||
clang = customClang;
|
||||
gccStdenv = customStdenv;
|
||||
clangStdenv = pkgs.stdenvAdapters.overrideCC pkgs.stdenv customClang;
|
||||
gcov = customGcov;
|
||||
|
||||
@@ -1,28 +1,14 @@
|
||||
{
|
||||
pkgs,
|
||||
# With the custom glibc, the clang tools (clang-tidy, ...) parse code with the
|
||||
# Linux custom toolchain's headers, i.e. the same glibc and libstdc++ as the
|
||||
# build. Without it, they use the nixpkgs default compiler's.
|
||||
customGlibc ? null,
|
||||
}:
|
||||
{ pkgs }:
|
||||
let
|
||||
# Compiler versions used across the dev shell and the CI environment.
|
||||
# Docs link here and scripts read the version off the tools;
|
||||
# only the clang-format rev in .pre-commit-config.yaml
|
||||
# has to be bumped alongside llvmVersion.
|
||||
gccVersion = 15;
|
||||
llvmVersion = 23;
|
||||
llvmVersion = 22;
|
||||
|
||||
gccPackage = pkgs."gcc${toString gccVersion}";
|
||||
llvmPackages = pkgs."llvmPackages_${toString llvmVersion}";
|
||||
|
||||
# Bound explicitly so it tracks llvmPackages above, not the `with pkgs` default.
|
||||
# isLinux first: darwin must not evaluate the custom glibc.
|
||||
clangTools = llvmPackages.clang-tools.override (
|
||||
pkgs.lib.optionalAttrs (pkgs.stdenv.hostPlatform.isLinux && customGlibc != null) {
|
||||
inherit (import ./linux.nix { inherit pkgs customGlibc; }) clang;
|
||||
}
|
||||
);
|
||||
clangTools = llvmPackages.clang-tools;
|
||||
|
||||
# In LLVM 22, run-clang-tidy.py moved from share/clang/ to bin/, so nixpkgs
|
||||
# clang-tools no longer links it. Wrap it manually.
|
||||
@@ -30,21 +16,6 @@ let
|
||||
exec ${pkgs.python3}/bin/python3 ${llvmPackages.clang-unwrapped}/bin/run-clang-tidy "$@"
|
||||
'';
|
||||
|
||||
# Conan 2.33 is the first release whose settings.yml accepts clang 23.
|
||||
# TODO: drop once nixpkgs ships it.
|
||||
conan = pkgs.conan.overridePythonAttrs (old: {
|
||||
version = "2.33.0";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "conan-io";
|
||||
repo = "conan";
|
||||
tag = "2.33.0";
|
||||
hash = "sha256-FDJjesqvPiAUAEjeqQt088Vnet/KXHbUyEPytP9MyG4=";
|
||||
};
|
||||
dependencies = old.dependencies ++ [ pkgs.python3Packages.truststore ];
|
||||
# The upstream test suite takes long and needs network access.
|
||||
doCheck = false;
|
||||
});
|
||||
|
||||
rust = import ./rust.nix { inherit pkgs; };
|
||||
|
||||
# Nix wraps its toolchain so that binaries are exposed only under unsuffixed
|
||||
@@ -54,11 +25,10 @@ let
|
||||
# - Conan's Boost recipe looks up `g++-<major>` before plain `g++`.
|
||||
# - bin/pre-commit/clang_tidy_check.py looks up `run-clang-tidy-<v>` and
|
||||
# `clang-apply-replacements-<v>` before the unsuffixed names.
|
||||
# On a host that also has the matching system binary
|
||||
# (e.g. Ubuntu's `/usr/bin/g++-<v>` or `clang-tidy-<v>`),
|
||||
# the probe escapes Nix and mixes a system tool into the Nix environment.
|
||||
# Generate version-suffixed symlinks next to a package's tools
|
||||
# so those probes resolve to the Nix ones.
|
||||
# On a host that also has the matching system binary (e.g. Ubuntu's
|
||||
# `/usr/bin/g++-15` or `clang-tidy-22`) the probe escapes Nix and mixes a
|
||||
# system tool into the Nix environment. Generate version-suffixed symlinks
|
||||
# next to a package's tools so those probes resolve to the Nix ones.
|
||||
#
|
||||
# Compiler links must point at whichever compiler is active in a given
|
||||
# environment (the plain stdenv compiler in the dev shell, the custom-glibc
|
||||
@@ -142,7 +112,6 @@ in
|
||||
gnumake
|
||||
gnupg # needed for signing commits & codecov/codecov-action
|
||||
graphviz
|
||||
jq
|
||||
less # needed for git diff
|
||||
mold
|
||||
nettools # provides netstat, used to debug failures in CI
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
#include <xrpl/basics/CountedObject.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
CountedObjects&
|
||||
CountedObjects::getInstance() noexcept
|
||||
{
|
||||
static CountedObjects kInstance;
|
||||
|
||||
return kInstance;
|
||||
}
|
||||
|
||||
CountedObjects::CountedObjects() noexcept : count_(0), head_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
CountedObjects::List
|
||||
CountedObjects::getCounts(int minimumThreshold) const
|
||||
{
|
||||
List counts;
|
||||
|
||||
// When other operations are concurrent, the count
|
||||
// might be temporarily less than the actual count.
|
||||
counts.reserve(count_.load());
|
||||
|
||||
for (auto* ctr = head_.load(); ctr != nullptr; ctr = ctr->getNext())
|
||||
{
|
||||
if (ctr->getCount() >= minimumThreshold)
|
||||
counts.emplace_back(ctr->getName(), ctr->getCount());
|
||||
}
|
||||
|
||||
std::ranges::sort(counts);
|
||||
|
||||
return counts;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -1,6 +1,5 @@
|
||||
#include <xrpl/basics/StringUtilities.h>
|
||||
|
||||
#include <xrpl/basics/Blob.h>
|
||||
#include <xrpl/beast/core/LexicalCast.h>
|
||||
#include <xrpl/beast/net/IPEndpoint.h>
|
||||
|
||||
@@ -20,7 +19,7 @@
|
||||
namespace xrpl {
|
||||
|
||||
std::string
|
||||
sqlBlobLiteral(Blob const& blob)
|
||||
sqlBlobLiteral(Slice blob)
|
||||
{
|
||||
std::string j;
|
||||
|
||||
|
||||
@@ -33,13 +33,13 @@ AcceptedLedgerTx::AcceptedLedgerTx(
|
||||
|
||||
Serializer s;
|
||||
met->add(s);
|
||||
rawMeta_ = std::move(s.modData());
|
||||
rawMeta_ = s.takeData();
|
||||
|
||||
json_ = json::ValueType::Object;
|
||||
json_[jss::transaction] = txn_->getJson(JsonOptions::Values::None);
|
||||
|
||||
json_[jss::meta] = meta_.getJson(JsonOptions::Values::None);
|
||||
json_[jss::raw_meta] = strHex(rawMeta_);
|
||||
json_[jss::raw_meta] = strHex(makeSlice(rawMeta_));
|
||||
|
||||
json_[jss::result] = transHuman(meta_.getResultTER());
|
||||
|
||||
@@ -74,7 +74,7 @@ std::string
|
||||
AcceptedLedgerTx::getEscMeta() const
|
||||
{
|
||||
XRPL_ASSERT(!rawMeta_.empty(), "xrpl::AcceptedLedgerTx::getEscMeta : metadata is set");
|
||||
return sqlBlobLiteral(rawMeta_);
|
||||
return sqlBlobLiteral(makeSlice(rawMeta_));
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -80,10 +80,10 @@ BookDirs::const_iterator::operator++()
|
||||
XRPL_ASSERT(index_ != kZero, "xrpl::BookDirs::const_iterator::operator++ : nonzero index");
|
||||
if (!cdirNext(*view_, curKey_, sle_, entry_, index_))
|
||||
{
|
||||
if (index_ == 0)
|
||||
if (index_ == kZero)
|
||||
curKey_ = view_->succ(++curKey_, nextQuality_).value_or(kZero);
|
||||
|
||||
if (index_ != 0 || curKey_ == kZero)
|
||||
if (index_ != kZero || curKey_ == kZero)
|
||||
{
|
||||
curKey_ = key_;
|
||||
entry_ = 0;
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <xrpl/ledger/LedgerTiming.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/FeeSettingsEntry.h>
|
||||
#include <xrpl/ledger/entries/NegativeUNLEntry.h>
|
||||
#include <xrpl/nodestore/NodeObject.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Fees.h>
|
||||
@@ -263,7 +262,7 @@ Ledger::Ledger(Ledger const& prevLedger, NetClock::time_point closeTime)
|
||||
{
|
||||
header_.seq = prevLedger.header_.seq + 1;
|
||||
header_.parentCloseTime = prevLedger.header_.closeTime;
|
||||
header_.hash = prevLedger.header().hash + UInt256(1);
|
||||
header_.hash = prevLedger.header().hash.next();
|
||||
header_.drops = prevLedger.header().drops;
|
||||
header_.closeTimeResolution = prevLedger.header_.closeTimeResolution;
|
||||
header_.parentHash = prevLedger.header().hash;
|
||||
@@ -364,17 +363,13 @@ Ledger::deserializeTx(SHAMapItem const& item)
|
||||
std::pair<std::shared_ptr<STTx const>, std::shared_ptr<STObject const>>
|
||||
Ledger::deserializeTxPlusMeta(SHAMapItem const& item)
|
||||
{
|
||||
std::pair<std::shared_ptr<STTx const>, std::shared_ptr<STObject const>> result;
|
||||
SerialIter sit(item.slice());
|
||||
{
|
||||
SerialIter s(sit.getSlice(sit.getVLDataLength()));
|
||||
result.first = std::make_shared<STTx const>(s);
|
||||
}
|
||||
{
|
||||
SerialIter s(sit.getSlice(sit.getVLDataLength()));
|
||||
result.second = std::make_shared<STObject const>(s, sfMetadata);
|
||||
}
|
||||
return result;
|
||||
|
||||
SerialIter txSit(sit.getVL());
|
||||
SerialIter metaSit(sit.getVL());
|
||||
|
||||
return {
|
||||
std::make_shared<STTx const>(txSit), std::make_shared<STObject const>(metaSit, sfMetadata)};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -534,9 +529,9 @@ Ledger::rawTxInsert(
|
||||
XRPL_ASSERT(metaData, "xrpl::Ledger::rawTxInsert : non-null metadata input");
|
||||
|
||||
// low-level - just add to table
|
||||
Serializer s(txn->getDataLength() + metaData->getDataLength() + 16);
|
||||
s.addVL(txn->peekData());
|
||||
s.addVL(metaData->peekData());
|
||||
Serializer s(txn->size() + metaData->size() + 16);
|
||||
s.addVL(txn->slice());
|
||||
s.addVL(metaData->slice());
|
||||
if (!txMap_.addGiveItem(SHAMapNodeType::TnTransactionMd, makeShamapitem(key, s.slice())))
|
||||
logicError("duplicate_tx: " + to_string(key));
|
||||
}
|
||||
@@ -641,7 +636,7 @@ HashSet<PublicKey>
|
||||
Ledger::negativeUNL() const
|
||||
{
|
||||
HashSet<PublicKey> negUnl;
|
||||
if (auto const sle = NegativeUNLEntryR(*this); sle && sle->isFieldPresent(sfDisabledValidators))
|
||||
if (auto sle = read(keylet::negativeUNL()); sle && sle->isFieldPresent(sfDisabledValidators))
|
||||
{
|
||||
auto const& nUnlData = sle->getFieldArray(sfDisabledValidators);
|
||||
for (auto const& n : nUnlData)
|
||||
@@ -665,7 +660,7 @@ Ledger::negativeUNL() const
|
||||
std::optional<PublicKey>
|
||||
Ledger::validatorToDisable() const
|
||||
{
|
||||
if (auto const sle = NegativeUNLEntryR(*this); sle && sle->isFieldPresent(sfValidatorToDisable))
|
||||
if (auto sle = read(keylet::negativeUNL()); sle && sle->isFieldPresent(sfValidatorToDisable))
|
||||
{
|
||||
auto d = sle->getFieldVL(sfValidatorToDisable);
|
||||
auto s = makeSlice(d);
|
||||
@@ -679,8 +674,7 @@ Ledger::validatorToDisable() const
|
||||
std::optional<PublicKey>
|
||||
Ledger::validatorToReEnable() const
|
||||
{
|
||||
if (auto const sle = NegativeUNLEntryR(*this);
|
||||
sle && sle->isFieldPresent(sfValidatorToReEnable))
|
||||
if (auto sle = read(keylet::negativeUNL()); sle && sle->isFieldPresent(sfValidatorToReEnable))
|
||||
{
|
||||
auto d = sle->getFieldVL(sfValidatorToReEnable);
|
||||
auto s = makeSlice(d);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/hash/uhash.h>
|
||||
#include <xrpl/ledger/detail/ReadViewFwdRange.h>
|
||||
#include <xrpl/ledger/entries/AmendmentsEntry.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/Rules.h>
|
||||
@@ -73,8 +72,9 @@ makeRulesGivenLedger(
|
||||
std::optional const digest = ledger.digest(k.key);
|
||||
if (digest)
|
||||
{
|
||||
if (AmendmentsEntryR const entry(k, ledger); entry)
|
||||
return Rules(presets, digest, entry->getFieldV256(sfAmendments));
|
||||
auto const sle = ledger.read(k);
|
||||
if (sle)
|
||||
return Rules(presets, digest, sle->getFieldV256(sfAmendments));
|
||||
}
|
||||
return Rules(presets);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/AmendmentsEntry.h>
|
||||
#include <xrpl/ledger/entries/LedgerHashesEntry.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||
@@ -310,13 +309,40 @@ areCompatible(
|
||||
std::set<UInt256>
|
||||
getEnabledAmendments(ReadView const& view)
|
||||
{
|
||||
return AmendmentsEntryR(view).enabledAmendments();
|
||||
std::set<UInt256> amendments;
|
||||
|
||||
if (auto const sle = view.read(keylet::amendments()))
|
||||
{
|
||||
if (sle->isFieldPresent(sfAmendments))
|
||||
{
|
||||
auto const& v = sle->getFieldV256(sfAmendments);
|
||||
amendments.insert(v.begin(), v.end());
|
||||
}
|
||||
}
|
||||
|
||||
return amendments;
|
||||
}
|
||||
|
||||
MajorityAmendmentsT
|
||||
getMajorityAmendments(ReadView const& view)
|
||||
{
|
||||
return AmendmentsEntryR(view).majorityAmendments();
|
||||
MajorityAmendmentsT ret;
|
||||
|
||||
if (auto const sle = view.read(keylet::amendments()))
|
||||
{
|
||||
if (sle->isFieldPresent(sfMajorities))
|
||||
{
|
||||
using Tp = NetClock::time_point;
|
||||
using D = Tp::duration;
|
||||
|
||||
auto const majorities = sle->getFieldArray(sfMajorities);
|
||||
|
||||
for (auto const& m : majorities)
|
||||
ret[m.getFieldH256(sfAmendment)] = Tp(D(m.getFieldU32(sfCloseTime)));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::optional<UInt256>
|
||||
|
||||
@@ -506,7 +506,7 @@ pseudoAccountAddress(ReadView const& view, UInt256 const& pseudoOwnerKey)
|
||||
RipeshaHasher rsh;
|
||||
auto const hash = sha512Half(i, view.header().parentHash, pseudoOwnerKey);
|
||||
rsh(hash.data(), hash.size());
|
||||
AccountID const ret = AccountID::fromRaw(static_cast<RipeshaHasher::result_type>(rsh));
|
||||
AccountID const ret{static_cast<RipeshaHasher::result_type>(rsh)};
|
||||
if (!view.read(keylet::account(ret)))
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -18,10 +18,8 @@
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/MPTAmount.h>
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/Quality.h>
|
||||
#include <xrpl/protocol/Rate.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
@@ -1339,26 +1337,9 @@ directSendNoLimitMPT(
|
||||
}
|
||||
|
||||
// Sending 3rd party MPTs: transit.
|
||||
if (waiveFee == WaiveTransferFee::Yes)
|
||||
{
|
||||
saActual = saAmount;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const rate = transferRate(view, saAmount.get<MPTIssue>().getMptID());
|
||||
if (view.rules().enabled(fixCleanup3_5_0))
|
||||
{
|
||||
// Number math loses precision on large MPT amounts, which can
|
||||
// overcharge the sender. MPTs are integral, so compute the cost
|
||||
// exactly and round it up, matching the payment engine.
|
||||
auto const cost = mulRatio(saAmount.mpt(), rate.value, QUALITY_ONE, true);
|
||||
saActual = STAmount(saAmount.asset(), cost.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
saActual = multiply(saAmount, rate);
|
||||
}
|
||||
}
|
||||
saActual = (waiveFee == WaiveTransferFee::Yes)
|
||||
? saAmount
|
||||
: multiply(saAmount, transferRate(view, saAmount.get<MPTIssue>().getMptID()));
|
||||
|
||||
JLOG(j.debug()) << "directSendNoLimitMPT> " << to_string(uSenderID) << " - > "
|
||||
<< to_string(uReceiverID) << " : deliver=" << saAmount.getFullText()
|
||||
@@ -1467,23 +1448,9 @@ directSendNoLimitMultiMPT(
|
||||
}
|
||||
|
||||
// Sending 3rd party MPTs: transit.
|
||||
STAmount actualSend = amount;
|
||||
if (waiveFee != WaiveTransferFee::Yes)
|
||||
{
|
||||
auto const rate = transferRate(view, amount.get<MPTIssue>().getMptID());
|
||||
if (view.rules().enabled(fixCleanup3_5_0))
|
||||
{
|
||||
// Number math loses precision on large MPT amounts, which can
|
||||
// overcharge the sender. MPTs are integral, so compute the
|
||||
// cost exactly and round it up, matching the payment engine.
|
||||
auto const cost = mulRatio(amount.mpt(), rate.value, QUALITY_ONE, true);
|
||||
actualSend = STAmount(amount.asset(), cost.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
actualSend = multiply(amount, rate);
|
||||
}
|
||||
}
|
||||
STAmount const actualSend = (waiveFee == WaiveTransferFee::Yes)
|
||||
? amount
|
||||
: multiply(amount, transferRate(view, amount.get<MPTIssue>().getMptID()));
|
||||
actual += actualSend;
|
||||
takeFromSender += actualSend;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <xrpl/nodestore/detail/DecodedBlob.h>
|
||||
|
||||
#include <xrpl/basics/Blob.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/nodestore/NodeObject.h>
|
||||
@@ -12,8 +11,13 @@
|
||||
|
||||
namespace xrpl::node_store {
|
||||
|
||||
DecodedBlob::DecodedBlob(void const* key, void const* value, int valueBytes) : key_(key)
|
||||
DecodedBlob::DecodedBlob(std::optional<UInt256> key, void const* value, int valueBytes)
|
||||
{
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
key_ = key.value();
|
||||
|
||||
/* Data format:
|
||||
|
||||
Bytes
|
||||
@@ -63,7 +67,7 @@ DecodedBlob::createObject()
|
||||
{
|
||||
Blob data(objectData_, objectData_ + dataBytes_);
|
||||
|
||||
object = NodeObject::createObject(objectType_, std::move(data), UInt256::fromVoid(key_));
|
||||
object = NodeObject::createObject(objectType_, std::move(data), key_);
|
||||
}
|
||||
|
||||
return object;
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
@@ -216,7 +217,7 @@ public:
|
||||
[&hash, pno, &status](void const* data, std::size_t size) {
|
||||
nudb::detail::buffer bf;
|
||||
auto const result = nodeobjectDecompress(data, size, bf);
|
||||
DecodedBlob decoded(hash.data(), result.first, result.second);
|
||||
DecodedBlob decoded(hash, result.first, result.second);
|
||||
if (!decoded.wasOk())
|
||||
{
|
||||
status = Status::DataCorrupt;
|
||||
@@ -240,7 +241,7 @@ public:
|
||||
nudb::error_code ec;
|
||||
nudb::detail::buffer bf;
|
||||
auto const result = nodeobjectCompress(e.getData(), e.getSize(), bf);
|
||||
db.insert(e.getKey(), result.first, result.second, ec);
|
||||
db.insert(e.getKey().data(), result.first, result.second, ec);
|
||||
if (ec && ec != nudb::error::key_exists)
|
||||
Throw<nudb::system_error>(ec);
|
||||
}
|
||||
@@ -288,14 +289,25 @@ public:
|
||||
Throw<nudb::system_error>(ec);
|
||||
nudb::visit(
|
||||
dp,
|
||||
[&](void const* key,
|
||||
[&](void const* keyData,
|
||||
std::size_t keyBytes,
|
||||
void const* data,
|
||||
std::size_t size,
|
||||
nudb::error_code&) {
|
||||
auto key = uint256::fromRaw(
|
||||
std::span{static_cast<unsigned char const*>(keyData), keyBytes});
|
||||
|
||||
if (!key) [[unlikely]]
|
||||
{
|
||||
ec = make_error_code(nudb::error::invalid_key_size);
|
||||
return;
|
||||
}
|
||||
|
||||
nudb::detail::buffer bf;
|
||||
auto const result = nodeobjectDecompress(data, size, bf);
|
||||
|
||||
DecodedBlob decoded(key, result.first, result.second);
|
||||
|
||||
if (!decoded.wasOk())
|
||||
{
|
||||
ec = make_error_code(nudb::error::missing_value);
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <format>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
@@ -111,6 +112,9 @@ public:
|
||||
if (!getIfExists(keyValues, Keys::kPath, name))
|
||||
Throw<std::runtime_error>("Missing path in RocksDBFactory backend");
|
||||
|
||||
if (keyBytes != uint256::size())
|
||||
Throw<std::runtime_error>("Incorrect key size: expected 32 bytes");
|
||||
|
||||
rocksdb::BlockBasedTableOptions tableOptions;
|
||||
options.env = env;
|
||||
|
||||
@@ -292,7 +296,7 @@ public:
|
||||
|
||||
if (getStatus.ok())
|
||||
{
|
||||
DecodedBlob decoded(hash.data(), string.data(), string.size());
|
||||
DecodedBlob decoded(hash, string.data(), string.size());
|
||||
|
||||
if (decoded.wasOk())
|
||||
{
|
||||
@@ -317,8 +321,8 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
status = static_cast<Status>(
|
||||
static_cast<int>(Status::CustomCode) + unsafeCast<int>(getStatus.code()));
|
||||
status = checkedCast<Status>(
|
||||
safeCast<int>(Status::CustomCode) + safeCast<int>(getStatus.code()));
|
||||
|
||||
JLOG(journal.error()) << getStatus.ToString();
|
||||
}
|
||||
@@ -347,7 +351,7 @@ public:
|
||||
EncodedBlob const encoded(e);
|
||||
|
||||
wb.Put(
|
||||
rocksdb::Slice(reinterpret_cast<char const*>(encoded.getKey()), keyBytes),
|
||||
rocksdb::Slice(reinterpret_cast<char const*>(encoded.getKey().data()), keyBytes),
|
||||
rocksdb::Slice(
|
||||
reinterpret_cast<char const*>(encoded.getData()), encoded.getSize()));
|
||||
}
|
||||
@@ -375,9 +379,12 @@ public:
|
||||
|
||||
for (it->SeekToFirst(); it->Valid(); it->Next())
|
||||
{
|
||||
if (it->key().size() == keyBytes)
|
||||
if (it->key().size() == keyBytes && it->key().size() == uint256::size())
|
||||
{
|
||||
DecodedBlob decoded(it->key().data(), it->value().data(), it->value().size());
|
||||
DecodedBlob decoded(
|
||||
uint256::fromRaw(std::span{it->key().data(), it->key().size()}),
|
||||
it->value().data(),
|
||||
it->value().size());
|
||||
|
||||
if (decoded.wasOk())
|
||||
{
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <xrpl/protocol/digest.h>
|
||||
#include <xrpl/protocol/tokens.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
@@ -19,95 +21,143 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace detail {
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Caches the base58 representations of AccountIDs
|
||||
/** If true, we implement a cache for account ID lookups.
|
||||
|
||||
This is generally a good idea and can improve performance, especially
|
||||
when serving client requests.
|
||||
|
||||
The cache may generate warnings under some sanitizers; if you want to
|
||||
disable caching, set this variable to false.
|
||||
*/
|
||||
class AccountIdCache
|
||||
constexpr bool cacheAccountIDs = true;
|
||||
|
||||
/** Represents a cached entry for the given AccountID.
|
||||
|
||||
We keep the size and alignment of the structure at 64 bytes to
|
||||
make sure it fits within a cache line and avoid false sharing.
|
||||
*/
|
||||
struct alignas(64) CachedAccountID
|
||||
{
|
||||
private:
|
||||
struct CachedAccountID
|
||||
{
|
||||
AccountID id;
|
||||
char encoding[40] = {0};
|
||||
};
|
||||
/** The sequence lock for the entry.
|
||||
|
||||
// The actual cache
|
||||
std::vector<CachedAccountID> cache_;
|
||||
An even value means that the data is stable, whereas an odd
|
||||
value indicates the data is being actively modified.
|
||||
|
||||
// We use a hash function designed to resist algorithmic complexity attacks
|
||||
HardenedHash<> hasher_;
|
||||
We use a 32-bit value to ensure that the counter will never
|
||||
return to an observed value during a read window.
|
||||
*/
|
||||
std::atomic<std::uint32_t> seq{0};
|
||||
|
||||
// 64 spinlocks, packed into a single 64-bit value
|
||||
std::atomic<std::uint64_t> locks_ = 0;
|
||||
/** The account id. */
|
||||
AccountID id{};
|
||||
|
||||
public:
|
||||
AccountIdCache(std::size_t count) : cache_(count)
|
||||
{
|
||||
// This is non-binding, but we try to avoid wasting memory that
|
||||
// is caused by overallocation.
|
||||
cache_.shrink_to_fit();
|
||||
}
|
||||
/** The length of the cached encoding.
|
||||
|
||||
std::string
|
||||
toBase58(AccountID const& id)
|
||||
{
|
||||
auto const index = hasher_(id) % cache_.size();
|
||||
This field disambiguates collisions between ACCOUNT_ZERO and
|
||||
never-written-to slots, since they would otherwise share the
|
||||
same encoded bits.
|
||||
*/
|
||||
std::uint8_t len = 0;
|
||||
|
||||
PackedSpinlock sl(locks_, index % 64);
|
||||
|
||||
{
|
||||
std::scoped_lock const lock(sl);
|
||||
|
||||
// The check against the first character of the encoding ensures
|
||||
// that we don't mishandle the case of the all-zero account:
|
||||
if (cache_[index].encoding[0] != 0 && cache_[index].id == id)
|
||||
return cache_[index].encoding;
|
||||
}
|
||||
|
||||
auto ret = encodeBase58Token(TokenType::AccountID, id.data(), id.size());
|
||||
|
||||
XRPL_ASSERT(ret.size() <= 38, "xrpl::detail::AccountIdCache : maximum result size");
|
||||
|
||||
{
|
||||
std::scoped_lock const lock(sl);
|
||||
cache_[index].id = id;
|
||||
std::strcpy(cache_[index].encoding, ret.c_str());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/** The actual string encoding. */
|
||||
char encoding[39] = {0};
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
static_assert(sizeof(CachedAccountID) == 64 && alignof(CachedAccountID) == 64);
|
||||
|
||||
static std::unique_ptr<detail::AccountIdCache> gAccountIdCache;
|
||||
// The actual cache to use: a simple, direct-mapped, best-effort construct.
|
||||
//
|
||||
// We do not use a hardened hash for this because an AccountID is already
|
||||
// just cryptographically generated (i.e. uniformly distributed) bits and
|
||||
// there is no amplification, since collisions do not carry an additional
|
||||
// cost.
|
||||
//
|
||||
// The size is a "nice" power of 2 because it makes the calculation of an
|
||||
// index easier.
|
||||
constinit std::array<CachedAccountID, 65536> gAccountIdCache{};
|
||||
|
||||
void
|
||||
initAccountIdCache(std::size_t count)
|
||||
{
|
||||
if (!gAccountIdCache && count != 0)
|
||||
gAccountIdCache = std::make_unique<detail::AccountIdCache>(count);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string
|
||||
toBase58(AccountID const& v)
|
||||
{
|
||||
if (gAccountIdCache)
|
||||
return gAccountIdCache->toBase58(v);
|
||||
// Since the input bits are generated by a cryptographically secure
|
||||
// hash construct, we can just pick any subset of them, no muss, no
|
||||
// fuss.
|
||||
auto const index = [&v]() -> std::uint16_t {
|
||||
auto const data = v.data();
|
||||
|
||||
return encodeBase58Token(TokenType::AccountID, v.data(), v.size());
|
||||
return static_cast<std::uint16_t>(data[0]) | (static_cast<std::uint16_t>(data[1]) << 8);
|
||||
}();
|
||||
|
||||
if constexpr (cacheAccountIDs)
|
||||
{
|
||||
auto& slot = gAccountIdCache[index];
|
||||
|
||||
// This is the optimistic, store-free read path: a collision with a
|
||||
// concurrent writer will be detected because the seq recheck fails
|
||||
// and we fall through to the slow path.
|
||||
//
|
||||
// These unsynchronized reads of the slot fields are, formally, data
|
||||
// races and, technically speaking, result in undefined behavior and
|
||||
// a tool like TSAN might flag them. These should not have an impact
|
||||
// on the correctness of the returned data: the sequence lock checks
|
||||
// ensure we discard any data that was in flux.
|
||||
if (auto const s0 = slot.seq.load(std::memory_order::acquire);
|
||||
(s0 & 1) == 0 && slot.len != 0 && slot.id == v)
|
||||
{
|
||||
char buf[38];
|
||||
auto const len = std::min<std::size_t>(slot.len, sizeof(buf));
|
||||
std::memcpy(buf, slot.encoding, len);
|
||||
|
||||
// Prevents the loads above from sinking below the recheck; the
|
||||
// acquire on s0 constrains later operations, not earlier ones.
|
||||
std::atomic_thread_fence(std::memory_order::acquire);
|
||||
|
||||
// Everything read from the slot — the gates above and the bytes in
|
||||
// buf — precedes this recheck and is validated by it. No slot access
|
||||
// may follow it.
|
||||
if (slot.seq.load(std::memory_order::relaxed) == s0)
|
||||
return std::string(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
auto ret = encodeBase58Token(TokenType::AccountID, v.data(), v.size());
|
||||
|
||||
XRPL_ASSERT(!ret.empty() && ret.size() <= 38, "xrpl::toBase58 : maximum result size");
|
||||
|
||||
if constexpr (cacheAccountIDs)
|
||||
{
|
||||
auto& slot = gAccountIdCache[index];
|
||||
|
||||
// The CAS to an odd value excludes other writers; if it fails, another
|
||||
// thread wrote or is writing into this slot. That is not a problem: we
|
||||
// just don't store our result into the cache this time.
|
||||
if (auto s0 = slot.seq.load(std::memory_order::relaxed); (s0 & 1) == 0 &&
|
||||
slot.seq.compare_exchange_strong(s0, s0 + 1, std::memory_order::acquire))
|
||||
{
|
||||
slot.id = v;
|
||||
slot.len = static_cast<std::uint8_t>(ret.size());
|
||||
std::copy_n(ret.data(), ret.size(), slot.encoding);
|
||||
|
||||
// The acquire on the CAS above keeps the writes from becoming visible
|
||||
// before the seqlock transitions to an odd value, which means readers
|
||||
// can detect an in-progress write. This release publishes them before
|
||||
// the seqlock transitions to an even value.
|
||||
slot.seq.store(s0 + 2, std::memory_order::release);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::optional<AccountID>
|
||||
parseBase58(std::string const& s)
|
||||
{
|
||||
auto const result = decodeBase58Token(s, TokenType::AccountID);
|
||||
if (result.size() != AccountID::kBytes)
|
||||
return std::nullopt;
|
||||
return AccountID::fromRaw(result);
|
||||
return AccountID::fromRaw(decodeBase58Token(s, TokenType::AccountID));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -148,25 +198,9 @@ parseBase58(std::string const& s)
|
||||
AccountID
|
||||
calcAccountID(PublicKey const& pk)
|
||||
{
|
||||
static_assert(AccountID::kBytes == sizeof(RipeshaHasher::result_type));
|
||||
|
||||
RipeshaHasher rsh;
|
||||
rsh(pk.data(), pk.size());
|
||||
return AccountID::fromRaw(static_cast<RipeshaHasher::result_type>(rsh));
|
||||
}
|
||||
|
||||
AccountID const&
|
||||
xrpAccount()
|
||||
{
|
||||
static AccountID const kAccount(beast::kZero);
|
||||
return kAccount;
|
||||
}
|
||||
|
||||
AccountID const&
|
||||
noAccount()
|
||||
{
|
||||
static AccountID const kAccount(1);
|
||||
return kAccount;
|
||||
return AccountID{static_cast<RipeshaHasher::result_type>(rsh)};
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -185,8 +185,9 @@ getBookBase(Book const& book)
|
||||
UInt256
|
||||
getQualityNext(UInt256 const& uBase)
|
||||
{
|
||||
static constexpr UInt256 kNextQuality(
|
||||
"0000000000000000000000000000000000000000000000010000000000000000");
|
||||
static constexpr UInt256 kNextQuality{
|
||||
"0000000000000000000000000000000000000000000000010000000000000000"};
|
||||
|
||||
return uBase + kNextQuality;
|
||||
}
|
||||
|
||||
@@ -429,9 +430,9 @@ payChannel(AccountID const& src, AccountID const& dst, SeqProxy const& seq) noex
|
||||
Keylet
|
||||
nftokenPageMin(AccountID const& owner)
|
||||
{
|
||||
std::array<std::uint8_t, 32> buf{};
|
||||
std::memcpy(buf.data(), owner.data(), owner.size());
|
||||
return {ltNFTOKEN_PAGE, UInt256::fromRaw(buf)};
|
||||
std::array<std::uint8_t, UInt256::size()> buf{};
|
||||
std::ranges::copy(owner, buf.begin());
|
||||
return {ltNFTOKEN_PAGE, UInt256{buf}};
|
||||
}
|
||||
|
||||
Keylet
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/protocol/HashPrefix.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
@@ -20,8 +21,8 @@ addRaw(LedgerHeader const& info, Serializer& s, bool includeHash)
|
||||
s.addBitString(info.accountHash);
|
||||
s.add32(info.parentCloseTime.time_since_epoch().count());
|
||||
s.add32(info.closeTime.time_since_epoch().count());
|
||||
s.add8(info.closeTimeResolution.count());
|
||||
s.add8(info.closeFlags);
|
||||
s.add8(unsafeCast<std::uint8_t>(info.closeTimeResolution.count()));
|
||||
s.add8(unsafeCast<std::uint8_t>(info.closeFlags));
|
||||
|
||||
if (includeHash)
|
||||
s.addBitString(info.hash);
|
||||
@@ -30,7 +31,7 @@ addRaw(LedgerHeader const& info, Serializer& s, bool includeHash)
|
||||
LedgerHeader
|
||||
deserializeHeader(Slice data, bool hasHash)
|
||||
{
|
||||
SerialIter sit(data.data(), data.size());
|
||||
SerialIter sit{data};
|
||||
|
||||
LedgerHeader header;
|
||||
|
||||
@@ -50,12 +51,6 @@ deserializeHeader(Slice data, bool hasHash)
|
||||
return header;
|
||||
}
|
||||
|
||||
LedgerHeader
|
||||
deserializePrefixedHeader(Slice data, bool hasHash)
|
||||
{
|
||||
return deserializeHeader(data + 4, hasHash);
|
||||
}
|
||||
|
||||
UInt256
|
||||
calculateLedgerHash(LedgerHeader const& info)
|
||||
{
|
||||
|
||||
@@ -295,11 +295,9 @@ verify(PublicKey const& publicKey, Slice const& m, Slice const& sig) noexcept
|
||||
NodeID
|
||||
calcNodeID(PublicKey const& pk)
|
||||
{
|
||||
static_assert(NodeID::kBytes == sizeof(RipeshaHasher::result_type));
|
||||
|
||||
RipeshaHasher h;
|
||||
h(pk.data(), pk.size());
|
||||
return NodeID::fromRaw(static_cast<RipeshaHasher::result_type>(h));
|
||||
return NodeID{static_cast<RipeshaHasher::result_type>(h)};
|
||||
}
|
||||
|
||||
} // 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