Compare commits

..

4 Commits

Author SHA1 Message Date
Bart
58e3f62090 perf: Serialize nodes without copying 2026-06-06 09:36:33 -04:00
Ayaz Salikhov
949887feb9 build: Create single test binary xrpl_tests (#7327) 2026-06-05 19:24:32 +00:00
dependabot[bot]
fc57dab78b ci: [DEPENDABOT] bump actions/checkout from 6.0.2 to 6.0.3 (#7414)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-05 17:17:47 +00:00
Ayaz Salikhov
63ffdc39dc ci: Refactor build-related nix / docker / workflows (#7408) 2026-06-05 17:05:19 +00:00
43 changed files with 397 additions and 306 deletions

View File

@@ -11,9 +11,6 @@ endfunction()
function(create_symbolic_link target link)
endfunction()
function(xrpl_add_test name)
endfunction()
macro(exclude_from_default target_)
endmacro()

View File

@@ -43,9 +43,6 @@ pushd "${DIRECTORY}"
# Rename the files.
find cmake -type f -name 'Rippled*.cmake' -exec bash -c 'mv "${1}" "${1/Rippled/Xrpl}"' - {} \;
find cmake -type f -name 'Ripple*.cmake' -exec bash -c 'mv "${1}" "${1/Ripple/Xrpl}"' - {} \;
if [ -e cmake/xrpl_add_test.cmake ]; then
mv cmake/xrpl_add_test.cmake cmake/XrplAddTest.cmake
fi
if [ -e include/xrpl/proto/ripple.proto ]; then
mv include/xrpl/proto/ripple.proto include/xrpl/proto/xrpl.proto
fi
@@ -60,7 +57,6 @@ find cmake -type f -name '*.cmake' | while read -r FILE; do
done
${SED_COMMAND} -i -E 's/Rippled?/Xrpl/g' CMakeLists.txt
${SED_COMMAND} -i 's/ripple/xrpl/g' CMakeLists.txt
${SED_COMMAND} -i 's/include(xrpl_add_test)/include(XrplAddTest)/' src/tests/libxrpl/CMakeLists.txt
${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' include/xrpl/protocol/messages.h
${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' BUILD.md
${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' BUILD.md

View File

@@ -1,5 +1,5 @@
{
"image_tag": "sha-6c54342",
"image_tag": "sha-8abe82e",
"configs": {
"ubuntu": [
{

View File

@@ -1,109 +0,0 @@
name: Build Nix Docker image
on:
push:
branches:
- develop
paths:
- ".github/workflows/build-nix-image.yml"
- ".github/workflows/reusable-build-docker-image.yml"
- "docker/**"
- "flake.nix"
- "flake.lock"
- "nix/**"
pull_request:
paths:
- ".github/workflows/build-nix-image.yml"
- ".github/workflows/reusable-build-docker-image.yml"
- "docker/**"
- "flake.nix"
- "flake.lock"
- "nix/**"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
jobs:
build:
name: Build ${{ matrix.distro.name }} (${{ matrix.target.platform }})
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
# The base images are the oldest supported version of each distro
# that we want to build images for.
distro:
- name: nixos
base_image: nixos/nix:latest
- name: ubuntu
base_image: ubuntu:20.04
- name: rhel
base_image: registry.access.redhat.com/ubi9/ubi:latest
- name: debian
base_image: debian:bookworm
target:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
uses: ./.github/workflows/reusable-build-docker-image.yml
with:
image_name: ghcr.io/xrplf/xrpld/nix-${{ matrix.distro.name }}
dockerfile: docker/nix.Dockerfile
base_image: ${{ matrix.distro.base_image }}
platform: ${{ matrix.target.platform }}
runner: ${{ matrix.target.runner }}
push: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' }}
merge:
name: Merge ${{ matrix.distro }} manifest
needs: build
if: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' }}
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
distro: [nixos, ubuntu, rhel, debian]
env:
IMAGE_NAME: ghcr.io/xrplf/xrpld/nix-${{ matrix.distro }}
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: Docker metadata
id: meta
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=sha-,format=short
type=raw,value=latest
- name: Login to GitHub Container Registry
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create multi-arch manifests
run: |
for tag in $(jq -cr '.tags[]' <<<"$DOCKER_METADATA_OUTPUT_JSON"); do
docker buildx imagetools create -t "$tag" "${tag}-amd64" "${tag}-arm64"
done
- name: Inspect image
run: |
docker buildx imagetools inspect "${IMAGE_NAME}:${{ steps.meta.outputs.version }}"

56
.github/workflows/build-nix-images.yml vendored Normal file
View File

@@ -0,0 +1,56 @@
name: Build Nix Docker images
on:
push:
branches:
- develop
paths:
- ".github/workflows/build-nix-images.yml"
- ".github/workflows/reusable-build-docker-image.yml"
- ".github/workflows/reusable-build-merge-docker-images.yml"
- "flake.nix"
- "flake.lock"
- "nix/**"
pull_request:
paths:
- ".github/workflows/build-nix-images.yml"
- ".github/workflows/reusable-build-docker-image.yml"
- ".github/workflows/reusable-build-merge-docker-images.yml"
- "flake.nix"
- "flake.lock"
- "nix/**"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
jobs:
build-merge:
name: Build and push nix-${{ matrix.distro.name }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
# The base images are the oldest supported version of each distro
# that we want to build images for.
distro:
- name: nixos
base_image: nixos/nix:latest
- name: ubuntu
base_image: ubuntu:20.04
- name: debian
base_image: debian:bookworm
- name: rhel
base_image: registry.access.redhat.com/ubi9/ubi:latest
uses: ./.github/workflows/reusable-build-merge-docker-images.yml
with:
image_name: ghcr.io/xrplf/xrpld/nix-${{ matrix.distro.name }}
dockerfile: nix/docker/Dockerfile
base_image: ${{ matrix.distro.base_image }}

View File

@@ -0,0 +1,48 @@
name: Build packaging Docker images
on:
push:
branches:
- develop
paths:
- ".github/workflows/build-packaging-images.yml"
- ".github/workflows/reusable-build-docker-image.yml"
- ".github/workflows/reusable-build-merge-docker-images.yml"
- "package/Dockerfile"
- "package/install-packaging-tools.sh"
pull_request:
paths:
- ".github/workflows/build-packaging-images.yml"
- ".github/workflows/reusable-build-docker-image.yml"
- ".github/workflows/reusable-build-merge-docker-images.yml"
- "package/Dockerfile"
- "package/install-packaging-tools.sh"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
jobs:
build-merge:
name: Build and push packaging-${{ matrix.distro.name }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
distro:
- name: debian
base_image: debian:bookworm
- name: rhel
base_image: registry.access.redhat.com/ubi9/ubi:latest
uses: ./.github/workflows/reusable-build-merge-docker-images.yml
with:
image_name: ghcr.io/xrplf/xrpld/packaging-${{ matrix.distro.name }}
dockerfile: package/Dockerfile
base_image: ${{ matrix.distro.base_image }}

View File

@@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Write PR body to file
env:

View File

@@ -33,7 +33,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- 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

View File

@@ -41,10 +41,10 @@ env:
jobs:
build:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/ci/tools-rippled-documentation:sha-a8c7be1
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-8abe82e
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab
@@ -57,19 +57,11 @@ jobs:
with:
subtract: ${{ env.NPROC_SUBTRACT }}
- name: Check configuration
run: |
echo 'Checking path.'
echo ${PATH} | tr ':' '\n'
- name: Print build environment
uses: XRPLF/actions/print-build-env@59dec886e4afb05a1724443af08baccbc045b574
echo 'Checking environment variables.'
env | sort
echo 'Checking CMake version.'
cmake --version
echo 'Checking Doxygen version.'
doxygen --version
- name: Check Doxygen version
run: doxygen --version
- name: Build documentation
env:

View File

@@ -38,7 +38,7 @@ defaults:
jobs:
build:
name: Build (${{ inputs.platform }})
name: Build ${{ inputs.platform }}
runs-on: ${{ inputs.runner }}
permissions:
contents: read
@@ -46,7 +46,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Determine arch
id: vars

View File

@@ -0,0 +1,89 @@
name: Reusable build and merge Docker image (multi-arch)
on:
workflow_call:
inputs:
image_name:
description: "Full image name without tag (e.g. 'ghcr.io/xrplf/xrpld/nix-ubuntu')"
required: true
type: string
dockerfile:
description: "Path to the Dockerfile, relative to the repository root"
required: true
type: string
base_image:
description: "Value passed to the Dockerfile as the BASE_IMAGE build arg"
required: true
type: string
defaults:
run:
shell: bash
jobs:
build:
name: Build ${{ inputs.image_name }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
target:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
uses: ./.github/workflows/reusable-build-docker-image.yml
with:
image_name: ${{ inputs.image_name }}
dockerfile: ${{ inputs.dockerfile }}
base_image: ${{ inputs.base_image }}
platform: ${{ matrix.target.platform }}
runner: ${{ matrix.target.runner }}
push: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' }}
merge:
name: Merge ${{ inputs.image_name }}
needs: build
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: Docker metadata
id: meta
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
with:
images: ${{ inputs.image_name }}
tags: |
type=sha,prefix=sha-,format=short
type=raw,value=latest
- name: Login to GitHub Container Registry
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create multi-arch manifests
if: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' }}
run: |
for tag in $(jq -cr '.tags[]' <<<"$DOCKER_METADATA_OUTPUT_JSON"); do
docker buildx imagetools create -t "$tag" "${tag}-amd64" "${tag}-arm64"
done
- name: Inspect image
if: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' }}
env:
IMAGE_NAME: ${{ inputs.image_name }}
IMAGE_VERSION: ${{ steps.meta.outputs.version }}
run: |
docker buildx imagetools inspect "${IMAGE_NAME}:${IMAGE_VERSION}"

View File

@@ -110,7 +110,7 @@ jobs:
uses: XRPLF/actions/cleanup-workspace@c7d9ce5ebb03c752a354889ecd870cadfc2b1cd4
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab
@@ -236,6 +236,15 @@ jobs:
retention-days: 3
if-no-files-found: error
- name: Upload the test binary (Linux)
if: ${{ github.event.repository.visibility == 'public' && runner.os == 'Linux' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: xrpl_tests-${{ inputs.config_name }}
path: ${{ env.BUILD_DIR }}/xrpl_tests
retention-days: 3
if-no-files-found: error
- name: Export server definitions
if: ${{ runner.os != 'Windows' && !inputs.build_only && env.VOIDSTAR_ENABLED != 'true' }}
working-directory: ${{ env.BUILD_DIR }}
@@ -286,16 +295,8 @@ jobs:
- name: Run the separate tests
if: ${{ !inputs.build_only }}
working-directory: ${{ env.BUILD_DIR }}
# Windows locks some of the build files while running tests, and parallel jobs can collide
env:
BUILD_TYPE: ${{ inputs.build_type }}
PARALLELISM: ${{ runner.os == 'Windows' && '1' || steps.nproc.outputs.nproc }}
run: |
ctest \
--output-on-failure \
-C "${BUILD_TYPE}" \
-j "${PARALLELISM}"
working-directory: ${{ runner.os == 'Windows' && format('{0}/{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }}
run: ./xrpl_tests
- name: Run the embedded tests
if: ${{ !inputs.build_only }}

View File

@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Check definitions
run: .github/scripts/rename/definitions.sh .
- name: Check copyright notices

View File

@@ -42,7 +42,7 @@ jobs:
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab

View File

@@ -27,7 +27,7 @@ jobs:
matrix: ${{ steps.generate.outputs.matrix }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
@@ -45,7 +45,7 @@ jobs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout: |
.github/actions/generate-version
@@ -94,7 +94,7 @@ jobs:
systemd-rpm-macros
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0

View File

@@ -40,10 +40,10 @@ defaults:
jobs:
upload:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/ci/ubuntu-noble:gcc-13-sha-5dd7158
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-8abe82e
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Generate build version number
id: version

View File

@@ -64,7 +64,7 @@ jobs:
uses: XRPLF/actions/cleanup-workspace@c7d9ce5ebb03c752a354889ecd870cadfc2b1cd4
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab

View File

@@ -1,22 +0,0 @@
include(isolate_headers)
function(xrpl_add_test name)
set(target ${PROJECT_NAME}.test.${name})
file(
GLOB_RECURSE sources
CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/${name}.cpp"
)
add_executable(${target} ${ARGN} ${sources})
isolate_headers(
${target}
"${CMAKE_SOURCE_DIR}"
"${CMAKE_SOURCE_DIR}/tests/${name}"
PRIVATE
)
add_test(NAME ${target} COMMAND ${target})
endfunction()

View File

@@ -47,7 +47,7 @@ setup_target_for_coverage_gcovr(
"include/xrpl/beast/test"
"include/xrpl/beast/unit_test"
"${CMAKE_BINARY_DIR}/pb-xrpl.libpb"
DEPENDENCIES xrpld xrpl.tests
DEPENDENCIES xrpld xrpl_tests
)
add_code_coverage_to_target(opts INTERFACE)

View File

@@ -56,7 +56,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 docker/loader-path.sh /tmp/loader-path.sh
COPY nix/docker/loader-path.sh /tmp/loader-path.sh
RUN <<EOF
target="$(/tmp/loader-path.sh)"
@@ -71,12 +71,12 @@ if [ ! -e "${target}" ]; then
fi
EOF
COPY docker/check-tools.sh /tmp/check-tools.sh
COPY nix/docker/check-tools.sh /tmp/check-tools.sh
RUN /tmp/check-tools.sh
# Sanity-check that the g++/clang++ are able to build binaries, including sanitizer-instrumented ones.
COPY docker/test_files/cpp_sources/ /tmp/cpp_sources/
COPY docker/test_files/compile-cpp-sources.sh /tmp/compile-cpp-sources.sh
COPY nix/docker/test_files/cpp_sources/ /tmp/cpp_sources/
COPY nix/docker/test_files/compile-cpp-sources.sh /tmp/compile-cpp-sources.sh
RUN /tmp/compile-cpp-sources.sh /tmp/cpp_sources /tmp/bins
# Tester: start from a clean BASE_IMAGE, install sanitizer runtime libraries,
@@ -93,8 +93,8 @@ RUN if echo "${BASE_IMAGE}" | grep -qiE 'nixos'; then \
SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"]
# Sanity-check that the built binaries run correctly in the vanilla base image, with the necessary sanitizer runtime libraries installed.
COPY docker/install-sanitizer-libs.sh /tmp/install-sanitizer-libs.sh
COPY docker/test_files/run-test-binaries.sh /tmp/run-test-binaries.sh
COPY nix/docker/install-sanitizer-libs.sh /tmp/install-sanitizer-libs.sh
COPY nix/docker/test_files/run-test-binaries.sh /tmp/run-test-binaries.sh
COPY --from=final /tmp/bins /tmp/bins
RUN <<EOF

14
package/Dockerfile Normal file
View File

@@ -0,0 +1,14 @@
ARG BASE_IMAGE=debian:bookworm
FROM ${BASE_IMAGE}
# Packaging runs in a vanilla distro image, so the tooling has to come
# from the distro's archive: debhelper for deb, rpm-build (and the
# systemd / find-debuginfo macros it depends on) for rpm.
# The container also uses git (real history) for
# build_pkg.sh's SOURCE_DATE_EPOCH; otherwise it falls back to a tarball
# download and the timestamp comes from wall-clock time.
COPY package/install-packaging-tools.sh /tmp/install-packaging-tools.sh
RUN /tmp/install-packaging-tools.sh

View File

@@ -22,25 +22,24 @@ package/
Packaging targets and their container images are declared in
[`.github/scripts/strategy-matrix/linux.json`](../.github/scripts/strategy-matrix/linux.json)
via a `"package": true` field on specific os entries. Today only
`linux/amd64` is emitted; the architecture is hardcoded in `generate.py`
and the workflow runner. The package format
inside `package_configs` configurations. Today only
`linux/amd64` is emitted. The package format
(deb or rpm) is inferred at build time from the container's package manager
(`apt-get` -> deb, `dnf`/`yum` -> rpm). The image tag is composed as
`ghcr.io/xrplf/ci/{distro}-{version}:{compiler}-{cver}-sha-{image_sha}`
`ghcr.io/xrplf/xrpld/packaging-<distro>:sha-<git_sha>`
the same scheme used by `reusable-build-test.yml`. Bump `image_sha` in
`linux.json` and both CI and local builds pick up the new image with no
workflow edits.
| Package type | Image (derived from `linux.json`) | Tool required |
| ------------ | ---------------------------------------------------- | --------------------------------------------------------------- |
| RPM | `ghcr.io/xrplf/ci/rhel-9:gcc-12-sha-<git_sha>` | `rpmbuild` |
| DEB | `ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12-sha-<git_sha>` | `dpkg-buildpackage`, `debhelper (>= 13)`, `dh-sequence-systemd` |
| RPM | `ghcr.io/xrplf/xrpld/packaging-rhel:sha-<git_sha>` | `rpmbuild` |
| DEB | `ghcr.io/xrplf/xrpld/packaging-debian:sha-<git_sha>` | `dpkg-buildpackage`, `debhelper (>= 13)`, `dh-sequence-systemd` |
To print the exact image tags for the current `linux.json`:
```bash
./.github/scripts/strategy-matrix/generate.py --packaging --config=.github/scripts/strategy-matrix/linux.json
./.github/scripts/strategy-matrix/generate.py --packaging
```
## Building packages

View File

@@ -0,0 +1,68 @@
#!/bin/bash
set -euo pipefail
if [ ! -f /etc/os-release ]; then
echo "ERROR: /etc/os-release not found; cannot detect OS" >&2
exit 1
fi
# shellcheck source=/dev/null
. /etc/os-release
echo "Detected OS: ${ID} ${VERSION_ID:-}"
case "${ID}" in
ubuntu | debian | rhel | centos | rocky | almalinux)
echo "Supported OS detected: ${ID}"
;;
*)
echo "ERROR: unsupported OS '${ID}'. Supported: debian, ubuntu, rhel-family" >&2
exit 1
;;
esac
function install() {
case "${ID}" in
debian | ubuntu)
apt-get update -y
apt-get install -y --no-install-recommends \
ca-certificates \
debhelper \
debhelper-compat \
dpkg-dev \
git
;;
rhel | centos | rocky | almalinux)
dnf install -y --setopt=install_weak_deps=False \
git \
rpm-build \
redhat-rpm-config \
systemd-rpm-macros
;;
esac
}
function postinstall() {
# Don't clear cache in non-CI environments
if [ -z "${CI:-}" ]; then
echo "Not running in CI environment; skipping cache cleanup"
return
fi
case "${ID}" in
debian | ubuntu)
apt-get clean
rm -rf /var/lib/apt/lists/*
;;
rhel | centos | rocky | almalinux)
dnf clean -y all
rm -rf /var/cache/dnf/*
;;
esac
}
install
postinstall

View File

@@ -1250,30 +1250,16 @@ hasInvalidAmount(STBase const& field, int depth, beast::Journal j)
return true;
}
// Dispatch on the serialized type tag rather than RTTI: this is on the invariant-checking path
// and a dynamic_cast chain over every field of every modified entry is measurably expensive.
// The object-like tags below all denote STObject subclasses (STLedgerEntry, STTx), so the
// downcast is sound; nested fields are only ever plain STI_OBJECT / STI_ARRAY containers.
// safeDowncast keeps a dynamic_cast validity assert in debug builds while compiling to
// static_cast in release.
switch (field.getSType())
{
case STI_AMOUNT: {
auto const& amount = safeDowncast<STAmount const&>(field);
return !isLegalMPT(amount) || !isLegalNet(amount);
}
if (auto const amount = dynamic_cast<STAmount const*>(&field))
return !isLegalMPT(*amount) || !isLegalNet(*amount);
case STI_OBJECT:
case STI_LEDGERENTRY:
case STI_TRANSACTION:
return hasInvalidAmount(safeDowncast<STObject const&>(field), depth + 1, j);
if (auto const object = dynamic_cast<STObject const*>(&field))
return hasInvalidAmount(*object, depth + 1, j);
case STI_ARRAY:
return hasInvalidAmount(safeDowncast<STArray const&>(field), depth + 1, j);
if (auto const array = dynamic_cast<STArray const*>(&field))
return hasInvalidAmount(*array, depth + 1, j);
default:
return false;
}
return false;
}
bool

View File

@@ -449,17 +449,16 @@ SHAMap::getNodeFat(
std::stack<std::tuple<SHAMapTreeNode*, SHAMapNodeID, int>> stack;
stack.emplace(node, nodeID, depth);
Serializer s(8192);
while (!stack.empty())
{
std::tie(node, nodeID, depth) = stack.top();
stack.pop();
// Add this node to the reply
s.erase();
// Use a fresh Serializer per node and move its buffer into `data` rather than copying it
// via Serializer::getData(): the move is O(1) whereas the copy was O(node size).
Serializer s(256);
node->serializeForWire(s);
data.emplace_back(nodeID, s.getData());
data.emplace_back(nodeID, std::move(s.modData()));
if (node->isInner())
{
@@ -487,9 +486,9 @@ SHAMap::getNodeFat(
else if (childNode->isInner() || fatLeaves)
{
// Just include this node
s.erase();
childNode->serializeForWire(s);
data.emplace_back(childID, s.getData());
Serializer cs(256);
childNode->serializeForWire(cs);
data.emplace_back(childID, std::move(cs.modData()));
}
}
}

View File

@@ -1172,17 +1172,21 @@ Transactor::checkTransactionInvariants(TER result, XRPAmount fee)
[[nodiscard]] TER
Transactor::checkInvariants(TER result, XRPAmount fee)
{
/*
* DISABLED for 3.2.0 — Must be re-introduced for 3.3.0
*
* Transaction invariants are disabled due to a performance regression:
* the two-pass design (transaction-specific invariants + protocol invariants)
* iterates over modified ledger entries twice per transaction.
*
* Until resolved, only protocol invariants are checked (delegated to ctx_).
* This is safe because all transaction invariants in 3.2.0 are no-ops.
*/
return ctx_.checkInvariants(result, fee);
// Transaction invariants first (more specific). These check post-conditions of the specific
// transaction. If these fail, the transaction's core logic is wrong.
auto const txResult = checkTransactionInvariants(result, fee);
// Protocol invariants second (broader). These check properties that must hold regardless of
// transaction type.
auto const protoResult = ctx_.checkInvariants(result, fee);
// Fail if either check failed. tef (fatal) takes priority over tec.
if (protoResult == tefINVARIANT_FAILED)
return tefINVARIANT_FAILED;
if (txResult == tecINVARIANT_FAILED || protoResult == tecINVARIANT_FAILED)
return tecINVARIANT_FAILED;
return result;
}
//------------------------------------------------------------------------------
ApplyResult

View File

@@ -1,51 +1,56 @@
include(XrplAddTest)
include(GoogleTest)
include(isolate_headers)
# Test requirements.
find_package(GTest REQUIRED)
# Custom target for all tests defined in this file
add_custom_target(xrpl.tests)
# Test helpers
add_library(xrpl.helpers.test STATIC)
target_sources(
xrpl.helpers.test
PRIVATE helpers/Account.cpp helpers/TestSink.cpp helpers/TxTest.cpp
# Single combined gtest binary built from the shared test helpers and all test
# modules below.
add_executable(
xrpl_tests
main.cpp
helpers/Account.cpp
helpers/TestSink.cpp
helpers/TxTest.cpp
)
target_include_directories(xrpl.helpers.test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(xrpl.helpers.test PUBLIC xrpl.libxrpl gtest::gtest)
# Common library dependencies for the rest of the tests.
add_library(xrpl.imports.test INTERFACE)
target_link_libraries(
xrpl.imports.test
INTERFACE gtest::gtest xrpl.libxrpl xrpl.helpers.test
set_target_properties(
xrpl_tests
PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
)
# Lets test sources include the shared helpers as <helpers/...>.
target_include_directories(xrpl_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(xrpl_tests PRIVATE GTest::gtest xrpl.libxrpl)
# One test for each module.
xrpl_add_test(basics)
target_link_libraries(xrpl.test.basics PRIVATE xrpl.imports.test)
add_dependencies(xrpl.tests xrpl.test.basics)
xrpl_add_test(crypto)
target_link_libraries(xrpl.test.crypto PRIVATE xrpl.imports.test)
add_dependencies(xrpl.tests xrpl.test.crypto)
xrpl_add_test(json)
target_link_libraries(xrpl.test.json PRIVATE xrpl.imports.test)
add_dependencies(xrpl.tests xrpl.test.json)
xrpl_add_test(tx)
target_link_libraries(xrpl.test.tx PRIVATE xrpl.imports.test)
add_dependencies(xrpl.tests xrpl.test.tx)
xrpl_add_test(protocol_autogen)
target_link_libraries(xrpl.test.protocol_autogen PRIVATE xrpl.imports.test)
add_dependencies(xrpl.tests xrpl.test.protocol_autogen)
# Network unit tests are currently not supported on Windows
# One source subdirectory per module. Network unit tests are currently not
# supported on Windows.
set(test_modules
basics
crypto
json
tx
protocol_autogen
)
if(NOT WIN32)
xrpl_add_test(net)
target_link_libraries(xrpl.test.net PRIVATE xrpl.imports.test)
add_dependencies(xrpl.tests xrpl.test.net)
list(APPEND test_modules net)
endif()
foreach(module IN LISTS test_modules)
# Append the module's sources (${module}/*.cpp and ${module}.cpp, if any).
file(
GLOB_RECURSE sources
CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/${module}/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/${module}.cpp"
)
target_sources(xrpl_tests PRIVATE ${sources})
# Expose the module's private headers under their canonical include path.
isolate_headers(
xrpl_tests
"${CMAKE_SOURCE_DIR}"
"${CMAKE_SOURCE_DIR}/tests/${module}"
PRIVATE
)
endforeach()
gtest_discover_tests(xrpl_tests)

View File

@@ -1,8 +0,0 @@
#include <gtest/gtest.h>
int
main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -1,8 +0,0 @@
#include <gtest/gtest.h>
int
main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -1,8 +0,0 @@
#include <gtest/gtest.h>
int
main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -1,8 +0,0 @@
#include <gtest/gtest.h>
int
main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}