Merge branch 'develop' into copilot/apply-asfdisallowincomingtrustline

This commit is contained in:
Mayukha Vadari
2026-07-27 10:40:02 -04:00
committed by GitHub
226 changed files with 8921 additions and 7722 deletions

View File

@@ -30,7 +30,9 @@ ignoreRegExpList:
- ABCDEFGHIJKLMNOPQRSTUVWXYZ
- ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
overrides:
- filename: "**/*_test.cpp" # all test files
- filename:
- "**/*_test.cpp" # legacy boost.test files
- "src/tests/**/*.cpp" # gtest test files
ignoreRegExpList:
- /"[^"]*"/g # double-quoted strings
- /'[^']*'/g # single-quoted strings

View File

@@ -40,18 +40,18 @@ listed later.
| 04 | xrpl/protocol |
| 05 | xrpl/core xrpl/resource xrpl/server |
| 06 | xrpl/ledger xrpl/nodestore xrpl/net |
| 07 | xrpl/shamap |
| 07 | xrpl/shamap xrpl/consensus |
## xrpld Modules (Application Implementation)
| Level / Tier | Module(s) |
| ------------ | -------------------------------- |
| 05 | xrpld/conditions xrpld/consensus |
| 06 | xrpld/core xrpld/peerfinder |
| 07 | xrpld/shamap xrpld/overlay |
| 08 | xrpld/app |
| 09 | xrpld/rpc |
| 10 | xrpld/perflog |
| Level / Tier | Module(s) |
| ------------ | --------------------------- |
| 05 | xrpld/conditions |
| 06 | xrpld/core xrpld/peerfinder |
| 07 | xrpld/shamap xrpld/overlay |
| 08 | xrpld/app |
| 09 | xrpld/rpc |
| 10 | xrpld/perflog |
## Test Modules

View File

@@ -1,9 +1,6 @@
Loop: xrpld.app xrpld.overlay
xrpld.app > xrpld.overlay
Loop: xrpld.app xrpld.peerfinder
xrpld.peerfinder ~= xrpld.app
Loop: xrpld.app xrpld.rpc
xrpld.rpc > xrpld.app

View File

@@ -6,6 +6,8 @@ libxrpl.conditions > xrpl.basics
libxrpl.conditions > xrpl.conditions
libxrpl.config > xrpl.basics
libxrpl.config > xrpl.config
libxrpl.consensus > xrpl.basics
libxrpl.consensus > xrpl.consensus
libxrpl.core > xrpl.basics
libxrpl.core > xrpl.core
libxrpl.core > xrpl.json
@@ -25,6 +27,9 @@ libxrpl.nodestore > xrpl.config
libxrpl.nodestore > xrpl.json
libxrpl.nodestore > xrpl.nodestore
libxrpl.nodestore > xrpl.protocol
libxrpl.peerfinder > xrpl.basics
libxrpl.peerfinder > xrpl.peerfinder
libxrpl.peerfinder > xrpl.protocol
libxrpl.protocol > xrpl.basics
libxrpl.protocol > xrpl.json
libxrpl.protocol > xrpl.protocol
@@ -60,9 +65,9 @@ test.app > test.jtx
test.app > test.unit_test
test.app > xrpl.basics
test.app > xrpl.config
test.app > xrpl.consensus
test.app > xrpl.core
test.app > xrpld.app
test.app > xrpld.consensus
test.app > xrpld.core
test.app > xrpld.overlay
test.app > xrpld.rpc
@@ -83,12 +88,9 @@ test.basics > xrpl.protocol
test.beast > xrpl.basics
test.conditions > xrpl.basics
test.conditions > xrpl.conditions
test.consensus > test.csf
test.consensus > test.jtx
test.consensus > test.unit_test
test.consensus > xrpl.basics
test.consensus > xrpld.app
test.consensus > xrpld.consensus
test.consensus > xrpl.ledger
test.consensus > xrpl.protocol
test.consensus > xrpl.shamap
@@ -103,10 +105,6 @@ test.core > xrpl.json
test.core > xrpl.protocol
test.core > xrpl.rdb
test.core > xrpl.server
test.csf > xrpl.basics
test.csf > xrpld.consensus
test.csf > xrpl.json
test.csf > xrpl.ledger
test.json > test.jtx
test.json > xrpl.json
test.jtx > test.unit_test
@@ -132,12 +130,9 @@ test.ledger > xrpl.json
test.ledger > xrpl.ledger
test.ledger > xrpl.protocol
test.nodestore > test.jtx
test.nodestore > test.unit_test
test.nodestore > xrpl.basics
test.nodestore > xrpl.config
test.nodestore > xrpld.core
test.nodestore > xrpl.nodestore
test.nodestore > xrpl.protocol
test.nodestore > xrpl.rdb
test.overlay > test.jtx
test.overlay > test.unit_test
@@ -146,19 +141,13 @@ test.overlay > xrpl.config
test.overlay > xrpld.app
test.overlay > xrpld.core
test.overlay > xrpld.overlay
test.overlay > xrpld.peerfinder
test.overlay > xrpl.json
test.overlay > xrpl.nodestore
test.overlay > xrpl.peerfinder
test.overlay > xrpl.protocol
test.overlay > xrpl.resource
test.overlay > xrpl.server
test.overlay > xrpl.shamap
test.peerfinder > test.beast
test.peerfinder > test.unit_test
test.peerfinder > xrpl.basics
test.peerfinder > xrpld.core
test.peerfinder > xrpld.peerfinder
test.peerfinder > xrpl.protocol
test.protocol > test.jtx
test.protocol > test.unit_test
test.protocol > xrpl.basics
@@ -192,11 +181,13 @@ test.unit_test > xrpl.basics
test.unit_test > xrpl.protocol
tests.libxrpl > xrpl.basics
tests.libxrpl > xrpl.config
tests.libxrpl > xrpl.consensus
tests.libxrpl > xrpl.core
tests.libxrpl > xrpl.json
tests.libxrpl > xrpl.ledger
tests.libxrpl > xrpl.net
tests.libxrpl > xrpl.nodestore
tests.libxrpl > xrpl.peerfinder
tests.libxrpl > xrpl.protocol
tests.libxrpl > xrpl.protocol_autogen
tests.libxrpl > xrpl.resource
@@ -206,6 +197,10 @@ tests.libxrpl > xrpl.tx
xrpl.conditions > xrpl.basics
xrpl.conditions > xrpl.protocol
xrpl.config > xrpl.basics
xrpl.consensus > xrpl.basics
xrpl.consensus > xrpl.json
xrpl.consensus > xrpl.ledger
xrpl.consensus > xrpl.protocol
xrpl.core > xrpl.basics
xrpl.core > xrpl.json
xrpl.core > xrpl.protocol
@@ -220,6 +215,8 @@ xrpl.nodestore > xrpl.basics
xrpl.nodestore > xrpl.config
xrpl.nodestore > xrpl.json
xrpl.nodestore > xrpl.protocol
xrpl.peerfinder > xrpl.basics
xrpl.peerfinder > xrpl.protocol
xrpl.protocol > xrpl.basics
xrpl.protocol > xrpl.json
xrpl.protocol_autogen > xrpl.json
@@ -246,23 +243,20 @@ xrpl.tx > xrpl.protocol
xrpld.app > test.unit_test
xrpld.app > xrpl.basics
xrpld.app > xrpl.config
xrpld.app > xrpl.consensus
xrpld.app > xrpl.core
xrpld.app > xrpld.consensus
xrpld.app > xrpld.core
xrpld.app > xrpl.json
xrpld.app > xrpl.ledger
xrpld.app > xrpl.net
xrpld.app > xrpl.nodestore
xrpld.app > xrpl.peerfinder
xrpld.app > xrpl.protocol
xrpld.app > xrpl.rdb
xrpld.app > xrpl.resource
xrpld.app > xrpl.server
xrpld.app > xrpl.shamap
xrpld.app > xrpl.tx
xrpld.consensus > xrpl.basics
xrpld.consensus > xrpl.json
xrpld.consensus > xrpl.ledger
xrpld.consensus > xrpl.protocol
xrpld.core > xrpl.basics
xrpld.core > xrpl.config
xrpld.core > xrpl.core
@@ -271,21 +265,22 @@ xrpld.core > xrpl.protocol
xrpld.core > xrpl.rdb
xrpld.overlay > xrpl.basics
xrpld.overlay > xrpl.config
xrpld.overlay > xrpl.consensus
xrpld.overlay > xrpl.core
xrpld.overlay > xrpld.consensus
xrpld.overlay > xrpld.core
xrpld.overlay > xrpld.peerfinder
xrpld.overlay > xrpl.json
xrpld.overlay > xrpl.ledger
xrpld.overlay > xrpl.peerfinder
xrpld.overlay > xrpl.protocol
xrpld.overlay > xrpl.resource
xrpld.overlay > xrpl.server
xrpld.overlay > xrpl.shamap
xrpld.overlay > xrpl.tx
xrpld.peerfinder > xrpl.basics
xrpld.peerfinder > xrpl.config
xrpld.peerfinder > xrpld.app
xrpld.peerfinder > xrpld.core
xrpld.peerfinder > xrpl.protocol
xrpld.peerfinder > xrpl.peerfinder
xrpld.peerfinder > xrpl.rdb
xrpld.perflog > xrpl.basics
xrpld.perflog > xrpl.config

View File

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

View File

@@ -1,5 +1,5 @@
{
"image_tag": "sha-3122de8",
"image_tag": "sha-40cdf49",
"configs": {
"ubuntu": [
{

View File

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

View File

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

114
.github/workflows/check-tools.yml vendored Normal file
View File

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

View File

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

View File

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

View File

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

View File

@@ -110,7 +110,7 @@ jobs:
uses: XRPLF/actions/cleanup-workspace@c7d9ce5ebb03c752a354889ecd870cadfc2b1cd4
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@e4b6449d55a61c002d7c3fdfa6c20f721ede0606

View File

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

View File

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

View File

@@ -34,13 +34,13 @@ 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-3122de8"
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-40cdf49"
permissions:
contents: read
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@e4b6449d55a61c002d7c3fdfa6c20f721ede0606

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -133,6 +133,12 @@ target_link_libraries(
add_module(xrpl resource)
target_link_libraries(xrpl.libxrpl.resource PUBLIC xrpl.libxrpl.protocol)
add_module(xrpl peerfinder)
target_link_libraries(
xrpl.libxrpl.peerfinder
PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.protocol
)
# Level 08
add_module(xrpl net)
target_link_libraries(
@@ -201,6 +207,16 @@ target_link_libraries(
add_module(xrpl tx)
target_link_libraries(xrpl.libxrpl.tx PUBLIC xrpl.libxrpl.ledger)
add_module(xrpl consensus)
target_link_libraries(
xrpl.libxrpl.consensus
PUBLIC
xrpl.libxrpl.basics
xrpl.libxrpl.json
xrpl.libxrpl.protocol
xrpl.libxrpl.ledger
)
add_library(xrpl.libxrpl)
set_target_properties(xrpl.libxrpl PROPERTIES OUTPUT_NAME xrpl)
@@ -220,6 +236,7 @@ target_link_modules(
beast
conditions
config
consensus
core
crypto
git
@@ -227,6 +244,7 @@ target_link_modules(
ledger
net
nodestore
peerfinder
protocol
protocol_autogen
rdb

View File

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

38
docs/build/nix.md vendored
View File

@@ -38,8 +38,10 @@ The first time you run this command, it will take a few minutes to download and
### Platform notes
- **Linux**: `nix develop` gives you a shell with all the tooling necessary to
develop xrpld and with GCC 15.2 (also provided by Nix). There are no caveats.
- **Linux**: `nix develop` gives you a shell with all the tooling necessary to develop xrpld
and with the same GCC/glibc toolchain that Nix builds for CI.
See [Choosing a different compiler](#choosing-a-different-compiler)
for the custom-vs-plain toolchain trade-off.
- **macOS**: `nix develop` gives you a full environment too, with Clang (and
every other tool, including Conan) provided by Nix. To use your system-wide
Apple Clang instead, enter `nix develop .#apple-clang`. Conan has no binary in
@@ -63,8 +65,16 @@ The first time you run this command, it will take a few minutes to download and
### Choosing a different compiler
A compiler can be chosen by providing its name with the `.#` prefix, e.g. `nix develop .#clang`.
The `.#gcc` and `.#clang` shells provide the same GCC and Clang versions used in CI
(pinned in [`nix/packages.nix`](../../nix/packages.nix)).
On Linux, `.#gcc` and `.#clang` provide the exact toolchain CI uses:
the compiler (pinned in [`nix/packages.nix`](../../nix/packages.nix))
rebuilt against the pinned custom glibc (see [`nix/compilers.nix`](../../nix/compilers.nix)).
Building that toolchain the first time is slow unless it is fetched from a Nix binary cache.
If you don't need the custom glibc, the Linux-only `.#gcc-plain` and `.#clang-plain`
give you the stock nixpkgs compilers of the same versions.
On macOS there is no custom glibc, so `.#gcc` and `.#clang` are already the plain nixpkgs toolchain,
and the `-plain` variants do not exist.
Use `nix flake show` to see all the available development shells.
Use `nix develop .#no-compiler` to use the compiler from your system.
@@ -72,14 +82,18 @@ Use `nix develop .#no-compiler` to use the compiler from your system.
### Example Usage
```bash
# Use GCC (same version as CI)
# Use GCC same toolchain as CI (custom glibc on Linux)
nix develop .#gcc
# Use Clang (same version as CI)
# Use Clang same toolchain as CI (custom glibc on Linux)
nix develop .#clang
# Use default for your platform
nix develop
# Stock nixpkgs GCC/Clang, Linux only — skips the custom-glibc build, but does not match CI
nix develop .#gcc-plain
nix develop .#clang-plain
```
### Using a different shell
@@ -110,6 +124,10 @@ nix develop -c "$SHELL"
Once inside the Nix development shell, follow the standard [build instructions](../../BUILD.md#steps). The Nix shell provides all necessary tools (CMake, Ninja, Conan, etc.).
Coverage builds (`-Dcoverage=ON`) work in the `gcc` shell (and `gcc-plain` on Linux):
each ships a `gcov` matching its compiler, since Nix's cc-wrapper does not expose one.
The `clang` shells do not include `llvm-cov`, so use a `gcc` shell for coverage.
## Automatic Activation with direnv
[direnv](https://direnv.net/) or [nix-direnv](https://github.com/nix-community/nix-direnv) can automatically activate the Nix development shell when you enter the repository directory.
@@ -136,6 +154,14 @@ conan install .. --output-folder . --build '*' --settings build_type=Release
To update `flake.lock` to the latest revision use `nix flake update` command.
## Tooling snapshots
The tool versions in each Nix environment are recorded in
[`nix/check-tools/`](../../nix/check-tools) and verified by CI. If you change the
environment (bump the CI image tag, update `flake.lock`, or edit the tool list in
`bin/check-tools.sh`), CI fails until you regenerate and commit the affected
snapshot — see [`nix/check-tools/README.md`](../../nix/check-tools/README.md).
## Troubleshooting
See [Troubleshooting Nix problems](./nix_troubleshooting.md) for common issues,

View File

@@ -5,6 +5,7 @@
#include <xrpl/beast/container/detail/aged_associative_container.h>
#include <xrpl/beast/container/detail/aged_container_iterator.h>
#include <xrpl/beast/container/detail/empty_base_optimization.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <boost/intrusive/list.hpp>
#include <boost/intrusive/unordered_set.hpp>

View File

@@ -10,7 +10,7 @@
namespace xrpl {
template <class TxID, class Sequence>
class RCLCensorshipDetector
class CensorshipDetector
{
public:
struct TxIDSeq
@@ -49,7 +49,7 @@ private:
TxIDSeqVec tracker_;
public:
RCLCensorshipDetector() = default;
CensorshipDetector() = default;
/**
* Add transactions being proposed for the current consensus round.

View File

@@ -1,15 +1,14 @@
#pragma once
#include <xrpld/consensus/ConsensusParms.h>
#include <xrpld/consensus/ConsensusProposal.h>
#include <xrpld/consensus/ConsensusTypes.h>
#include <xrpl/basics/Log.h>
#include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/beast/clock/abstract_clock.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/consensus/ConsensusParms.h>
#include <xrpl/consensus/ConsensusProposal.h>
#include <xrpl/consensus/ConsensusTypes.h>
#include <xrpl/json/json_value.h>
#include <xrpl/json/json_writer.h>
#include <xrpl/ledger/LedgerTiming.h>

View File

@@ -1,11 +1,10 @@
#pragma once
#include <xrpld/consensus/ConsensusProposal.h>
#include <xrpld/consensus/DisputedTx.h>
#include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/consensus/ConsensusProposal.h>
#include <xrpl/consensus/DisputedTx.h>
#include <chrono>
#include <cstddef>

View File

@@ -1,9 +1,8 @@
#pragma once
#include <xrpld/consensus/ConsensusParms.h>
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/consensus/ConsensusParms.h>
#include <xrpl/json/json_value.h>
#include <xrpl/json/json_writer.h>

View File

@@ -1,7 +1,5 @@
#pragma once
#include <xrpld/consensus/LedgerTrie.h>
#include <xrpl/basics/Log.h>
#include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/basics/chrono.h>
@@ -11,6 +9,7 @@
#include <xrpl/beast/hash/uhash.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/consensus/LedgerTrie.h>
#include <xrpl/json/json_value.h>
#include <algorithm>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -21,7 +21,7 @@
#include <cstring>
#include <string>
namespace xrpl::NodeStore {
namespace xrpl::node_store {
template <class BufferFactory>
std::pair<void const*, std::size_t>
@@ -269,7 +269,7 @@ nodeobjectCompress(void const* in, std::size_t inSize, BufferFactory&& bf)
case 1: // lz4
{
std::uint8_t* p = nullptr;
auto const lzr = NodeStore::lz4Compress(in, inSize, [&p, &vn, &bf](std::size_t n) {
auto const lzr = node_store::lz4Compress(in, inSize, [&p, &vn, &bf](std::size_t n) {
p = reinterpret_cast<std::uint8_t*>(bf(vn + n));
return p + vn;
});
@@ -316,4 +316,4 @@ filterInner(void* in, std::size_t inSize)
}
}
} // namespace xrpl::NodeStore
} // namespace xrpl::node_store

View File

@@ -6,7 +6,7 @@
#include <cstdint>
#include <type_traits>
namespace xrpl::NodeStore {
namespace xrpl::node_store {
// This is a variant of the base128 varint format from
// google protocol buffers:
@@ -123,4 +123,4 @@ write(nudb::detail::ostream& os, std::size_t t)
writeVarint(os.data(sizeVarint(t)), t);
}
} // namespace xrpl::NodeStore
} // namespace xrpl::node_store

View File

@@ -0,0 +1,163 @@
#pragma once
#include <xrpl/beast/utility/PropertyStream.h>
#include <xrpl/peerfinder/detail/Tuning.h>
#include <cstddef>
#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
namespace xrpl::PeerFinder {
struct PeerLimitConfig
{
std::optional<std::size_t> maxPeers;
std::optional<std::size_t> inPeers;
std::optional<std::size_t> outPeers;
};
/**
* PeerFinder configuration settings.
*/
struct Config
{
/**
* The largest number of public peer slots to allow.
* This includes both inbound and outbound, but does not include
* fixed peers.
*/
std::size_t maxPeers{Tuning::kDefaultMaxPeers};
/**
* The number of automatic outbound connections to maintain.
* Outbound connections are only maintained if autoConnect
* is `true`.
*/
std::size_t outPeers = calcOutPeers(); // Note: relies on `maxPeers` being initialized
/**
* The number of automatic inbound connections to maintain.
* Inbound connections are only maintained if wantIncoming
* is `true`.
*/
std::size_t inPeers{0};
/**
* `true` if we want our IP address kept private.
*/
bool peerPrivate = true;
/**
* `true` if we want to accept incoming connections.
*/
bool wantIncoming{true};
/**
* `true` if we want to establish connections automatically
*/
bool autoConnect{true};
/**
* The listening port number.
*/
std::uint16_t listeningPort{0};
/**
* The set of features we advertise.
*/
std::string features;
/**
* Limit how many incoming connections we allow per IP
*/
int ipLimit{0};
/**
* `true` if we want to verify endpoints in TMEndpoints messages
*/
bool verifyEndpoints = true;
//--------------------------------------------------------------------------
/**
* Returns a suitable value for outPeers according to the rules.
*/
[[nodiscard]] std::size_t
calcOutPeers() const;
/**
* Adjusts the values so they follow the business rules.
*/
void
applyTuning();
/**
* Write the configuration into a property stream
*/
void
onWrite(beast::PropertyStream::Map& map) const;
/**
* Make PeerFinder::Config from peer limit and server mode parameters.
*/
static Config
makeConfig(
bool peerPrivate,
bool standalone,
PeerLimitConfig const& limits,
std::uint16_t port,
bool validationPublicKey,
int ipLimit,
bool verifyEndpoints);
/**
* Compares two configurations for equality field by field.
*/
friend bool
operator==(Config const& lhs, Config const& rhs) = default;
};
//------------------------------------------------------------------------------
/**
* Possible results from activating a slot.
*/
enum class Result { InboundDisabled, DuplicatePeer, IpLimitExceeded, Full, Success };
/**
* @brief Converts a `Result` enum value to its string representation.
*
* This function provides a human-readable string for a given `Result` enum,
* which is useful for logging, debugging, or displaying status messages.
*
* @param result The `Result` enum value to convert.
* @return A `std::string_view` representing the enum value. Returns "unknown"
* if the enum value is not explicitly handled.
*
* @note This function returns a `std::string_view` for performance.
* A `std::string` would need to allocate memory on the heap and copy the
* string literal into it every time the function is called.
*/
inline std::string_view
to_string(Result result) noexcept
{
switch (result)
{
case Result::InboundDisabled:
return "inbound disabled";
case Result::DuplicatePeer:
return "peer already connected";
case Result::IpLimitExceeded:
return "ip limit exceeded";
case Result::Full:
return "slots full";
case Result::Success:
return "success";
}
return "unknown";
}
} // namespace xrpl::PeerFinder

View File

@@ -0,0 +1,179 @@
#pragma once
#include <xrpl/beast/net/IPEndpoint.h>
#include <xrpl/beast/utility/PropertyStream.h>
#include <xrpl/peerfinder/Config.h>
#include <xrpl/peerfinder/Slot.h>
#include <xrpl/peerfinder/Types.h>
#include <xrpl/protocol/PublicKey.h>
#include <boost/asio/ip/tcp.hpp>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
namespace xrpl::PeerFinder {
/**
* Maintains a set of IP addresses used for getting into the network.
*/
class Manager : public beast::PropertyStream::Source
{
protected:
Manager() noexcept;
public:
/**
* Destroy the object.
* Any pending source fetch operations are aborted.
* There may be some listener calls made before the
* destructor returns.
*/
~Manager() override = default;
/**
* Set the configuration for the manager.
* The new settings will be applied asynchronously.
* Thread safety:
* Can be called from any threads at any time.
*/
virtual void
setConfig(Config const& config) = 0;
/**
* Transition to the started state, synchronously.
*/
virtual void
start() = 0;
/**
* Transition to the stopped state, synchronously.
*/
virtual void
stop() = 0;
/**
* Returns the configuration for the manager.
*/
virtual Config
config() = 0;
/**
* Add a peer that should always be connected.
* This is useful for maintaining a private cluster of peers.
* The string is the name as specified in the configuration
* file, along with the set of corresponding IP addresses.
*/
virtual void
addFixedPeer(std::string_view name, std::vector<beast::IP::Endpoint> const& addresses) = 0;
/**
* Add a set of strings as fallback IP::Endpoint sources.
* @param name A label used for diagnostics.
*/
virtual void
addFallbackStrings(std::string const& name, std::vector<std::string> const& strings) = 0;
/**
* Add a URL as a fallback location to obtain IP::Endpoint sources.
* @param name A label used for diagnostics.
*/
/* VFALCO NOTE Unimplemented
virtual void addFallbackURL (std::string const& name,
std::string const& url) = 0;
*/
//--------------------------------------------------------------------------
/**
* Create a new inbound slot with the specified remote endpoint.
* If nullptr is returned, then the slot could not be assigned.
* Usually this is because of a detected self-connection.
*/
virtual std::pair<std::shared_ptr<Slot>, Result>
newInboundSlot(
beast::IP::Endpoint const& localEndpoint,
beast::IP::Endpoint const& remoteEndpoint) = 0;
/**
* Create a new outbound slot with the specified remote endpoint.
* If nullptr is returned, then the slot could not be assigned.
* Usually this is because of a duplicate connection.
*/
virtual std::pair<std::shared_ptr<Slot>, Result>
newOutboundSlot(beast::IP::Endpoint const& remoteEndpoint) = 0;
/**
* Called when mtENDPOINTS is received.
*/
virtual void
onEndpoints(std::shared_ptr<Slot> const& slot, Endpoints const& endpoints) = 0;
/**
* Called when the slot is closed.
* This always happens when the socket is closed, unless the socket
* was canceled.
*/
virtual void
onClosed(std::shared_ptr<Slot> const& slot) = 0;
/**
* Called when an outbound connection is deemed to have failed
*/
virtual void
onFailure(std::shared_ptr<Slot> const& slot) = 0;
/**
* Called when we received redirect IPs from a busy peer.
*/
virtual void
onRedirects(
boost::asio::ip::tcp::endpoint const& remoteAddress,
std::vector<boost::asio::ip::tcp::endpoint> const& eps) = 0;
//--------------------------------------------------------------------------
/**
* Called when an outbound connection attempt succeeds.
* The local endpoint must be valid. If the caller receives an error
* when retrieving the local endpoint from the socket, it should
* proceed as if the connection attempt failed by calling on_closed
* instead of on_connected.
* @return `true` if the connection should be kept
*/
virtual bool
onConnected(std::shared_ptr<Slot> const& slot, beast::IP::Endpoint const& localEndpoint) = 0;
/**
* Request an active slot type.
*/
virtual Result
activate(std::shared_ptr<Slot> const& slot, PublicKey const& key, bool reserved) = 0;
/**
* Returns a set of endpoints suitable for redirection.
*/
virtual std::vector<Endpoint>
redirect(std::shared_ptr<Slot> const& slot) = 0;
/**
* Return a set of addresses we should connect to.
*/
virtual std::vector<beast::IP::Endpoint>
autoconnect() = 0;
virtual std::vector<std::pair<std::shared_ptr<Slot>, std::vector<Endpoint>>>
buildEndpointsForPeers() = 0;
/**
* Perform periodic activity.
* This should be called once per second.
*/
virtual void
oncePerSecond() = 0;
};
} // namespace xrpl::PeerFinder

View File

@@ -0,0 +1,46 @@
#pragma once
#include <xrpl/beast/clock/abstract_clock.h>
#include <xrpl/beast/net/IPEndpoint.h>
#include <xrpl/peerfinder/detail/Tuning.h>
#include <chrono>
#include <cstdint>
#include <vector>
namespace xrpl::PeerFinder {
using clock_type = beast::AbstractClock<std::chrono::steady_clock>;
/**
* Represents a set of addresses.
*/
using IPAddresses = std::vector<beast::IP::Endpoint>;
//------------------------------------------------------------------------------
/**
* Describes a connectable peer address along with some metadata.
*/
struct Endpoint
{
Endpoint() = default;
Endpoint(beast::IP::Endpoint ep, std::uint32_t hops);
std::uint32_t hops = 0;
beast::IP::Endpoint address;
};
inline bool
operator<(Endpoint const& lhs, Endpoint const& rhs)
{
return lhs.address < rhs.address;
}
/**
* A set of Endpoint used for connecting.
*/
using Endpoints = std::vector<Endpoint>;
} // namespace xrpl::PeerFinder

View File

@@ -1,11 +1,11 @@
#pragma once
#include <xrpld/peerfinder/PeerfinderManager.h>
#include <xrpld/peerfinder/detail/Store.h>
#include <xrpl/beast/net/IPEndpoint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/PropertyStream.h>
#include <xrpl/peerfinder/Types.h>
#include <xrpl/peerfinder/detail/Store.h>
#include <xrpl/peerfinder/detail/Tuning.h>
#include <boost/bimap.hpp>
#include <boost/bimap/multiset_of.hpp>

View File

@@ -1,11 +1,10 @@
#pragma once
#include <xrpld/peerfinder/PeerfinderManager.h>
#include <xrpld/peerfinder/Slot.h>
#include <xrpld/peerfinder/detail/Tuning.h>
#include <xrpl/beast/utility/PropertyStream.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/peerfinder/Config.h>
#include <xrpl/peerfinder/Slot.h>
#include <xrpl/peerfinder/detail/Tuning.h>
#include <cstddef>
#include <sstream>

View File

@@ -1,7 +1,7 @@
#pragma once
#include <xrpld/peerfinder/PeerfinderManager.h>
#include <xrpld/peerfinder/detail/Tuning.h>
#include <xrpl/peerfinder/Types.h>
#include <xrpl/peerfinder/detail/Tuning.h>
#include <algorithm>
#include <chrono>

View File

@@ -1,12 +1,11 @@
#pragma once
#include <xrpld/peerfinder/PeerfinderManager.h>
#include <xrpld/peerfinder/detail/SlotImp.h>
#include <xrpld/peerfinder/detail/Tuning.h>
#include <xrpl/beast/container/aged_set.h>
#include <xrpl/beast/net/IPAddress.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/peerfinder/Types.h>
#include <xrpl/peerfinder/detail/SlotImp.h>
#include <xrpl/peerfinder/detail/Tuning.h>
#include <algorithm>
#include <cstddef>

View File

@@ -1,9 +1,5 @@
#pragma once
#include <xrpld/peerfinder/PeerfinderManager.h>
#include <xrpld/peerfinder/detail/Tuning.h>
#include <xrpld/peerfinder/detail/iosformat.h>
#include <xrpl/basics/Log.h>
#include <xrpl/basics/random.h>
#include <xrpl/beast/container/aged_map.h>
@@ -12,6 +8,8 @@
#include <xrpl/beast/utility/PropertyStream.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/beast/utility/maybe_const.h>
#include <xrpl/peerfinder/Types.h>
#include <xrpl/peerfinder/detail/Tuning.h>
#include <boost/intrusive/list.hpp>
#include <boost/iterator/transform_iterator.hpp>
@@ -22,6 +20,8 @@
#include <cstddef>
#include <cstdint>
#include <functional>
#include <iomanip>
#include <ios>
#include <iterator>
#include <memory>
#include <sstream>
@@ -411,7 +411,7 @@ Livecache<Allocator>::expire()
}
if (n > 0)
{
JLOG(journal_.debug()) << beast::Leftw(18) << "Livecache expired " << n
JLOG(journal_.debug()) << std::left << std::setw(18) << "Livecache expired " << n
<< ((n > 1) ? " entries" : " entry");
}
}
@@ -434,7 +434,7 @@ Livecache<Allocator>::insert(Endpoint const& ep)
if (result.second)
{
hops.insert(e);
JLOG(journal_.debug()) << beast::Leftw(18) << "Livecache insert " << ep.address
JLOG(journal_.debug()) << std::left << std::setw(18) << "Livecache insert " << ep.address
<< " at hops " << ep.hops;
return;
}
@@ -442,7 +442,7 @@ Livecache<Allocator>::insert(Endpoint const& ep)
{
// Drop duplicates at higher hops
std::size_t const excess(ep.hops - e.endpoint.hops);
JLOG(journal_.trace()) << beast::Leftw(18) << "Livecache drop " << ep.address
JLOG(journal_.trace()) << std::left << std::setw(18) << "Livecache drop " << ep.address
<< " at hops +" << excess;
return;
}
@@ -453,12 +453,12 @@ Livecache<Allocator>::insert(Endpoint const& ep)
if (ep.hops < e.endpoint.hops)
{
hops.reinsert(e, ep.hops);
JLOG(journal_.debug()) << beast::Leftw(18) << "Livecache update " << ep.address
JLOG(journal_.debug()) << std::left << std::setw(18) << "Livecache update " << ep.address
<< " at hops " << ep.hops;
}
else
{
JLOG(journal_.trace()) << beast::Leftw(18) << "Livecache refresh " << ep.address
JLOG(journal_.trace()) << std::left << std::setw(18) << "Livecache refresh " << ep.address
<< " at hops " << ep.hops;
}
}

View File

@@ -1,17 +1,5 @@
#pragma once
#include <xrpld/peerfinder/PeerfinderManager.h>
#include <xrpld/peerfinder/Slot.h>
#include <xrpld/peerfinder/detail/Bootcache.h>
#include <xrpld/peerfinder/detail/Counts.h>
#include <xrpld/peerfinder/detail/Fixed.h>
#include <xrpld/peerfinder/detail/Handouts.h>
#include <xrpld/peerfinder/detail/Livecache.h>
#include <xrpld/peerfinder/detail/SlotImp.h>
#include <xrpld/peerfinder/detail/Source.h>
#include <xrpld/peerfinder/detail/Store.h>
#include <xrpld/peerfinder/detail/iosformat.h>
#include <xrpl/basics/Log.h>
#include <xrpl/basics/contract.h>
#include <xrpl/basics/random.h>
@@ -22,18 +10,34 @@
#include <xrpl/beast/utility/PropertyStream.h>
#include <xrpl/beast/utility/WrappedSink.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/peerfinder/Config.h>
#include <xrpl/peerfinder/Slot.h>
#include <xrpl/peerfinder/Types.h>
#include <xrpl/peerfinder/detail/Bootcache.h>
#include <xrpl/peerfinder/detail/Counts.h>
#include <xrpl/peerfinder/detail/Fixed.h>
#include <xrpl/peerfinder/detail/Handouts.h>
#include <xrpl/peerfinder/detail/Livecache.h>
#include <xrpl/peerfinder/detail/SlotImp.h>
#include <xrpl/peerfinder/detail/Source.h>
#include <xrpl/peerfinder/detail/Store.h>
#include <xrpl/protocol/PublicKey.h>
#include <boost/asio/error.hpp>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <iomanip>
#include <ios>
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <set>
#include <stdexcept>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
@@ -197,8 +201,8 @@ public:
if (result.second)
{
JLOG(journal.debug())
<< beast::Leftw(18) << "Logic add fixed '" << name << "' at " << remoteAddress;
JLOG(journal.debug()) << std::left << std::setw(18) << "Logic add fixed '" << name
<< "' at " << remoteAddress;
return;
}
}
@@ -221,7 +225,7 @@ public:
if (iter == slots.end())
{
// The slot disconnected before we finished the check
JLOG(journal.debug()) << beast::Leftw(18) << "Logic tested " << checkedAddress
JLOG(journal.debug()) << std::left << std::setw(18) << "Logic tested " << checkedAddress
<< " but the connection was closed";
return;
}
@@ -255,7 +259,7 @@ public:
beast::IP::Endpoint const& localEndpoint,
beast::IP::Endpoint const& remoteEndpoint)
{
JLOG(journal.debug()) << beast::Leftw(18) << "Logic accept" << remoteEndpoint
JLOG(journal.debug()) << std::left << std::setw(18) << "Logic accept" << remoteEndpoint
<< " on local " << localEndpoint;
std::scoped_lock const _(lock);
@@ -266,7 +270,7 @@ public:
auto const count = connectedAddresses.count(remoteEndpoint.address());
if (count + 1 > config_.ipLimit)
{
JLOG(journal.debug()) << beast::Leftw(18) << "Logic dropping inbound "
JLOG(journal.debug()) << std::left << std::setw(18) << "Logic dropping inbound "
<< remoteEndpoint << " because of ip limits.";
return {SlotImp::ptr(), Result::IpLimitExceeded};
}
@@ -275,8 +279,8 @@ public:
// Check for duplicate connection
if (slots.contains(remoteEndpoint))
{
JLOG(journal.debug()) << beast::Leftw(18) << "Logic dropping " << remoteEndpoint
<< " as duplicate incoming";
JLOG(journal.debug()) << std::left << std::setw(18) << "Logic dropping "
<< remoteEndpoint << " as duplicate incoming";
return {SlotImp::ptr(), Result::DuplicatePeer};
}
@@ -304,15 +308,15 @@ public:
std::pair<SlotImp::ptr, Result>
newOutboundSlot(beast::IP::Endpoint const& remoteEndpoint)
{
JLOG(journal.debug()) << beast::Leftw(18) << "Logic connect " << remoteEndpoint;
JLOG(journal.debug()) << std::left << std::setw(18) << "Logic connect " << remoteEndpoint;
std::scoped_lock const _(lock);
// Check for duplicate connection
if (slots.contains(remoteEndpoint))
{
JLOG(journal.debug()) << beast::Leftw(18) << "Logic dropping " << remoteEndpoint
<< " as duplicate connect";
JLOG(journal.debug()) << std::left << std::setw(18) << "Logic dropping "
<< remoteEndpoint << " as duplicate connect";
return {SlotImp::ptr(), Result::DuplicatePeer};
}
@@ -506,15 +510,15 @@ public:
if (!h.list().empty())
{
JLOG(journal.debug())
<< beast::Leftw(18) << "Logic connect " << h.list().size() << " fixed";
JLOG(journal.debug()) << std::left << std::setw(18) << "Logic connect "
<< h.list().size() << " fixed";
return h.list();
}
if (counts_.attempts() > 0)
{
JLOG(journal.debug())
<< beast::Leftw(18) << "Logic waiting on " << counts_.attempts() << " attempts";
JLOG(journal.debug()) << std::left << std::setw(18) << "Logic waiting on "
<< counts_.attempts() << " attempts";
return none;
}
}
@@ -535,14 +539,14 @@ public:
if (!h.list().empty())
{
JLOG(journal.debug())
<< beast::Leftw(18) << "Logic connect " << h.list().size() << " live "
<< std::left << std::setw(18) << "Logic connect " << h.list().size() << " live "
<< ((h.list().size() > 1) ? "endpoints" : "endpoint");
return h.list();
}
if (counts_.attempts() > 0)
{
JLOG(journal.debug())
<< beast::Leftw(18) << "Logic waiting on " << counts_.attempts() << " attempts";
JLOG(journal.debug()) << std::left << std::setw(18) << "Logic waiting on "
<< counts_.attempts() << " attempts";
return none;
}
}
@@ -568,8 +572,9 @@ public:
if (!h.list().empty())
{
JLOG(journal.debug()) << beast::Leftw(18) << "Logic connect " << h.list().size()
<< " boot " << ((h.list().size() > 1) ? "addresses" : "address");
JLOG(journal.debug()) << std::left << std::setw(18) << "Logic connect "
<< h.list().size() << " boot "
<< ((h.list().size() > 1) ? "addresses" : "address");
return h.list();
}
@@ -689,8 +694,8 @@ public:
// Enforce hop limit
if (ep.hops > Tuning::kMaxHops)
{
JLOG(journal.debug()) << beast::Leftw(18) << "Endpoints drop " << ep.address
<< " for excess hops " << ep.hops;
JLOG(journal.debug()) << std::left << std::setw(18) << "Endpoints drop "
<< ep.address << " for excess hops " << ep.hops;
iter = list.erase(iter);
continue;
}
@@ -706,18 +711,18 @@ public:
}
else
{
JLOG(journal.debug())
<< beast::Leftw(18) << "Endpoints drop " << ep.address << " for extra self";
JLOG(journal.debug()) << std::left << std::setw(18) << "Endpoints drop "
<< ep.address << " for extra self";
iter = list.erase(iter);
continue;
}
}
// Discard invalid addresses
if (config_.verifyEndpoints && !isValidAddress(ep.address))
if (!isValidAddress(ep.address))
{
JLOG(journal.debug())
<< beast::Leftw(18) << "Endpoints drop " << ep.address << " as invalid";
JLOG(journal.debug()) << std::left << std::setw(18) << "Endpoints drop "
<< ep.address << " as invalid";
iter = list.erase(iter);
continue;
}
@@ -727,8 +732,8 @@ public:
return ep.address == other.address;
}))
{
JLOG(journal.debug())
<< beast::Leftw(18) << "Endpoints drop " << ep.address << " as duplicate";
JLOG(journal.debug()) << std::left << std::setw(18) << "Endpoints drop "
<< ep.address << " as duplicate";
iter = list.erase(iter);
continue;
}
@@ -1074,13 +1079,13 @@ public:
if (!results.error)
{
int const count(addBootcacheAddresses(results.addresses));
JLOG(journal.info()) << beast::Leftw(18) << "Logic added " << count << " new "
JLOG(journal.info()) << std::left << std::setw(18) << "Logic added " << count << " new "
<< ((count == 1) ? "address" : "addresses") << " from "
<< source->name();
}
else
{
JLOG(journal.error()) << beast::Leftw(18) << "Logic failed "
JLOG(journal.error()) << std::left << std::setw(18) << "Logic failed "
<< "'" << source->name() << "' fetch, "
<< results.error.message();
}
@@ -1098,8 +1103,6 @@ public:
{
if (isUnspecified(address))
return false;
if (isLoopback(address))
return false;
if (!isPublic(address))
return false;
if (address.port() == 0)
@@ -1221,8 +1224,8 @@ Logic<Checker>::onRedirects(
bootcache.insert(beast::IPAddressConversion::fromAsio(*first));
if (n > 0)
{
JLOG(journal.trace()) << beast::Leftw(18) << "Logic add " << n << " redirect IPs from "
<< remoteAddress;
JLOG(journal.trace()) << std::left << std::setw(18) << "Logic add " << n
<< " redirect IPs from " << remoteAddress;
}
}

View File

@@ -1,10 +1,9 @@
#pragma once
#include <xrpld/peerfinder/PeerfinderManager.h>
#include <xrpld/peerfinder/Slot.h>
#include <xrpl/beast/container/aged_unordered_map.h>
#include <xrpl/beast/net/IPEndpoint.h>
#include <xrpl/peerfinder/Slot.h>
#include <xrpl/peerfinder/Types.h>
#include <xrpl/protocol/PublicKey.h>
#include <atomic>
@@ -172,7 +171,7 @@ private:
std::optional<beast::IP::Endpoint> localEndpoint_;
std::optional<PublicKey> publicKey_;
static constexpr std::int32_t kUnknownPort = -1;
static std::int32_t constexpr kUnknownPort = -1;
std::atomic<std::int32_t> listeningPort_;
public:

View File

@@ -1,8 +1,7 @@
#pragma once
#include <xrpld/peerfinder/PeerfinderManager.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/peerfinder/Types.h>
#include <boost/system/error_code.hpp>

View File

@@ -1,6 +1,6 @@
#pragma once
#include <xrpld/peerfinder/detail/Source.h>
#include <xrpl/peerfinder/detail/Source.h>
#include <memory>
#include <string>

View File

@@ -0,0 +1,36 @@
#pragma once
#include <xrpl/beast/insight/Collector.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/peerfinder/PeerfinderManager.h>
#include <xrpl/peerfinder/Types.h>
#include <xrpl/peerfinder/detail/Store.h>
#include <boost/asio/io_context.hpp>
#include <memory>
namespace xrpl::PeerFinder {
/**
* @brief Create a new Manager.
*
* @param ioContext The io_context used to schedule asynchronous work.
* @param clock The clock used for timekeeping.
* @param journal The journal used for logging.
* @param store The persistence backend for the bootstrap cache. The caller
* retains ownership and must keep it alive (and opened) for the lifetime of
* the returned Manager. This lets consumers supply their own Store
* implementation (e.g. the SQLite-backed StoreSqdb in xrpld).
* @param collector The collector used to report metrics.
* @return The newly created Manager.
*/
std::unique_ptr<Manager>
makeManager(
boost::asio::io_context& ioContext,
clock_type& clock,
beast::Journal journal,
Store& store,
beast::insight::Collector::ptr const& collector);
} // namespace xrpl::PeerFinder

View File

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

View File

@@ -17,7 +17,8 @@ class ValidPermissionedDEX
bool regularOffers_ = false; // post-fixCleanup3_2_0: excludes deleted offers
bool badHybridsOld_ = false; // pre-fixCleanup3_1_3: missing field/domain or size > 1
bool badHybrids_ = false; // post-fixCleanup3_1_3: also catches size == 0 (size != 1)
hash_set<uint256> domains_;
hash_set<uint256> domainsOld_; // pre-fixCleanup3_4_0: also flags deleted domains
hash_set<uint256> domains_; // post-fixCleanup3_4_0: excludes deleted domains
public:
void

49
nix/check-tools/README.md Normal file
View File

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

47
nix/check-tools/macos.txt Normal file
View File

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

View File

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

View File

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

View File

@@ -6,108 +6,18 @@
let
inherit (import ./packages.nix { inherit pkgs; })
commonPackages
gccPackage
gccVersion
llvmPackages
llvmVersion
mkVersionedToolLinks
;
# Underlying compiler toolchains to wrap (versions pinned in packages.nix).
customGccPackage = gccPackage;
customLlvmPackages = llvmPackages;
# binutils wrapped to emit binaries that reference the custom glibc
# (dynamic linker path, library search path, RPATH).
customBinutils = pkgs.wrapBintoolsWith {
bintools = pkgs.binutils-unwrapped;
libc = customGlibc;
};
# Rebuild gcc (specifically libstdc++ / libgcc_s) against the custom
# glibc. The override swaps gcc.cc's bootstrap stdenv for one that uses
# the existing gcc binary but links against the custom glibc, so the
# resulting compiler ships runtime libraries that only reference symbols
# available in that glibc.
customGccCc = customGccPackage.cc.override {
stdenv = pkgs.stdenvAdapters.overrideCC pkgs.stdenv (
pkgs.wrapCCWith {
cc = customGccPackage.cc;
libc = customGlibc;
bintools = customBinutils;
}
);
};
# cc-wrapper around the rebuilt compiler, pointing at the custom glibc
# headers and libraries. This is what we actually expose to users.
customGcc = pkgs.wrapCCWith {
cc = customGccCc;
libc = customGlibc;
bintools = customBinutils;
};
# gcov ships in gcc's `cc` output, but the cc-wrapper doesn't expose it.
# Surface the gcov from our rebuilt gcc (linked against the custom glibc, so
# it runs under the loader installed in the image) and matching the exact
# compiler version, so gcovr can produce coverage reports in the CI env.
customGcov = pkgs.runCommand "gcov-custom-for-ci-env" { } ''
mkdir -p "$out/bin"
ln -s "${customGccCc}/bin/gcov" "$out/bin/gcov"
'';
# stdenv built around the rebuilt gcc / custom glibc. Used to rebuild
# compiler-rt below so its sanitizer runtimes see the custom glibc
# headers.
customStdenv = pkgs.stdenvAdapters.overrideCC pkgs.stdenv customGcc;
# Rebuild compiler-rt against the custom glibc so the sanitizer runtimes
# don't use glibc symbols (or sysconf constants like _SC_SIGSTKSZ) that
# only exist in newer glibc versions. scudo is dropped because its CMake
# includes CheckAtomic with -nostdinc++ in CMAKE_REQUIRED_FLAGS, which
# makes std::atomic unfindable in our stdenv; we don't use scudo (only
# asan/ubsan/tsan etc.).
customCompilerRt =
(customLlvmPackages.compiler-rt.override {
stdenv = customStdenv;
}).overrideAttrs
(old: {
postPatch = (old.postPatch or "") + ''
substituteInPlace lib/CMakeLists.txt \
--replace-quiet 'add_subdirectory(scudo/standalone)' \
'# scudo/standalone disabled in xrpld ci-env'
'';
});
# cc-wrapper around clang, pointing at the custom glibc headers and
# libraries. Reuses the rebuilt gcc for libstdc++ / libgcc_s so that
# C++ binaries produced by clang also only reference symbols available
# in the custom glibc. compiler-rt is wired into a resource-root so
# sanitizer runtimes (libclang_rt.*.a) are found at link time; this
# mirrors what nixpkgs does internally when building llvmPackages.clang.
customClang = pkgs.wrapCCWith {
cc = customLlvmPackages.clang-unwrapped;
libc = customGlibc;
bintools = customBinutils;
gccForLibs = customGccCc;
extraPackages = [ customCompilerRt ];
extraBuildCommands = ''
rsrc="$out/resource-root"
mkdir "$rsrc"
ln -s "${customLlvmPackages.clang-unwrapped.lib}/lib/clang/${toString llvmVersion}/include" "$rsrc/include"
ln -s "${customCompilerRt.out}/lib" "$rsrc/lib"
ln -s "${customCompilerRt.out}/share" "$rsrc/share" || true
echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags
# compiler-rt ships the sanitizer/profile/xray interface headers (e.g.
# <sanitizer/lsan_interface.h>) in its `dev` output. In a normal Nix
# build these reach the include path because compiler-rt is propagated
# via depsTargetTargetPropagated and stdenv's setup hooks add its
# dev/include. The CI image runs clang outside a Nix stdenv (binaries
# on PATH, no setup hooks), so that never happens; add the headers
# explicitly. gcc ships its own copy, which is why this is clang-only.
echo "-isystem ${customCompilerRt.dev}/include" >> $out/nix-support/cc-cflags
'';
};
# Custom-glibc toolchain, shared with the Linux dev shell (see compilers.nix).
inherit (import ./compilers.nix { inherit pkgs customGlibc; })
customGcc
customClang
customBinutils
customGcov
;
# Strip the generic cc/c++/cpp symlinks from the clang wrapper so it can
# coexist with the gcc wrapper in buildEnv. gcc remains the default

117
nix/compilers.nix Normal file
View File

@@ -0,0 +1,117 @@
# Custom-glibc compiler toolchain shared by the CI environment (ci-env.nix) and
# the Linux dev shell (devshell.nix): gcc / clang / binutils rebuilt to target
# the pinned custom glibc. Linux only — the pinned glibc snapshot does not build
# on darwin, so callers must not evaluate this on macOS.
{
pkgs,
customGlibc,
}:
let
inherit (import ./packages.nix { inherit pkgs; })
gccPackage
llvmPackages
llvmVersion
mkGcov
;
# binutils wrapped to emit binaries that reference the custom glibc
# (dynamic linker path, library search path, RPATH).
customBinutils = pkgs.wrapBintoolsWith {
bintools = pkgs.binutils-unwrapped;
libc = customGlibc;
};
# Rebuild gcc (specifically libstdc++ / libgcc_s) against the custom
# glibc. The override swaps gcc.cc's bootstrap stdenv for one that uses
# the existing gcc binary but links against the custom glibc, so the
# resulting compiler ships runtime libraries that only reference symbols
# available in that glibc.
customGccCc = gccPackage.cc.override {
stdenv = pkgs.stdenvAdapters.overrideCC pkgs.stdenv (
pkgs.wrapCCWith {
cc = gccPackage.cc;
libc = customGlibc;
bintools = customBinutils;
}
);
};
# cc-wrapper around the rebuilt compiler, pointing at the custom glibc
# headers and libraries. This is what we actually expose to users.
customGcc = pkgs.wrapCCWith {
cc = customGccCc;
libc = customGlibc;
bintools = customBinutils;
};
# gcov matching the rebuilt gcc (linked against the custom glibc), so gcovr
# can produce coverage reports both in CI and in the dev shell.
customGcov = mkGcov {
name = "custom";
cc = customGccCc;
};
# stdenv built around the rebuilt gcc / custom glibc. Exported as the dev
# shell's gcc stdenv, and used below to rebuild compiler-rt so its sanitizer
# runtimes see the custom glibc headers.
customStdenv = pkgs.stdenvAdapters.overrideCC pkgs.stdenv customGcc;
# Rebuild compiler-rt against the custom glibc so the sanitizer runtimes
# don't use glibc symbols (or sysconf constants like _SC_SIGSTKSZ) that
# only exist in newer glibc versions. scudo is dropped because its CMake
# includes CheckAtomic with -nostdinc++ in CMAKE_REQUIRED_FLAGS, which
# makes std::atomic unfindable in our stdenv; we don't use scudo (only
# asan/ubsan/tsan etc.).
customCompilerRt =
(llvmPackages.compiler-rt.override {
stdenv = customStdenv;
}).overrideAttrs
(old: {
postPatch = (old.postPatch or "") + ''
substituteInPlace lib/CMakeLists.txt \
--replace-quiet 'add_subdirectory(scudo/standalone)' \
'# scudo/standalone disabled in xrpld ci-env'
'';
});
# cc-wrapper around clang, pointing at the custom glibc headers and
# libraries. Reuses the rebuilt gcc for libstdc++ / libgcc_s so that
# C++ binaries produced by clang also only reference symbols available
# in the custom glibc. compiler-rt is wired into a resource-root so
# sanitizer runtimes (libclang_rt.*.a) are found at link time; this
# mirrors what nixpkgs does internally when building llvmPackages.clang.
customClang = pkgs.wrapCCWith {
cc = llvmPackages.clang-unwrapped;
libc = customGlibc;
bintools = customBinutils;
gccForLibs = customGccCc;
extraPackages = [ customCompilerRt ];
extraBuildCommands = ''
rsrc="$out/resource-root"
mkdir "$rsrc"
ln -s "${llvmPackages.clang-unwrapped.lib}/lib/clang/${toString llvmVersion}/include" "$rsrc/include"
ln -s "${customCompilerRt.out}/lib" "$rsrc/lib"
ln -s "${customCompilerRt.out}/share" "$rsrc/share" || true
echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags
# compiler-rt ships the sanitizer/profile/xray interface headers (e.g.
# <sanitizer/lsan_interface.h>) in its `dev` output. In a normal Nix
# build these reach the include path because compiler-rt is propagated
# via depsTargetTargetPropagated and stdenv's setup hooks add its
# dev/include. The CI image runs clang outside a Nix stdenv (binaries
# on PATH, no setup hooks), so that never happens; add the headers
# explicitly. gcc ships its own copy, which is why this is clang-only.
echo "-isystem ${customCompilerRt.dev}/include" >> $out/nix-support/cc-cflags
'';
};
in
{
inherit
customGcc
customClang
customBinutils
customStdenv
customGcov
;
customClangStdenv = pkgs.stdenvAdapters.overrideCC pkgs.stdenv customClang;
}

View File

@@ -1,27 +1,69 @@
{ pkgs, ... }:
{ pkgs, customGlibc, ... }:
let
inherit (import ./packages.nix { inherit pkgs; })
commonPackages
gccPackage
gccVersion
llvmVersion
llvmPackages
mkVersionedToolLinks
mkGcov
;
# Plain nixpkgs stdenvs — no custom glibc, unlike ci-env.nix.
gccStdenv = pkgs."gcc${toString gccVersion}Stdenv";
clangStdenv = llvmPackages.stdenv;
# Plain nixpkgs stdenvs — no custom glibc.
plainGccStdenv = pkgs."gcc${toString gccVersion}Stdenv";
plainClangStdenv = llvmPackages.stdenv;
# Custom-glibc stdenvs, matching the CI environment (see compilers.nix). The
# pinned glibc snapshot only builds on Linux, so on darwin these fall back to
# the plain stdenvs; the `if isLinux` guard keeps `customGlibc` from being
# forced (and erroring) on macOS.
customCompilers = import ./compilers.nix { inherit pkgs customGlibc; };
customGccStdenv = if pkgs.stdenv.isLinux then customCompilers.customStdenv else plainGccStdenv;
customClangStdenv =
if pkgs.stdenv.isLinux then customCompilers.customClangStdenv else plainClangStdenv;
# gcov matching each gcc shell, so `-Dcoverage=ON` builds work in the shell.
plainGcov = mkGcov {
name = "plain";
cc = gccPackage.cc;
};
customGccGcov = if pkgs.stdenv.isLinux then customCompilers.customGcov else plainGcov;
# Shown when entering a *-plain shell. These exist only on Linux (see below),
# where the stock toolchain diverges from CI.
plainWarningHook = ''
echo " WARNING: this is the stock nixpkgs toolchain and does not match CI's glibc. Prefer 'nix develop .#gcc' / '.#clang' unless you need to skip the custom-glibc build."
'';
# Tools to expose under version-suffixed names (see mkVersionedToolLinks).
gccVersionedTools = [
"gcc"
"g++"
"cpp"
];
clangVersionedTools = [
"clang"
"clang++"
];
# compilerName is the command used to print the version, or null for none.
makeShell =
{
shellName,
stdenv,
compilerName,
version ? null,
versionedTools ? [ ],
extraPackages ? [ ],
warningHook ? "",
# Opt out of PatchNixBinary.cmake retargeting binaries to the system
# loader. The plain toolchain links a newer glibc, so it must not be
# patched; the custom toolchain patches by default.
noPatchNixBinary ? false,
}:
let
compilerVersion =
compilerVersionHook =
if compilerName == null then
''echo "No compiler specified - using system compiler"''
else
@@ -36,43 +78,74 @@ let
tools = versionedTools;
});
in
(pkgs.mkShell.override { inherit stdenv; }) {
packages = commonPackages ++ versionedLinks;
shellHook = ''
echo "Welcome to xrpld development shell";
${compilerVersion}
'';
};
(pkgs.mkShell.override { inherit stdenv; }) (
{
packages = commonPackages ++ versionedLinks ++ extraPackages;
# Marks a managed dev shell, so the build (XrplSanity.cmake) can tell an
# intentional Nix toolchain from one leaked into a bare shell.
XRPL_DEVSHELL = shellName;
shellHook = ''
echo "Welcome to xrpld development shell";
${compilerVersionHook}
${warningHook}
'';
}
// pkgs.lib.optionalAttrs noPatchNixBinary { XRPLD_NO_PATCH_NIX_BINARY = "1"; }
);
in
rec {
# macOS: Nix Clang. Linux: Nix GCC.
default = if pkgs.stdenv.isDarwin then clang else gcc;
# gcc/clang use the custom-glibc toolchain, matching CI. On darwin there is no
# custom glibc, so they fall back to the plain nixpkgs toolchain.
gcc = makeShell {
stdenv = gccStdenv;
shellName = "gcc";
stdenv = customGccStdenv;
compilerName = "gcc";
version = gccVersion;
versionedTools = [
"gcc"
"g++"
"cpp"
];
versionedTools = gccVersionedTools;
extraPackages = [ customGccGcov ];
};
clang = makeShell {
stdenv = clangStdenv;
shellName = "clang";
stdenv = customClangStdenv;
compilerName = "clang";
version = llvmVersion;
versionedTools = [
"clang"
"clang++"
];
versionedTools = clangVersionedTools;
};
# Nix provides no compiler; use the one from your system (e.g. Apple Clang).
no-compiler = makeShell {
shellName = "no-compiler";
stdenv = pkgs.stdenvNoCC;
compilerName = null;
};
apple-clang = no-compiler;
}
# The *-plain shells (stock nixpkgs toolchain) exist only on Linux: on darwin
# gcc/clang are already plain, so these would be redundant and are omitted, which
# makes `nix develop .#gcc-plain` fail there rather than silently aliasing gcc.
// pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
gcc-plain = makeShell {
shellName = "gcc-plain";
stdenv = plainGccStdenv;
compilerName = "gcc";
version = gccVersion;
versionedTools = gccVersionedTools;
extraPackages = [ plainGcov ];
warningHook = plainWarningHook;
noPatchNixBinary = true;
};
clang-plain = makeShell {
shellName = "clang-plain";
stdenv = plainClangStdenv;
compilerName = "clang";
version = llvmVersion;
versionedTools = clangVersionedTools;
warningHook = plainWarningHook;
noPatchNixBinary = true;
};
}

View File

@@ -8,6 +8,7 @@ RUN mkdir -p ~/.config/nix && \
# Copy our source and setup our working dir.
COPY nix/ci-env.nix /tmp/build/nix/ci-env.nix
COPY nix/compilers.nix /tmp/build/nix/compilers.nix
COPY nix/packages.nix /tmp/build/nix/packages.nix
COPY nix/utils.nix /tmp/build/nix/utils.nix
COPY flake.nix /tmp/build/
@@ -57,7 +58,7 @@ ENV GIT_SSL_CAINFO="/nix/ci-env/etc/ssl/certs/ca-bundle.crt"
# Externally-built dynamically-linked ELF binaries hard-code the loader path
# (e.g. /lib64/ld-linux-x86-64.so.2) in their PT_INTERP header. Install it
# from the Nix store when the base image doesn't already provide one.
COPY nix/docker/loader-path.sh /tmp/loader-path.sh
COPY bin/default-loader-path.sh /tmp/loader-path.sh
RUN <<EOF
target="$(/tmp/loader-path.sh)"

View File

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

View File

@@ -16,7 +16,23 @@ let
exec ${pkgs.python3}/bin/python3 ${llvmPackages.clang-unwrapped}/bin/run-clang-tidy "$@"
'';
rustToolchain = pkgs.rust-bin.fromRustupToolchainFile ../rust-toolchain.toml;
# rust-overlay's toolchain propagates the *default* stdenv.cc onto the PATH (so
# cargo has a linker). That default may be different from the clang we pin here,
# so it shadows our clang and the build can silently use a different compiler
# version. Drop that cc from every propagation channel instead of pinning a
# replacement: the toolchain then carries no compiler and cargo just uses the
# active shell's stdenv cc. Must cover all channels — rust-overlay uses both
# propagatedBuildInputs and depsHostHostPropagated.
rustToolchainBase = pkgs.rust-bin.fromRustupToolchainFile ../rust-toolchain.toml;
rustToolchain =
let
defaultCc = pkgs.stdenv.cc; # default compiler from nixpkgs stdenv
withoutDefaultCc = builtins.filter (dep: (dep.outPath or "") != defaultCc.outPath);
in
rustToolchainBase.overrideAttrs (old: {
propagatedBuildInputs = withoutDefaultCc (old.propagatedBuildInputs or [ ]);
depsHostHostPropagated = withoutDefaultCc (old.depsHostHostPropagated or [ ]);
});
# Nix wraps its toolchain so that binaries are exposed only under unsuffixed
# names (gcc, g++, clang-tidy, ...). Several tools probe for a
@@ -48,6 +64,17 @@ let
}) tools
);
# The cc-wrapper doesn't re-export gcov, but coverage tooling (gcovr) needs a
# gcov that exactly matches the compiler. Surface it from a gcc `cc` output.
mkGcov =
{ name, cc }:
pkgs.linkFarm "gcov-${name}" [
{
name = "bin/gcov";
path = "${cc}/bin/gcov";
}
];
clangToolLinks = mkVersionedToolLinks {
name = "clang-tools";
package = clangTools;
@@ -72,6 +99,7 @@ in
gccPackage
llvmPackages
mkVersionedToolLinks
mkGcov
;
commonPackages = with pkgs; [

View File

@@ -17,7 +17,7 @@
#include <utility>
#include <vector>
namespace xrpl::NodeStore {
namespace xrpl::node_store {
namespace {
constexpr std::size_t kPoolSizes[] = {1000, 10000, 100000};
@@ -326,4 +326,4 @@ registerStoreBatch(BackendConfig const& bc)
}();
} // namespace
} // namespace xrpl::NodeStore
} // namespace xrpl::node_store

View File

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

View File

@@ -32,7 +32,7 @@
// Shared helpers for the NodeStore benchmarks.
//
namespace xrpl::NodeStore {
namespace xrpl::node_store {
// Fill `bytes` of memory at `buffer` with random bits drawn from `g`.
template <class Generator>
@@ -315,4 +315,4 @@ backendConfigs()
return kConfigs;
}
} // namespace xrpl::NodeStore
} // namespace xrpl::node_store

View File

@@ -1,10 +1,9 @@
#include <xrpld/consensus/Consensus.h>
#include <xrpld/consensus/ConsensusParms.h>
#include <xrpld/consensus/ConsensusTypes.h>
#include <xrpl/consensus/Consensus.h>
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/consensus/ConsensusParms.h>
#include <xrpl/consensus/ConsensusTypes.h>
#include <algorithm>
#include <chrono>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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