Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/docker-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: docker-pr

on:
pull_request:
types: [opened, synchronize, reopened, labeled]

permissions:
contents: read

jobs:
build-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}

- id: meta
run: |
echo "tag=${{ github.event.pull_request.number }}-$(git rev-parse --short=8 HEAD)" >> "$GITHUB_OUTPUT"

- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3

- if: contains(github.event.pull_request.labels.*.name, 'push-debug-image')
uses: docker/login-action@v3
with:
username: ${{ secrets.PARITYPR_DOCKERHUB_USERNAME }}
password: ${{ secrets.PARITYPR_DOCKERHUB_PASSWORD }}

- uses: docker/build-push-action@v6.18.0
with:
context: .
file: ./examples/statement-latency-bench/Dockerfile
push: ${{ contains(github.event.pull_request.labels.*.name, 'push-debug-image') }}
tags: paritypr/smoldot:${{ steps.meta.outputs.tag }}
4 changes: 4 additions & 0 deletions examples/statement-latency-bench/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
package-lock.json
chain-specs/
*.log
40 changes: 40 additions & 0 deletions examples/statement-latency-bench/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Build & run the statement-latency-bench Node.js tool.
#
# The bench depends on the local `smoldot` npm package
# (wasm-node/javascript), whose `prepack` step compiles Rust → wasm.
# So the builder stage needs rust + the wasm32 target + node.

FROM rust:1 AS builder

RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates \
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*

RUN rustup target add wasm32-unknown-unknown

COPY ./.. /build

# Build the smoldot npm package first: `npm run build` runs
# prepare.mjs (compiles Rust → wasm) then tsc, producing dist/.
# A plain `file:` install of the bench would NOT run these scripts.
WORKDIR /build/wasm-node/javascript
RUN npm install
RUN npm run build

# --install-links materializes the `file:../../wasm-node/javascript`
# dep as a real copy (including the freshly built dist/) in
# node_modules instead of a symlink, so the runtime stage can be a
# self-contained copy of just this directory.
WORKDIR /build/examples/statement-latency-bench
RUN npm install --omit=dev --install-links


FROM alpine:latest

RUN apk add --no-cache nodejs bash

WORKDIR /app
COPY --from=builder /build/examples/statement-latency-bench /app

ENTRYPOINT ["node", "/app/bench.js"]
84 changes: 84 additions & 0 deletions examples/statement-latency-bench/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# statement-latency-bench

Smoldot-based Node.js port of `polkadot-sdk/substrate/client/statement-store/statement-latency-bench`.

Each virtual client runs an in-process smoldot light client and joins the
statement-store libp2p network as its own peer. There is no `--rpc-endpoints`:
smoldot is a peer, not an RPC client of a node.

## Build smoldot first

```bash
cd ../../wasm-node/javascript
npm install && npm run build
cd -
npm install
```

## Usage

`--parachain-spec` and `--relay-chain-spec` each accept either a local file
path or an `http(s)://` URL. Bootnodes are expected to be embedded in the
spec; the canonical source is the [paritytech/chainspecs](https://github.com/paritytech/chainspecs)
repo, and smoldot bundles popular ones under `../../demo-chain-specs/`.

```bash
# bundled spec from the smoldot repo
node bench.js \
--parachain-spec ../../demo-chain-specs/polkadot_asset_hub.json \
--relay-chain-spec ../../demo-chain-specs/polkadot.json \
--num-clients 4 --num-rounds 2 --messages-pattern "3:128" \
--receive-timeout-ms 30000 --interval-ms 5000

# raw URL straight from polkadot-sdk (paritytech/chainspecs is a symlink-only
# index repo; raw.githubusercontent doesn't follow its symlinks across submodules,
# so point at the underlying files directly)
node bench.js \
--parachain-spec https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/cumulus/parachains/chain-specs/asset-hub-polkadot.json \
--relay-chain-spec https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/polkadot/node/service/chain-specs/polkadot.json \
--num-clients 4 --num-rounds 2 --messages-pattern "3:128"
```

For a local dev network, splice your bootnode into the parachain spec once
(e.g. with `jq`, like `examples/statement-chat/dev.sh`) and pass the result
as `--parachain-spec`.

## Flags

| Flag | Default | Notes |
|---|---|---|
| `--parachain-spec` | required | Parachain raw chain spec — file path or `http(s)://` URL. |
| `--relay-chain-spec` | required | Relay chain raw chain spec — file path or `http(s)://` URL. |
| `--false-positive-rate` | `0.01` | Statement-store affinity bloom filter rate. |
| `--num-clients` | `100` | Each spawns its own smoldot instance. |
| `--workers` | `1` | If >1, fork that many child processes; clients distributed evenly. Use to scale past one event loop's capacity (~150 clients). |
| `--num-rounds` | `1` | |
| `--messages-pattern` | `5:512` | `count:size,count:size,…` |
| `--receive-timeout-ms` | `5000` | |
| `--interval-ms` | `10000` | Wall-clock pacing between rounds. |
| `--statement-expiry-ms` | `600000` | |
| `--warmup-ms` | `15000` | Fixed sleep after `addChain` before round 1. |
| `--fail-fast` | `false` | First failure aborts all clients via AbortController. |
| `--log-level` | `info` | error/warn/info/debug/trace |

## Differences from `bench.rs`

- **Connection model.** Rust connects to N WS endpoints; smoldot joins the
network directly. Chain specs (with embedded bootnodes) replace
`--rpc-endpoints` as the wiring point.
- **One smoldot per client.** Smoldot dedupes within a client, so one peer per
client requires one `start()` per client. Each is ~tens of MB resident; for
N=100 expect multi-GB RAM. For larger N, use `--workers <K>` to fork K child
processes (each gets its own event loop and runs N/K clients), or follow the
same K8s-shard pattern as the Rust bench.
- **No barrier.** Smoldot startup is variable (5–30s) and gossip readiness is
not observable from JSON-RPC, so a barrier on a code line gives false
confidence. We use a fixed `--warmup-ms` instead and pace rounds by wall clock.
- **`--seed` removed.** Always derives sr25519 keys via `//StatementClient//${idx}`,
matching `sc_statement_store::test_utils::get_keypair`.
- **Output line prefixes** match `bench.rs` so log parsers keyed on the leading
tokens keep working: `Spawning {N} client tasks... {testRunId}`, `Benchmark
Results: send_min=…`, `Benchmark Failed: failed_clients=…`, `Benchmark
Finished: rounds_with_any_success=…`. The smoldot port also adds a
`Starting Statement Store Latency Benchmark:` config line and an `errors=[…]`
segment to `Benchmark Failed`, neither of which exists in `bench.rs`.
Loading
Loading