From 2087ba4d5584f4a320468869d1a536fcb3678400 Mon Sep 17 00:00:00 2001 From: EclesioMeloJunior Date: Tue, 11 Aug 2026 11:05:59 -0400 Subject: [PATCH 1/5] chore: include `ribasushi-rpc-checks` to test forest against external dataset --- .../ribasushi-rpc-checks/docker-compose.yaml | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 scripts/tests/ribasushi-rpc-checks/docker-compose.yaml diff --git a/scripts/tests/ribasushi-rpc-checks/docker-compose.yaml b/scripts/tests/ribasushi-rpc-checks/docker-compose.yaml new file mode 100644 index 00000000000..dd690e2eb3b --- /dev/null +++ b/scripts/tests/ribasushi-rpc-checks/docker-compose.yaml @@ -0,0 +1,73 @@ +name: rpc-checks + +# docker compose up --build --abort-on-container-exit --exit-code-from rpc-checks + +x-env: &env + CHAIN: ${CHAIN:-calibnet} + DAYS_AGO: ${DAYS_AGO:-2} + EPOCHS: ${EPOCHS:-1000} + +services: + snapshot: + image: alpine:3.24 + environment: *env + volumes: + - ./snapshots:/snapshots + entrypoint: ["/bin/sh", "-euc"] + command: + - | + apk add --no-cache curl jq >/dev/null + + day=$$(date -u -d "@$$(( $$(date -u +%s) - DAYS_AGO * 86400 ))" +%F) + url=$$(curl -sSf "https://forest-archive.chainsafe.dev/list/$$CHAIN/latest-v2?format=json" | + jq -r --arg d "$$day" '[.items[].url | select(contains("_"+$$d+"_"))] | first') + [ "$$url" != null ] || { echo "no $$CHAIN snapshot for $$day"; exit 1; } + + file=$$(basename "$$url") + head=$$(echo "$$file" | sed 's/.*_height_\([0-9]*\)\..*/\1/') + + # only downloads if the snapshot is not present + [ -f "/snapshots/$$file" ] || curl -sSfL -o "/snapshots/$$file" "$$url" + + # define env vars used later on the next services + printf 'SNAPSHOT=%s\nSTART=%s\nEND=%s\nBACKFILL=%s\n' \ + "$$file" "$$((head - EPOCHS))" "$$((head - 1))" "$$((EPOCHS + 1))" > /snapshots/env + cat /snapshots/env + + # The RPC port opens only after the backfill finishes, so "healthy" means ready. + forest: + image: ghcr.io/chainsafe/forest:latest + depends_on: + snapshot: + condition: service_completed_successfully + environment: *env + volumes: + - ./snapshots:/snapshots:ro + ports: + - "2345:2345" + entrypoint: ["/bin/sh", "-euc"] + command: + - | + . /snapshots/env + exec forest-tool api serve "/snapshots/$$SNAPSHOT" --chain "$$CHAIN" \ + --port 2345 --height 0 --index-backfill-epochs "$$BACKFILL" + healthcheck: + test: ["CMD", "forest-cli", "chain", "head"] + interval: 30s + timeout: 10s + retries: 10 + + rpc-checks: + image: ghcr.io/chainsafe/forest-rpc-checks:latest + depends_on: + forest: + condition: service_healthy + environment: + FOREST_RPC_URL: forest:2345/rpc/v1 + volumes: + - ./snapshots:/snapshots:ro + entrypoint: ["/bin/sh", "-euc"] + command: + - | + . /snapshots/env + exec bundle exec ruby check_rpc.rb "$$START" "$$END" From 39db12bd31c62f3bc231f240c5c9cf9ac5aa1746 Mon Sep 17 00:00:00 2001 From: EclesioMeloJunior Date: Tue, 11 Aug 2026 11:14:33 -0400 Subject: [PATCH 2/5] chore: update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc99b6da65d..ac494be6a01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ - [#7408](https://github.com/ChainSafe/forest/pull/7408): Impl `Forest.IndexBackfill`, `Forest.IndexBackfillStatus` and `Forest.IndexBackfillCancel` RPC methods and the `forest-cli index backfill` command to back-fill the chain index (Ethereum mappings, events, block blooms) through the running daemon, so the node no longer needs to be stopped. An interrupted or cancelled run can be resumed with `--resume`. +- [#7477](https://github.com/ChainSafe/forest/pull/7477) Include `scripts/tests/ribasushi-rpc-checks` that tests forest against external ribasushi dataset + ### Changed ### Removed From 170db7465c6121d57fb08c220949f7ff98ab432e Mon Sep 17 00:00:00 2001 From: EclesioMeloJunior Date: Tue, 11 Aug 2026 14:45:13 -0400 Subject: [PATCH 3/5] chore: introduce validation and timeouts --- CHANGELOG.md | 2 +- .../ribasushi-rpc-checks/docker-compose.yaml | 23 +++++++++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac494be6a01..2bd0b2c9514 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,7 @@ - [#7408](https://github.com/ChainSafe/forest/pull/7408): Impl `Forest.IndexBackfill`, `Forest.IndexBackfillStatus` and `Forest.IndexBackfillCancel` RPC methods and the `forest-cli index backfill` command to back-fill the chain index (Ethereum mappings, events, block blooms) through the running daemon, so the node no longer needs to be stopped. An interrupted or cancelled run can be resumed with `--resume`. -- [#7477](https://github.com/ChainSafe/forest/pull/7477) Include `scripts/tests/ribasushi-rpc-checks` that tests forest against external ribasushi dataset +- [#7270](https://github.com/ChainSafe/forest/issues/7270): Include `scripts/tests/ribasushi-rpc-checks` that tests Forest against the external Ribasushi dataset ### Changed diff --git a/scripts/tests/ribasushi-rpc-checks/docker-compose.yaml b/scripts/tests/ribasushi-rpc-checks/docker-compose.yaml index dd690e2eb3b..b20d18c27b3 100644 --- a/scripts/tests/ribasushi-rpc-checks/docker-compose.yaml +++ b/scripts/tests/ribasushi-rpc-checks/docker-compose.yaml @@ -17,18 +17,27 @@ services: command: - | apk add --no-cache curl jq >/dev/null - + + # validates DAYS_AGO and EPOCHS + case "$$DAYS_AGO" in ''|*[!0-9]*) echo "DAYS_AGO must be a non-negative integer: '$$DAYS_AGO'"; exit 1;; esac + case "$$EPOCHS" in ''|*[!0-9]*) echo "EPOCHS must be a non-negative integer: '$$EPOCHS'"; exit 1;; esac + [ "$$EPOCHS" -ge 1 ] || { echo "EPOCHS must be at least 1"; exit 1; } + day=$$(date -u -d "@$$(( $$(date -u +%s) - DAYS_AGO * 86400 ))" +%F) - url=$$(curl -sSf "https://forest-archive.chainsafe.dev/list/$$CHAIN/latest-v2?format=json" | + url=$$(curl -sSf --connect-timeout 10 --retry 3 \ + "https://forest-archive.chainsafe.dev/list/$$CHAIN/latest-v2?format=json" | jq -r --arg d "$$day" '[.items[].url | select(contains("_"+$$d+"_"))] | first') [ "$$url" != null ] || { echo "no $$CHAIN snapshot for $$day"; exit 1; } file=$$(basename "$$url") head=$$(echo "$$file" | sed 's/.*_height_\([0-9]*\)\..*/\1/') - + case "$$head" in ''|*[!0-9]*) echo "could not parse a height from '$$file'"; exit 1;; esac + [ "$$EPOCHS" -le "$$head" ] || { echo "EPOCHS ($$EPOCHS) exceeds head ($$head)"; exit 1; } + # only downloads if the snapshot is not present - [ -f "/snapshots/$$file" ] || curl -sSfL -o "/snapshots/$$file" "$$url" - + [ -f "/snapshots/$$file" ] || + curl -sSfL --connect-timeout 10 --retry 3 -o "/snapshots/$$file" "$$url" + # define env vars used later on the next services printf 'SNAPSHOT=%s\nSTART=%s\nEND=%s\nBACKFILL=%s\n' \ "$$file" "$$((head - EPOCHS))" "$$((head - 1))" "$$((EPOCHS + 1))" > /snapshots/env @@ -53,9 +62,9 @@ services: --port 2345 --height 0 --index-backfill-epochs "$$BACKFILL" healthcheck: test: ["CMD", "forest-cli", "chain", "head"] - interval: 30s + interval: 15s timeout: 10s - retries: 10 + retries: 480 rpc-checks: image: ghcr.io/chainsafe/forest-rpc-checks:latest From 6ecededd1920b252a60a611d823c36a8dbb708bf Mon Sep 17 00:00:00 2001 From: EclesioMeloJunior Date: Wed, 12 Aug 2026 15:42:15 -0400 Subject: [PATCH 4/5] chore: includes `prepare.sh` and `ribasushi-rpc-checks.yaml` --- .../RIBASUSHI_RPC_CHECKS_ISSUE_TEMPLATE.md | 8 ++ .github/workflows/ribasushi-rpc-checks.yml | 52 ++++++++ CHANGELOG.md | 2 +- .../guides/rpc_api_compatibility.md | 9 ++ scripts/tests/ribasushi-rpc-checks/.gitignore | 3 + .../ribasushi-rpc-checks/docker-compose.yaml | 82 ++++-------- scripts/tests/ribasushi-rpc-checks/prepare.sh | 125 ++++++++++++++++++ src/tool/offline_server/server.rs | 2 +- 8 files changed, 222 insertions(+), 61 deletions(-) create mode 100644 .github/RIBASUSHI_RPC_CHECKS_ISSUE_TEMPLATE.md create mode 100644 .github/workflows/ribasushi-rpc-checks.yml create mode 100644 scripts/tests/ribasushi-rpc-checks/.gitignore create mode 100755 scripts/tests/ribasushi-rpc-checks/prepare.sh diff --git a/.github/RIBASUSHI_RPC_CHECKS_ISSUE_TEMPLATE.md b/.github/RIBASUSHI_RPC_CHECKS_ISSUE_TEMPLATE.md new file mode 100644 index 00000000000..9fa0b1589b6 --- /dev/null +++ b/.github/RIBASUSHI_RPC_CHECKS_ISSUE_TEMPLATE.md @@ -0,0 +1,8 @@ +--- +title: "[automated] Ribasushi RPC checks failure" +labels: ["Bug"] +--- + +## Description + +Latest RPC checks against the external Ribasushi dataset failed. Please [check the logs]({{ env.WORKFLOW_URL }}) for more information. diff --git a/.github/workflows/ribasushi-rpc-checks.yml b/.github/workflows/ribasushi-rpc-checks.yml new file mode 100644 index 00000000000..f39474092c0 --- /dev/null +++ b/.github/workflows/ribasushi-rpc-checks.yml @@ -0,0 +1,52 @@ +name: Ribasushi RPC checks +permissions: + contents: read + issues: write + +concurrency: + group: ${{ github.workflow }} + +on: + workflow_dispatch: + schedule: + - cron: "0 13 * * *" # Runs every day at 13:00 UTC + +jobs: + rpc-checks: + name: RPC checks against the Ribasushi dataset + runs-on: warp-ubuntu-2404-x64-8x + timeout-minutes: 180 + defaults: + run: + working-directory: scripts/tests/ribasushi-rpc-checks + steps: + - name: Checkout Sources + uses: actions/checkout@v7 + - name: Free up disk space + working-directory: . + run: ./scripts/optimize_disk_space_gh_worker.sh + - name: Install aria2 + run: sudo apt-get install -y aria2 + - name: Prepare the snapshot and pin the images + run: | + # Images are tagged with their build date and the short commit hash. + tag="$(TZ=UTC git show -s --format=%cd --date=format-local:%Y-%m-%d HEAD)-$(git rev-parse --short=7 HEAD)" + echo "Testing ghcr.io/chainsafe/forest:$tag" + ./prepare.sh "$tag" + - name: Run the RPC checks + run: docker compose up --abort-on-container-exit --exit-code-from rpc-checks + - name: Dump docker logs + if: always() + uses: jwalton/gh-docker-logs@v2 + - name: Set WORKFLOW_URL + if: always() + run: | + export WORKFLOW_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" + echo "${WORKFLOW_URL}" + echo "WORKFLOW_URL=${WORKFLOW_URL}" >> "$GITHUB_ENV" + - uses: JasonEtco/create-an-issue@v2 + if: github.ref == 'refs/heads/main' && failure() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + filename: .github/RIBASUSHI_RPC_CHECKS_ISSUE_TEMPLATE.md diff --git a/CHANGELOG.md b/CHANGELOG.md index e49e6375939..973c296a470 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,7 @@ - [#7408](https://github.com/ChainSafe/forest/pull/7408): Impl `Forest.IndexBackfill`, `Forest.IndexBackfillStatus` and `Forest.IndexBackfillCancel` RPC methods and the `forest-cli index backfill` command to back-fill the chain index (Ethereum mappings, events, block blooms) through the running daemon, so the node no longer needs to be stopped. An interrupted or cancelled run can be resumed with `--resume`. -- [#7270](https://github.com/ChainSafe/forest/issues/7270): Include `scripts/tests/ribasushi-rpc-checks` that tests Forest against the external Ribasushi dataset +- [#7270](https://github.com/ChainSafe/forest/issues/7270): Include `scripts/tests/ribasushi-rpc-checks` that tests Forest against the external Ribasushi dataset, run daily in CI at 13:00 UTC ### Changed diff --git a/docs/docs/developers/guides/rpc_api_compatibility.md b/docs/docs/developers/guides/rpc_api_compatibility.md index 470d22ab7a1..17ad53f02cf 100644 --- a/docs/docs/developers/guides/rpc_api_compatibility.md +++ b/docs/docs/developers/guides/rpc_api_compatibility.md @@ -50,6 +50,15 @@ Forest. Forest does not yet support mining and none of the mining-related RPC calls will be implemented in the foreseeable future. +## External dataset checks + +Forest is also checked against the external Ribasushi dataset of recorded RPC +responses (`chain.data.riba.plus`). The `Ribasushi RPC checks` workflow runs daily +at 13:00 UTC: it serves a recent calibnet snapshot with `forest-tool api serve` +and replays the dataset's queries against it. To run it locally, execute +`./prepare.sh` in `scripts/tests/ribasushi-rpc-checks` followed by +`docker compose up --abort-on-container-exit --exit-code-from rpc-checks`. + ## Gateway The `lotus-gateway` executable is a reverse-proxy that sanitizes RPC calls diff --git a/scripts/tests/ribasushi-rpc-checks/.gitignore b/scripts/tests/ribasushi-rpc-checks/.gitignore new file mode 100644 index 00000000000..0bc164e73fa --- /dev/null +++ b/scripts/tests/ribasushi-rpc-checks/.gitignore @@ -0,0 +1,3 @@ +# Both are generated by `prepare.sh`. +/snapshots/ +/.env diff --git a/scripts/tests/ribasushi-rpc-checks/docker-compose.yaml b/scripts/tests/ribasushi-rpc-checks/docker-compose.yaml index b20d18c27b3..d977770d02a 100644 --- a/scripts/tests/ribasushi-rpc-checks/docker-compose.yaml +++ b/scripts/tests/ribasushi-rpc-checks/docker-compose.yaml @@ -1,65 +1,34 @@ name: rpc-checks -# docker compose up --build --abort-on-container-exit --exit-code-from rpc-checks - -x-env: &env - CHAIN: ${CHAIN:-calibnet} - DAYS_AGO: ${DAYS_AGO:-2} - EPOCHS: ${EPOCHS:-1000} +# WARNING: this file is not usable on its own. `./prepare.sh` downloads the +# snapshot and writes the `.env` file every `${...}` below is interpolated from, +# so it has to run first. Without it the services come up with empty images and +# arguments. +# +# ./prepare.sh +# docker compose up --abort-on-container-exit --exit-code-from rpc-checks services: - snapshot: - image: alpine:3.24 - environment: *env - volumes: - - ./snapshots:/snapshots - entrypoint: ["/bin/sh", "-euc"] - command: - - | - apk add --no-cache curl jq >/dev/null - - # validates DAYS_AGO and EPOCHS - case "$$DAYS_AGO" in ''|*[!0-9]*) echo "DAYS_AGO must be a non-negative integer: '$$DAYS_AGO'"; exit 1;; esac - case "$$EPOCHS" in ''|*[!0-9]*) echo "EPOCHS must be a non-negative integer: '$$EPOCHS'"; exit 1;; esac - [ "$$EPOCHS" -ge 1 ] || { echo "EPOCHS must be at least 1"; exit 1; } - - day=$$(date -u -d "@$$(( $$(date -u +%s) - DAYS_AGO * 86400 ))" +%F) - url=$$(curl -sSf --connect-timeout 10 --retry 3 \ - "https://forest-archive.chainsafe.dev/list/$$CHAIN/latest-v2?format=json" | - jq -r --arg d "$$day" '[.items[].url | select(contains("_"+$$d+"_"))] | first') - [ "$$url" != null ] || { echo "no $$CHAIN snapshot for $$day"; exit 1; } - - file=$$(basename "$$url") - head=$$(echo "$$file" | sed 's/.*_height_\([0-9]*\)\..*/\1/') - case "$$head" in ''|*[!0-9]*) echo "could not parse a height from '$$file'"; exit 1;; esac - [ "$$EPOCHS" -le "$$head" ] || { echo "EPOCHS ($$EPOCHS) exceeds head ($$head)"; exit 1; } - - # only downloads if the snapshot is not present - [ -f "/snapshots/$$file" ] || - curl -sSfL --connect-timeout 10 --retry 3 -o "/snapshots/$$file" "$$url" - - # define env vars used later on the next services - printf 'SNAPSHOT=%s\nSTART=%s\nEND=%s\nBACKFILL=%s\n' \ - "$$file" "$$((head - EPOCHS))" "$$((head - 1))" "$$((EPOCHS + 1))" > /snapshots/env - cat /snapshots/env - # The RPC port opens only after the backfill finishes, so "healthy" means ready. forest: - image: ghcr.io/chainsafe/forest:latest - depends_on: - snapshot: - condition: service_completed_successfully - environment: *env + image: ${FOREST_IMAGE} volumes: - ./snapshots:/snapshots:ro ports: - "2345:2345" - entrypoint: ["/bin/sh", "-euc"] + entrypoint: ["forest-tool"] command: - - | - . /snapshots/env - exec forest-tool api serve "/snapshots/$$SNAPSHOT" --chain "$$CHAIN" \ - --port 2345 --height 0 --index-backfill-epochs "$$BACKFILL" + - api + - serve + - /snapshots/${SNAPSHOT} + - --chain + - ${CHAIN} + - --port + - "2345" + - --height + - "0" + - --index-backfill-epochs + - ${BACKFILL} healthcheck: test: ["CMD", "forest-cli", "chain", "head"] interval: 15s @@ -67,16 +36,11 @@ services: retries: 480 rpc-checks: - image: ghcr.io/chainsafe/forest-rpc-checks:latest + image: ghcr.io/chainsafe/forest-rpc-checks:2026-08-11-43c77da depends_on: forest: condition: service_healthy environment: FOREST_RPC_URL: forest:2345/rpc/v1 - volumes: - - ./snapshots:/snapshots:ro - entrypoint: ["/bin/sh", "-euc"] - command: - - | - . /snapshots/env - exec bundle exec ruby check_rpc.rb "$$START" "$$END" + # The image already entrypoints into `bundle exec ruby check_rpc.rb`. + command: ["${START}", "${END}"] diff --git a/scripts/tests/ribasushi-rpc-checks/prepare.sh b/scripts/tests/ribasushi-rpc-checks/prepare.sh new file mode 100755 index 00000000000..50d4ef4ddd8 --- /dev/null +++ b/scripts/tests/ribasushi-rpc-checks/prepare.sh @@ -0,0 +1,125 @@ +#!/usr/bin/env bash +# Prepares everything the sibling `docker-compose.yaml` interpolates: +# +# * picks and downloads a chain snapshot into ./snapshots, +# * pins both container images to an immutable `date-digest` tag, +# * writes the resulting variables to ./.env, which `docker compose` reads +# automatically from the project directory. +# +# Usage: +# +# ./prepare.sh [FOREST_IMAGE_TAG] +# docker compose up --abort-on-container-exit --exit-code-from rpc-checks +# +# FOREST_IMAGE_TAG is a `date-digest` tag such as `2026-08-10-0b42ef6`. If not +# set then will use the `date-digest` for the current HEAD. +# +# Knobs, all optional: +# +# CHAIN network to test, defaults to calibnet +# DAYS_AGO age of the snapshot to fetch, defaults to 2 +# EPOCHS how many epochs to back-fill and check, defaults to 1000 + +set -euo pipefail + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) +SNAPSHOT_DIR="$SCRIPT_DIR/snapshots" +ENV_FILE="$SCRIPT_DIR/.env" + +CHAIN="${CHAIN:-calibnet}" +DAYS_AGO="${DAYS_AGO:-2}" +EPOCHS="${EPOCHS:-1000}" + +ARCHIVE_URL="https://forest-archive.chainsafe.dev/list/$CHAIN/latest-v2?format=json" + +fail() { + echo "$*" >&2 + exit 1 +} + +is_non_negative_integer() { + [[ $1 =~ ^[0-9]+$ ]] +} + +# Prints the UTC date, `$1` days in the past, as YYYY-MM-DD. GNU and BSD `date` +# spell date arithmetic differently, and only GNU understands `--version`, which +# is what tells the two apart here. CI will be 99% of the time GNU. +utc_day_offset() { + if date --version >/dev/null 2>&1; then + date -u -d "$1 days ago" +%F + else + date -u -v-"$1"d +%F + fi +} + +# Prints the `date-digest` tag of the image built from the checked out `HEAD`, +# e.g. `2026-08-10-0b42ef6` +forest_tag_for_head() { + local date short + date=$(TZ=UTC git -C "$SCRIPT_DIR" show -s --format=%cd --date=format-local:%Y-%m-%d HEAD) + short=$(git -C "$SCRIPT_DIR" rev-parse --short=7 HEAD) + echo "$date-$short" +} + +forest_image_tag="${1:-$(forest_tag_for_head)}" +[[ $forest_image_tag =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9a-f]{7,}$ ]] || + fail "FOREST_IMAGE_TAG must look like 2026-08-10-0b42ef6, got '$forest_image_tag'" + +is_non_negative_integer "$DAYS_AGO" || fail "DAYS_AGO must be a non-negative integer, got '$DAYS_AGO'" +is_non_negative_integer "$EPOCHS" || fail "EPOCHS must be a non-negative integer, got '$EPOCHS'" +((EPOCHS >= 1)) || fail "EPOCHS must be at least 1" + +# find the most recent snapshot download URL for the $DAYS_AGO argument +day=$(utc_day_offset "$DAYS_AGO") +url=$(curl --silent --show-error --fail --location --connect-timeout 10 --retry 3 --max-time 60 "$ARCHIVE_URL" | + jq --raw-output --arg day "$day" '[.items[].url | select(contains("_" + $day + "_"))] | first') +[[ -n $url && $url != null ]] || fail "no $CHAIN snapshot published for $day" + +file=$(basename "$url") + +# Snapshot names carry the epoch of their head tipset, as in +# `forest_snapshot_calibnet_2026-08-10_height_3000000.forest.car.zst`. +# Strip everything up to and including `_height_`, then everything from the first `.`. +head_epoch=${file##*_height_} +head_epoch=${head_epoch%%.*} +is_non_negative_integer "$head_epoch" || fail "could not parse a head epoch out of '$file'" +((EPOCHS <= head_epoch)) || fail "EPOCHS ($EPOCHS) exceeds the snapshot head epoch ($head_epoch)" + +mkdir -p "$SNAPSHOT_DIR" +destination="$SNAPSHOT_DIR/$file" + +# aria2 is a better option for heavy file downloads +# it keeps a control file next to a download and removes it +# once the transfer finishes, --continue helps for abrupt +# interruptions resuming the download instead of starting over +if [[ -f $destination && ! -f $destination.aria2 ]]; then + echo "Reusing the snapshot already downloaded at $destination" +else + aria2c \ + --max-connection-per-server=5 \ + --split=5 \ + --continue=true \ + --auto-file-renaming=false \ + --console-log-level=warn \ + --summary-interval=30 \ + --dir="$SNAPSHOT_DIR" \ + --out="$file" \ + "$url" +fi + +forest_image="${FOREST_IMAGE:-ghcr.io/chainsafe/forest:$forest_image_tag}" + +# The checks cover the epochs the node has an index for: back-filling N epochs +# from the head leaves the range [head - N, head - 1] queryable. +cat >"$ENV_FILE" <= 0`, - // or valiadte the last {-height} EPOCH(s) when `height < 0` + // or validate the last {-height} EPOCH(s) when `height < 0` let validate_until_epoch = if height > 0 { height } else { From 2b16fd192d231dac071496fbbad023bb084743d1 Mon Sep 17 00:00:00 2001 From: EclesioMeloJunior Date: Wed, 12 Aug 2026 15:55:21 -0400 Subject: [PATCH 5/5] add `Ribasushi` to .dict --- .config/forest.dic | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.config/forest.dic b/.config/forest.dic index 60add798833..3366e58fc82 100644 --- a/.config/forest.dic +++ b/.config/forest.dic @@ -1,4 +1,4 @@ -294 +295 Algorand/M API's API/SM @@ -212,6 +212,7 @@ README repo/S retag Reth +Ribasushi RLP RNG roadmap/S