From 04702a1d03edfab9bf0bfc912ddcea95a8691362 Mon Sep 17 00:00:00 2001 From: Luis Schwab Date: Mon, 14 Sep 2026 15:58:55 -0300 Subject: [PATCH 1/7] chore(ci): bump cargo-rbmt to v0.5.3 * Centralize the `cargo-rbmt` version in Cargo.toml and remove the `rbmt-version` file. * Update CI setup and workflow metadata for cargo-rbmt@0.5.3 --- .github/actions/setup-rbmt/action.yml | 13 +++++++------ .github/workflows/audit.yml | 3 +++ .github/workflows/bench.yml | 14 ++++++++------ .github/workflows/rust.yml | 21 +++++++++++++-------- Cargo.toml | 8 ++++---- rbmt-version | 1 - 6 files changed, 35 insertions(+), 25 deletions(-) delete mode 100644 rbmt-version diff --git a/.github/actions/setup-rbmt/action.yml b/.github/actions/setup-rbmt/action.yml index 863f38c..1478563 100644 --- a/.github/actions/setup-rbmt/action.yml +++ b/.github/actions/setup-rbmt/action.yml @@ -1,20 +1,21 @@ name: Setup cargo-rbmt -description: Install cargo-rbmt +description: Install cargo-rbmt from crates.io runs: - using: "composite" + using: composite steps: - name: Install cargo-rbmt shell: bash run: | - RBMT_VERSION=$(cat rbmt-version) - cargo install cargo-rbmt --version "$RBMT_VERSION" --locked + RBMT_VERSION=$(grep -A 1 '^\[package\.metadata\.rbmt\]$' Cargo.toml | grep -E -o '[0-9]+([.][0-9]+)*') + echo "Installing cargo-rbmt@v${RBMT_VERSION} from crates.io" + cargo install cargo-rbmt --version "$RBMT_VERSION" --locked - - name: Install Rust Toolchains + - name: Install Toolchains shell: bash run: cargo rbmt toolchains - - name: Intall cargo-rbmt Tools + - name: Install Tools shell: bash run: cargo rbmt tools diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 9d1b1c8..087de24 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 + name: Audit on: @@ -10,6 +12,7 @@ on: permissions: {} env: CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 jobs: audit: diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index da10d6a..bc35ba3 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -1,4 +1,6 @@ -name: Performance Benchmark +# SPDX-License-Identifier: MIT OR Apache-2.0 + +name: Benchmark on: push: @@ -14,24 +16,24 @@ env: jobs: benchmark: - name: Run Performance Benchmarks + name: Run Benchmarks runs-on: ubuntu-latest permissions: contents: read steps: - - name: Checkout repository + - name: Checkout Repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - - name: Setup build cache + - name: Setup Rust Cache uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - name: Setup cargo-rbmt uses: $/.github/actions/setup-rbmt - - name: Display system and commit information + - name: Display System and Commit Information env: BRANCH_REF: ${{ github.ref_name }} COMMIT_SHA: ${{ github.sha }} @@ -55,7 +57,7 @@ jobs: echo "- \`$name\`: ${slope}ns" >> $GITHUB_STEP_SUMMARY done - - name: Upload HTML reports + - name: Upload HTML Reports uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: benchmark-html-reports-${{ github.run_number }} diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 9659b5a..59b60f4 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,4 +1,6 @@ -name: Rust CI +# SPDX-License-Identifier: MIT OR Apache-2.0 + +name: Rust on: push: @@ -7,6 +9,7 @@ on: permissions: {} env: CARGO_TERM_COLOR: always + RBMT_LOG_LEVEL: progress RUST_BACKTRACE: 1 jobs: @@ -17,12 +20,12 @@ jobs: fail-fast: false matrix: include: - - name: Check Formatting + - name: Documentation + task: docs + - name: Formatting task: fmt --check - - name: Lint + - name: Linting task: lint - - name: Build Documentation - task: docsrs steps: - name: Checkout Repository @@ -30,13 +33,14 @@ jobs: with: persist-credentials: false - - name: Setup Build Cache + - name: Setup Rust Cache uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - name: Setup cargo-rbmt uses: $/.github/actions/setup-rbmt - - name: Run ${{ matrix.task }} + - name: Check ${{ matrix.name }} + shell: bash run: cargo rbmt ${{ matrix.task }} test: @@ -62,11 +66,12 @@ jobs: with: persist-credentials: false - - name: Setup Build Cache + - name: Setup Rust Cache uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - name: Setup cargo-rbmt uses: $/.github/actions/setup-rbmt - name: Run Tests + shell: bash run: cargo rbmt test --toolchain ${{ matrix.toolchain }} --lockfile ${{ matrix.lockfile }} diff --git a/Cargo.toml b/Cargo.toml index f5c6455..d5fd86b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,10 @@ edition = "2021" rust-version = "1.74.0" # MSRV autobenches = false +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + [features] default = ["std"] std = ["bitcoin_hashes/std", "hex-conservative/std", "hashbrown/default-hasher"] @@ -57,10 +61,6 @@ bumpalo = { version = "3.11.1" } # blame: criterion v0.5.1 (RUSTSEC-2022-0078) rayon = { version = "1.5.3" } # blame: criterion v0.5.1 (RUSTSEC-2022-0021, RUSTSEC-2023-0045) errno-dragonfly = { version = "0.1.2" } # blame: criterion v0.5.1 (RUSTSEC-2025-0121) -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - [package.metadata.rbmt] toolchains = { stable = "1.97.1", nightly = "nightly-2026-08-04" } tools = { cargo-audit = "=0.22.2", zizmor = "=1.30.1" } diff --git a/rbmt-version b/rbmt-version deleted file mode 100644 index 267577d..0000000 --- a/rbmt-version +++ /dev/null @@ -1 +0,0 @@ -0.4.1 From 69f9a4d34a39356be1e4541bf06919a6d3411e37 Mon Sep 17 00:00:00 2001 From: Luis Schwab Date: Mon, 14 Sep 2026 15:05:53 -0300 Subject: [PATCH 2/7] chore(ci): organize justfile recipes into groups * Organize recipes into groups * Improve `just fuzz` recipe: * `just fuzz list` * `just fuzz all` * `just fuzz ` * Use cargo-rbmt's nightly toolchain version --- README.md | 36 ++++++++----- justfile | 155 +++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 130 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index 4bf497a..5939117 100644 --- a/README.md +++ b/README.md @@ -68,18 +68,30 @@ A `justfile` is provided for convenience. Run `just` to see available commands: > A Rust implementation of Utreexo Available recipes: - bench BENCH="" # Run benchmarks: accumulator, proof, stump - check # Check code formatting, compilation, and linting [alias: c] - check-sigs # Checks whether all commits in this branch are signed [alias: cs] - doc # Generate documentation [alias: d] - doc-open # Generate and open documentation [alias: do] - fmt # Format code [alias: f] - lock # Regenerate Cargo-recent.lock and Cargo-minimal.lock [alias: l] - pre-push # Run pre-push suite: lock, fmt, check, test, and test-no-std [alias: p] - shellcheck # Run ShellCheck - test # Run tests across all toolchains and lockfiles [alias: t] - tools # Install cargo-rbmt tools - zizmor # Run Zizmor Static Analysis + [Dependencies] + lock # Generate Lockfiles [alias: l] + + [Documentation] + docs # Generate Documentation [alias: d] + docs-open # Generate and Open Documentation + + [Quality] + audit # Audit dependencies [alias: a] + check # Check Formatting, Linting and Documentation [alias: c] + check-sigs # Check Commit Signatures + fmt # Format Code [alias: f] + pre-push # Run pre-push suite: lock, fmt, check, and test [alias: p] + shellcheck # Run ShellCheck + zizmor # Run Zizmor Static Analysis + + [Setup] + setup-tools-toolchains # Setup Tools and Toolchains + update-tools-toolchains # Update Tools and Toolchains + + [Testing] + bench BENCH="" # Run Benchmarks: accumulator, proof, stump + fuzz TARGET="list" TIME="600" # Run Fuzz Targets: list, all, or TARGET + test # Run Tests [alias: t] ``` ## Minimum Supported Rust Version (MSRV) diff --git a/justfile b/justfile index a1d4034..bf26453 100644 --- a/justfile +++ b/justfile @@ -1,83 +1,140 @@ alias c := check -alias cs := check-sigs -alias d := doc -alias do := doc-open +alias a := audit +alias d := docs alias f := fmt alias l := lock alias t := test alias p := pre-push +export nightly := `cargo rbmt toolchains --nightly` +export RBMT_LOG_LEVEL := env("RBMT_LOG_LEVEL", "progress") + _default: @echo "> rustreexo" @echo "> A Rust implementation of Utreexo\n" @just --list -[doc("Run this project's fuzz targets for 10 minutes per target by default")] -fuzz TARGET="" TIME="600": - #!/usr/bin/env bash - set -euo pipefail +# Quality - if [[ -n "{{TARGET}}" ]]; then - cargo +nightly fuzz run "{{TARGET}}" -- -max_total_time={{TIME}} - else - for target in $(cargo +nightly fuzz list); do - echo "Running fuzz target: $target" - cargo +nightly fuzz run "$target" -- -max_total_time={{TIME}} - done - fi +[doc: "Audit dependencies"] +[group("Quality")] +audit: + @echo "Auditing Cargo.lock" + cargo generate-lockfile + cargo audit --file Cargo.lock -[doc: "Run benchmarks: accumulator, proof, stump"] -bench BENCH="": - cargo rbmt run bench {{ if BENCH != "" { "--bench " + BENCH } else { "" } }} + @echo "\nAuditing Cargo-recent.lock" + cargo audit --file Cargo-recent.lock + + @echo "\nAuditing Cargo-minimal.lock" + cargo audit --file Cargo-minimal.lock -[doc: "Check code formatting, compilation, and linting"] +[doc: "Check Formatting, Linting and Documentation"] +[group("Quality")] check: cargo rbmt fmt --check cargo rbmt lint - cargo rbmt docsrs + cargo rbmt docs -[doc: "Checks whether all commits in this branch are signed"] +[doc: "Check Commit Signatures"] +[group("Quality")] check-sigs: bash contrib/check-commit-signatures.sh -[doc: "Generate documentation"] -doc: - cargo rbmt docsrs - -[doc: "Generate and open documentation"] -doc-open: - cargo rbmt docsrs --open - -[doc: "Format code"] +[doc: "Format Code"] +[group("Quality")] fmt: cargo rbmt fmt -[doc: "Regenerate Cargo-recent.lock and Cargo-minimal.lock"] -lock: - cargo rbmt lock - -[doc: "Run tests across all toolchains and lockfiles"] -test: - cargo rbmt test --toolchain stable --lockfile recent - cargo rbmt test --toolchain stable --lockfile minimal - -[doc: "Setup cargo-rbmt tools"] -setup-tools: - RBMT_LOG_LEVEL=progress cargo rbmt tools +[doc: "Run pre-push suite: lock, fmt, check, and test"] +[group("Quality")] +pre-push: + @just check-sigs + @just lock + @just fmt + @just check + @just test + @just shellcheck + @just zizmor [doc: "Run ShellCheck"] +[group("Quality")] shellcheck: @command -v shellcheck >/dev/null 2>&1 || { echo "shellcheck was not found on \$PATH" && exit 1; } find . -name '*.sh' -print -exec shellcheck {} + [doc: "Run Zizmor Static Analysis"] +[group("Quality")] zizmor: zizmor . -[doc: "Run pre-push suite: lock, fmt, check, and test"] -pre-push: - @just check-sigs - @just lock - @just fmt - @just check - @just test +# Documentation + +[doc: "Generate Documentation"] +[group("Documentation")] +docs: + cargo rbmt docs + +[doc: "Generate and Open Documentation"] +[group("Documentation")] +docs-open: + cargo rbmt docs --open + +# Testing + +[doc: "Run Benchmarks: accumulator, proof, stump"] +[group("Testing")] +bench BENCH="": + cargo rbmt run bench {{ if BENCH != "" { "--bench " + BENCH } else { "" } }} + +[doc: "Run Fuzz Targets: list, all, or TARGET"] +[group("Testing")] +fuzz TARGET="list" TIME="600": + #!/usr/bin/env bash + set -euo pipefail + + case "{{TARGET}}" in + list) + cargo +{{ nightly }} fuzz list + ;; + all) + targets=$(cargo +{{ nightly }} fuzz list) + for target in $targets; do + echo "Fuzzing Target: $target" + cargo +{{ nightly }} fuzz run "$target" -- -max_total_time={{TIME}} + done + ;; + *) + cargo +{{ nightly }} fuzz run "{{TARGET}}" -- -max_total_time={{TIME}} + ;; + esac + +[doc: "Run Tests"] +[env("RBMT_LOG_LEVEL", "verbose")] +[group("Testing")] +test: + cargo rbmt test --toolchain stable --lockfile recent + cargo rbmt test --toolchain stable --lockfile minimal + cargo rbmt test --toolchain msrv --lockfile minimal + +# Dependencies + +[doc: "Generate Lockfiles"] +[group("Dependencies")] +lock: + cargo rbmt lock + +# Setup + +[doc: "Setup Tools and Toolchains"] +[group("Setup")] +setup-tools-toolchains: + cargo rbmt tools + cargo rbmt toolchains + +[doc: "Update Tools and Toolchains"] +[group("Setup")] +update-tools-toolchains: + cargo rbmt tools --update + cargo rbmt toolchains --update-stable + cargo rbmt toolchains --update-nightly From 87c1d45430943bff4f11043ec2344b0c62dc44fb Mon Sep 17 00:00:00 2001 From: Luis Schwab Date: Mon, 14 Sep 2026 15:05:53 -0300 Subject: [PATCH 3/7] fix(ci): simplify caching and run targets independently on fuzz workflow * Replace manual Rust and APT cache setup with rust-cache and corpus caching * Use the pinned nightly and cargo-fuzz installed by the shared setup action * Run a manual target matrix with readable names and per-target crash artifacts * Rename the `proof-corruption` target to remove the Cargo naming warning --- .github/workflows/fuzz.yml | 200 +++++++++++++------------------------ fuzz/Cargo.toml | 2 +- 2 files changed, 69 insertions(+), 133 deletions(-) diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 667f921..59548e6 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -1,140 +1,76 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 -name: Fuzz Tests +name: Fuzz on: - push: - pull_request: + push: + pull_request: -env: - CARGO_TERM_COLOR: always - CARGO_FUZZ_VERSION: 0.13.1 - APT_CONFIG: | - Dir::Cache "./.apt-cache"; - Dir::Cache::archives "./.apt-cache/archives"; - Dir::State "./.apt-state"; - Dir::State::lists "./.apt-state/lists/"; +permissions: + contents: read -permissions: {} +env: + CARGO_TERM_COLOR: always + CARGO_PROFILE_RELEASE_LTO: "false" + RBMT_LOG_LEVEL: progress jobs: - fuzz: - name: Run Fuzzing Tests - runs-on: ubuntu-latest - - steps: - - name: Checkout Repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: false - - - name: Install Nightly Rust Toolchain - run: | - rustup toolchain install nightly --profile minimal --no-self-update - rustup default nightly - - # Calculate cache keys - - name: Generate cache keys - run: | - YEAR=$(date +%Y) - WEEK=$(date +%U) - # Use '10#' to always treat week number as base-10 (avoids octal when number has a leading zero) - BIWEEK=$(( (10#$WEEK + 1) / 2 )) - echo "CACHE_VERSION=${YEAR}(${BIWEEK})" >> $GITHUB_ENV - - # Hash of all files that could affect the build - HASH=$(echo "${{ hashFiles('Cargo-minimal.lock', 'Cargo-recent.lock', 'Cargo.toml', '.github/workflows/**') }}") - echo "BUILD_HASH=${HASH}" >> $GITHUB_ENV - - # Hash of apt packages we need - APT_PACKAGES="build-essential cmake clang" - echo "APT_HASH=$(echo $APT_PACKAGES | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV - shell: bash - - # Restore Rust build cache - - name: Restore Rust cache - id: cache-rust - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: | - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - ~/.cargo/bin/cargo-fuzz - target/ - fuzz/target/ - key: ${{ runner.os }}-cargo-${{ env.CACHE_VERSION }}-fuzz${{ env.CARGO_FUZZ_VERSION }}-${{ env.BUILD_HASH }} - restore-keys: | - ${{ runner.os }}-cargo-${{ env.CACHE_VERSION }}-fuzz${{ env.CARGO_FUZZ_VERSION }}- - ${{ runner.os }}-cargo-${{ env.CACHE_VERSION }}- - ${{ runner.os }}-cargo- - - # Restore apt packages cache - - name: Restore apt cache - id: cache-apt - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: | - ./.apt-cache - ./.apt-state - key: ${{ runner.os }}-apt-${{ env.APT_HASH }} - - - name: Install Boost - run: | - sudo apt-get update - sudo apt-get install -y libboost-all-dev - - # Install system dependencies only if cache miss - - name: Install libfuzzer dependencies - if: steps.cache-apt.outputs.cache-hit != 'true' - run: | - mkdir -p ./.apt-cache/archives ./.apt-state/lists - sudo -E apt-get update && sudo -E apt-get install -y build-essential cmake clang - - # Install cargo-fuzz only if not found in cache - - name: Install cargo-fuzz - if: steps.cache-rust.outputs.cache-hit != 'true' - run: cargo +nightly install cargo-fuzz --version ${{ env.CARGO_FUZZ_VERSION }} --force - - # Run fuzzing tests - - name: Run fuzzing tests - run: | - cd fuzz - echo "Available fuzz targets:" - cargo fuzz list - for target in $(cargo fuzz list); do - echo "Running fuzz target: $target" - CARGO_PROFILE_RELEASE_LTO=false cargo +nightly fuzz run $target -- -max_total_time=60 - done - - # Save Rust cache if there was no exact match - - name: Save Rust cache - if: success() && steps.cache-rust.outputs.cache-hit != 'true' - uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: | - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - ~/.cargo/bin/cargo-fuzz - target/ - fuzz/target/ - key: ${{ steps.cache-rust.outputs.cache-primary-key }} - - # Save apt cache if there was no exact match - - name: Save apt cache - if: success() && steps.cache-apt.outputs.cache-hit != 'true' - uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: | - ./.apt-cache - ./.apt-state - key: ${{ runner.os }}-apt-${{ env.APT_HASH }} - - # Upload artifacts (if crashes are found) - - name: Upload artifacts - if: failure() - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: fuzz-artifacts - path: fuzz/artifacts + fuzz: + name: Fuzz - ${{ matrix.name }} + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - name: Deserialize + target: deserialize + - name: Proof Corruption + target: proof-corruption + + steps: + - name: Checkout Repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Setup Rust Cache + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + with: + workspaces: | + . -> target + fuzz -> target + + - name: Setup cargo-rbmt + uses: $/.github/actions/setup-rbmt + + - name: Restore Fuzz Corpus + id: corpus + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: fuzz/corpus/${{ matrix.target }} + key: fuzz-corpus-v1-${{ matrix.target }}-${{ github.run_id }}-${{ github.run_attempt }} + restore-keys: | + fuzz-corpus-v1-${{ matrix.target }}- + + - name: Run Fuzz Target + id: fuzz + shell: bash + run: | + nightly=$(cargo rbmt toolchains --nightly) + cargo +"$nightly" fuzz run "${{ matrix.target }}" -- -max_total_time=60 + + - name: Save Fuzz Corpus + if: ${{ !cancelled() && steps.fuzz.outcome != 'skipped' && steps.corpus.outcome == 'success' }} + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: fuzz/corpus/${{ matrix.target }} + key: ${{ steps.corpus.outputs.cache-primary-key }} + + - name: Upload Crash Artifacts + if: failure() && steps.fuzz.outcome == 'failure' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: fuzz-artifacts-${{ matrix.target }} + path: fuzz/artifacts/${{ matrix.target }} + if-no-files-found: ignore diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 69798f2..5dcd466 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -24,7 +24,7 @@ doc = false bench = false [[bin]] -name = "proof_corruption" +name = "proof-corruption" path = "fuzz_targets/proof_corruption.rs" test = false doc = false From 5cb92971ce235241c6f3dfa91e11bb42b78dccc0 Mon Sep 17 00:00:00 2001 From: Luis Schwab Date: Mon, 14 Sep 2026 15:05:53 -0300 Subject: [PATCH 4/7] fix(docs): remove redundant LICENSE.md Remove `LICENSE.md`, since GitHub cannot parse it. --- LICENSE.md | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md deleted file mode 100644 index c3f44ca..0000000 --- a/LICENSE.md +++ /dev/null @@ -1,14 +0,0 @@ -This software is licensed under [Apache 2.0](LICENSE-APACHE) or -[MIT](LICENSE-MIT), at your option. - -Some files retain their own copyright notice, however, for full authorship -information, see version control history. - -Except as otherwise noted in individual files, all files in this repository are -licensed under the Apache License, Version 2.0 or the MIT license , at your option. - -You may not use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of this software or any files in this repository except in -accordance with one or both of these licenses. From 725c9f3525e262d2fe36eb4620d8bae1c6f78557 Mon Sep 17 00:00:00 2001 From: Luis Schwab Date: Mon, 14 Sep 2026 15:15:34 -0300 Subject: [PATCH 5/7] feat(ci): assert the pull request is bisectable Add the `bisectability` job to the Rust workflow, which asserts all commits in the PR successfully pass all tests. --- .github/workflows/rust.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 59b60f4..e7bab7b 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -13,6 +13,29 @@ env: RUST_BACKTRACE: 1 jobs: + bisectability: + name: PR Bisectability + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + + steps: + - name: Checkout Repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Setup Rust Cache + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + + - name: Setup cargo-rbmt + uses: $/.github/actions/setup-rbmt + + - name: Assert PR Bisectability + shell: bash + run: cargo rbmt run --baseline "${{ github.event.pull_request.base.sha }}" -- test + check: name: Check - ${{ matrix.name }} runs-on: ubuntu-latest From 03afbef543f3cc6609d823d47391a5fa8447d4af Mon Sep 17 00:00:00 2001 From: Luis Schwab Date: Mon, 14 Sep 2026 15:31:03 -0300 Subject: [PATCH 6/7] feat(ci): add cross-compilation workflow Add cross-compilation testing to CI. Native targets run on native CI runners, and foreign targets are emulated using QEMU. * Native: * aarch64-apple-darwin * aarch64-unknown-linux-gnu * x86_64-pc-windows-msvc * x86_64-unknown-linux-musl * Emulated (QEMU): * i686-unknown-linux-gnu * arm-unknown-linux-gnueabi * armv7-unknown-linux-gnueabihf * powerpc64le-unknown-linux-gnu * powerpc-unknown-linux-gnu * riscv64gc-unknown-linux-gnu * s390x-unknown-linux-gnu --- .github/workflows/cross.yml | 153 ++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 .github/workflows/cross.yml diff --git a/.github/workflows/cross.yml b/.github/workflows/cross.yml new file mode 100644 index 0000000..7dcfd6c --- /dev/null +++ b/.github/workflows/cross.yml @@ -0,0 +1,153 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 + +name: Cross + +on: + push: + pull_request: + +permissions: + contents: read + +env: + CARGO_TERM_COLOR: always + RBMT_LOG_LEVEL: progress + RUST_BACKTRACE: 1 + +jobs: + cross-native: + name: "${{ matrix.target }} [native]" + runs-on: ${{ matrix.runner }} + timeout-minutes: 45 + strategy: + fail-fast: false + matrix: + include: + - runner: macos-26 + target: aarch64-apple-darwin + + - runner: ubuntu-24.04-arm + target: aarch64-unknown-linux-gnu + + - runner: windows-2025-vs2026 + target: x86_64-pc-windows-msvc + + steps: + - name: Checkout Repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Setup Rust Cache + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + + - name: Setup cargo-rbmt + uses: $/.github/actions/setup-rbmt + + - name: Run Tests + shell: bash + run: cargo rbmt test + + cross-linux: + name: "${{ matrix.target }} [${{ matrix.execution }}]" + runs-on: ubuntu-latest + timeout-minutes: 45 + env: + CROSS_TARGET: ${{ matrix.target }} + CROSS_LINKER: ${{ matrix.gcc }} + CROSS_PACKAGES: ${{ matrix.packages }} + CROSS_RUNNER: ${{ matrix.runner }} + + strategy: + fail-fast: false + matrix: + include: + - target: i686-unknown-linux-gnu + gcc: i686-linux-gnu-gcc + packages: gcc-i686-linux-gnu libc6-dev-i386-cross + runner: qemu-i386 -L /usr/i686-linux-gnu + execution: qemu + + - target: arm-unknown-linux-gnueabi + gcc: arm-linux-gnueabi-gcc + packages: gcc-arm-linux-gnueabi libc6-dev-armel-cross + runner: qemu-arm -L /usr/arm-linux-gnueabi + execution: qemu + + - target: armv7-unknown-linux-gnueabihf + gcc: arm-linux-gnueabihf-gcc + packages: gcc-arm-linux-gnueabihf libc6-dev-armhf-cross + runner: qemu-arm -L /usr/arm-linux-gnueabihf + execution: qemu + + - target: powerpc64le-unknown-linux-gnu + gcc: powerpc64le-linux-gnu-gcc + packages: gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross + runner: qemu-ppc64le -L /usr/powerpc64le-linux-gnu + execution: qemu + + - target: powerpc-unknown-linux-gnu + gcc: powerpc-linux-gnu-gcc + packages: gcc-powerpc-linux-gnu libc6-dev-powerpc-cross + runner: qemu-ppc -L /usr/powerpc-linux-gnu + execution: qemu + + - target: riscv64gc-unknown-linux-gnu + gcc: riscv64-linux-gnu-gcc + packages: gcc-riscv64-linux-gnu libc6-dev-riscv64-cross + runner: qemu-riscv64 -L /usr/riscv64-linux-gnu + execution: qemu + + - target: s390x-unknown-linux-gnu + gcc: s390x-linux-gnu-gcc + packages: gcc-s390x-linux-gnu libc6-dev-s390x-cross + runner: qemu-s390x -L /usr/s390x-linux-gnu + execution: qemu + + - target: x86_64-unknown-linux-musl + gcc: musl-gcc + packages: musl-tools + runner: "" + execution: native + + steps: + - name: Checkout Repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Setup Rust Cache + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + with: + key: cross-${{ matrix.target }} + + - name: Setup cargo-rbmt + uses: $/.github/actions/setup-rbmt + + - name: Install Cross Compiler and QEMU + shell: bash + run: | + read -r -a packages <<< "$CROSS_PACKAGES" + if [[ -n "$CROSS_RUNNER" ]]; then + packages+=(qemu-user) + fi + sudo apt-get update + sudo apt-get install --yes --no-install-recommends "${packages[@]}" + + - name: Install Rust Target + shell: bash + run: | + stable=$(cargo rbmt toolchains --stable) + rustup target add --toolchain "$stable" "$CROSS_TARGET" + + - name: Run Tests + shell: bash + # Run unit and integration tests, excluding cross-compiled doctests. + # Explicit QEMU runners avoid depending on host binfmt_misc registration. + run: | + target_env=$(printf '%s' "$CROSS_TARGET" | tr 'a-z-' 'A-Z_') + export "CARGO_TARGET_${target_env}_LINKER=$CROSS_LINKER" + if [[ -n "$CROSS_RUNNER" ]]; then + export "CARGO_TARGET_${target_env}_RUNNER=$CROSS_RUNNER" + fi + cargo rbmt test --toolchain stable --lockfile recent -- --target "$CROSS_TARGET" --tests From 159263d82baa104b86d6f8bd866a65f0cf5cb878 Mon Sep 17 00:00:00 2001 From: Luis Schwab Date: Mon, 14 Sep 2026 15:58:55 -0300 Subject: [PATCH 7/7] chore(ci): bump tools and toolchains * Bump stable to 1.98.1 * Bump nightly to nightly-2026-09-14 * Fix new lints * Add cargo-fuzz to cargo-rbmt's tools --- Cargo.toml | 5 +++-- src/mem_forest/mod.rs | 3 +-- src/pollard/mod.rs | 14 +++++++------- src/proof/mod.rs | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d5fd86b..41f7c33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,8 +62,9 @@ rayon = { version = "1.5.3" } # blame: criterion v0.5.1 (RUSTSEC-2022-0021, RUST errno-dragonfly = { version = "0.1.2" } # blame: criterion v0.5.1 (RUSTSEC-2025-0121) [package.metadata.rbmt] -toolchains = { stable = "1.97.1", nightly = "nightly-2026-08-04" } -tools = { cargo-audit = "=0.22.2", zizmor = "=1.30.1" } +version = "0.5.3" +toolchains = { stable = "1.98.1", nightly = "nightly-2026-09-14" } +tools = { cargo-audit = "0.22.2", cargo-fuzz = "0.13.2", zizmor = "1.30.1" } lint = { allowed_duplicates = ["bitcoin-consensus-encoding", "bitcoin-internals"] } [package.metadata.rbmt.test] diff --git a/src/mem_forest/mod.rs b/src/mem_forest/mod.rs index 70f6ab5..577ec5b 100644 --- a/src/mem_forest/mod.rs +++ b/src/mem_forest/mod.rs @@ -480,8 +480,7 @@ impl MemForest { let parent_left = parent .upgrade() .and_then(|parent| parent.left.clone().into_inner()) - .ok_or("Could not upgrade parent")? - .clone(); + .ok_or("Could not upgrade parent")?; // If the current node is a left child, we left-shift the indicator // and leave the LSB as 0 diff --git a/src/pollard/mod.rs b/src/pollard/mod.rs index bc8696f..efe1991 100644 --- a/src/pollard/mod.rs +++ b/src/pollard/mod.rs @@ -1193,9 +1193,9 @@ impl Pollard { self.leaf_map.remove(&node.hash()); // we are deleting a root, just write an empty hash where it was if node.aunt.borrow().is_none() { - for i in 0..64 { - if self.roots[i].as_ref().is_some_and(|root| root == node) { - self.roots[i] = Some(Rc::new(PollardNode::default())); + for root in &mut self.roots { + if root.as_ref().is_some_and(|root| root == node) { + *root = Some(Rc::new(PollardNode::default())); return Ok(()); } } @@ -1207,15 +1207,15 @@ impl Pollard { if node.grandparent().is_none() { // my parent is a root, I'm a root now - for i in 0..64 { + for root in &mut self.roots { let aunt = node.aunt().ok_or(PollardError::AuntNotFound)?; - let Some(root) = self.roots[i].as_ref() else { + let Some(root_node) = root.as_ref() else { continue; }; - if root.hash() == aunt.hash() { - self.roots[i] = Some(sibling); + if root_node.hash() == aunt.hash() { + *root = Some(sibling); return Ok(()); } } diff --git a/src/proof/mod.rs b/src/proof/mod.rs index 861fdff..c417ef2 100644 --- a/src/proof/mod.rs +++ b/src/proof/mod.rs @@ -1204,11 +1204,11 @@ mod tests { .unwrap(); let (cached_proof, cached_hashes) = cached_proof .update( - cached_hashes.clone(), + cached_hashes, &utxos, &case_values.update.proof.targets, case_values.remembers.clone(), - updated.clone(), + updated, ) .unwrap();