Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fresh-light-chainspecs

Refreshes a Substrate light-client chain spec's lightSyncState warp-sync checkpoint from a live RPC node, at build time — not at runtime, and not by tracking a third-party package's release cadence.

Why

A light client's cold-start time is dominated by how stale its checkpoint is, not by which chain or which client implementation you're using. Tracking @polkadot-api/known-chains (or similar) only refreshes on that package's own release cadence (observed: roughly every 1-3 weeks) — a hard ceiling on freshness that has nothing to do with your own deploy cadence. Fetching fresh at build time removes that ceiling: every image build gets a checkpoint that's only as stale as time since that build, with zero added runtime cost or network dependency at boot.

Same technique @polkadot-api/known-chains' own update-sync-state.js uses (a bare sync_state_genSyncSpec call against a real RPC node) — just run on your own schedule instead of theirs.

Usage

chainspec-refresh --out <path> [--chain polkadot|kusama|westend|paseo] [--rpc <wss-url>] [--merge-light-sync-state] [--timeout <ms>]
  • --out (required): file to write.
  • --chain (default: polkadot): which known relay chain's default RPC endpoint to use.
  • --rpc: overrides --chain's default endpoint — needed for anything not in the known list (a parachain, a private/custom endpoint, etc.).
  • --merge-light-sync-state: only replace lightSyncState in the existing file at --out, leaving bootNodes/genesis/etc untouched (--out must already exist). Without this flag, the full fetched spec overwrites --out.
  • --timeout (default 30000): milliseconds before giving up on the RPC.

Using it in a Dockerfile

The published binary is dynamically linked against musl's ld.so (not fully static) and also needs libstdc++/libgcc at runtime — verified against a plain alpine:latest, which is missing both. It runs correctly inside this image (which has them), but don't copy the binary itself into your own Dockerfile — a glibc-based image (Debian/Ubuntu, including oven/bun's official image) won't be able to run it at all, and even another Alpine image would need the same two packages installed.

Instead, use this image as an intermediate build stage and only copy out its output — a plain JSON file with no libc dependency at all:

FROM ghcr.io/bloque-app/fresh-light-chainspecs:<tag> AS chainspec
# For a merge-only refresh, the base file must already be present in this stage:
COPY chainspecs/kusama-relay.json /spec.json
RUN chainspec-refresh --chain kusama --out /spec.json --merge-light-sync-state

FROM <your-actual-base> AS builder
COPY --from=chainspec /spec.json ./chainspecs/kusama-relay.json
...

Pin a specific tag or digest, not latest — treat a bump here like any other dependency bump: a deliberate, reviewed step, not something that silently changes what your build produces.

Every project should also keep its own committed default spec for local dev (a raw fetch for compiled/native projects, a last-known-good file for JS/TS ones) — this tool only overrides that default during the actual Docker build, it doesn't replace the need for one.

Development

bun install
bun test
bun run typecheck
bun run build   # compiles dist/chainspec-refresh (bun-linux-x64-musl)

About

Refreshes a Substrate light-client chain spec's lightSyncState checkpoint from a live RPC node at build time

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages