Skip to content

Commit c976ee1

Browse files
committed
Initial commit
0 parents  commit c976ee1

32 files changed

+11363
-0
lines changed

.github/workflows/ci.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
merge_group:
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
build:
13+
timeout-minutes: 10
14+
runs-on: ubuntu-latest
15+
strategy:
16+
matrix:
17+
node-version:
18+
- "22"
19+
- "24"
20+
steps:
21+
- uses: actions/checkout@v5
22+
- uses: actions/cache@v4
23+
with:
24+
path: .turbo
25+
key: ${{ runner.os }}-${{ matrix.node-version }}-turbo-${{ github.sha }}
26+
restore-keys: |
27+
${{ runner.os }}-${{ matrix.node-version }}-turbo-
28+
- uses: pnpm/action-setup@v4
29+
- name: Setup Node.js ${{ matrix.node-version }}
30+
uses: actions/setup-node@v5
31+
with:
32+
node-version: ${{ matrix.node-version }}
33+
- name: Install deps
34+
run: pnpm install
35+
- name: Build core
36+
run: pnpm build
37+
- name: Lint
38+
run: pnpm lint
39+
- name: Test
40+
run: pnpm test
41+
42+
# this allows our branch protection mechanism to work with matrix-based runs
43+
build-status:
44+
runs-on: ubuntu-latest
45+
needs: [build]
46+
if: always()
47+
steps:
48+
- run: ${{!contains(needs.*.result, 'failure')}}

.github/workflows/publish.yml

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
name: Publish
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
build:
14+
timeout-minutes: 10
15+
runs-on: ubuntu-latest
16+
strategy:
17+
matrix:
18+
node-version:
19+
- "22"
20+
steps:
21+
- uses: actions/checkout@v5
22+
- uses: actions/cache@v4
23+
with:
24+
path: .turbo
25+
key: ${{ runner.os }}-${{ matrix.node-version }}-turbo-${{ github.sha }}
26+
restore-keys: |
27+
${{ runner.os }}-${{ matrix.node-version }}-turbo-
28+
- uses: pnpm/action-setup@v4
29+
- name: Setup Node.js ${{ matrix.node-version }}
30+
uses: actions/setup-node@v5
31+
with:
32+
node-version: ${{ matrix.node-version }}
33+
registry-url: https://registry.npmjs.org
34+
- name: Install deps
35+
run: pnpm install
36+
- name: Build
37+
run: pnpm build
38+
- name: Lint
39+
run: pnpm lint
40+
- name: Test
41+
run: pnpm test
42+
publish:
43+
needs: [build]
44+
runs-on: ubuntu-latest
45+
permissions:
46+
contents: read
47+
id-token: write
48+
strategy:
49+
matrix:
50+
node-version:
51+
- "22"
52+
steps:
53+
- uses: actions/checkout@v5
54+
- name: Check if version has been updated
55+
id: check
56+
uses: EndBug/version-check@d17247dd94ca7b39d0b0691399be8d7c510622c9
57+
with:
58+
diff-search: true
59+
file-name: ./package.json
60+
- uses: actions/cache@v4
61+
if: steps.check.outputs.changed == 'true'
62+
with:
63+
path: .turbo
64+
key: ${{ runner.os }}-${{ matrix.node-version }}-turbo-${{ github.sha }}
65+
restore-keys: |
66+
${{ runner.os }}-${{ matrix.node-version }}-turbo-
67+
- uses: pnpm/action-setup@v4
68+
if: steps.check.outputs.changed == 'true'
69+
- name: Setup Node.js ${{ matrix.node-version }}
70+
if: steps.check.outputs.changed == 'true'
71+
uses: actions/setup-node@v5
72+
with:
73+
node-version: ${{ matrix.node-version }}
74+
registry-url: https://registry.npmjs.org
75+
- name: Install deps
76+
if: steps.check.outputs.changed == 'true'
77+
run: pnpm install
78+
- name: Build
79+
if: steps.check.outputs.changed == 'true'
80+
run: pnpm turbo build-core --cache-dir=.turbo
81+
- name: Publish
82+
if: steps.check.outputs.changed == 'true'
83+
run: |
84+
pnpm publish --no-git-checks --access=public --tag latest
85+
env:
86+
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_AUTOMATION_TOKEN }}
87+
NPM_CONFIG_PROVENANCE: "true"

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
*.log
2+
.DS_Store
3+
node_modules
4+
coverage
5+
.cache
6+
packages/**/dist/**
7+
experiments/dist/**
8+
examples/*/dist/**
9+
.vscode
10+
.pnpm-store
11+
.turbo
12+
/bin

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Changelog
2+
3+
## Unreleased
4+
5+
## 0.0.1
6+
7+
Initial release

README.md

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
# @polkadot-api/check-runtime
2+
3+
Detect common pitfalls when preparing or rolling out **runtime upgrades** on PolkadotSDK-based chains.
4+
5+
- **Two ways to use it**
6+
- **Library**: one function, `getProblems(uri, options)`, returns a list of problems detected.
7+
- **CLI**: `check-runtime problems <uri>` for fast local checks and CI.
8+
9+
> ✅ Designed to be **simple**, **deterministic**, and **automation‑friendly**.
10+
11+
---
12+
13+
## Table of contents
14+
15+
- [Installation](#installation)
16+
- [Requirements](#requirements)
17+
- [CLI Usage](#cli-usage)
18+
- [Examples](#examples)
19+
- [Exit codes](#exit-codes)
20+
- [CI integration](#ci-integration)
21+
22+
- [Programmatic API](#programmatic-api)
23+
- [Signature](#signature)
24+
- [Parameters](#parameters)
25+
- [Return value](#return-value)
26+
- [Usage examples](#usage-examples)
27+
28+
- [Problem reference](#problem-reference)
29+
- [Notes & limitations](#notes--limitations)
30+
31+
---
32+
33+
## Installation
34+
35+
**Using npm**
36+
37+
```bash
38+
npm i @polkadot-api/check-runtime
39+
```
40+
41+
Or run the CLI without installing globally:
42+
43+
```bash
44+
npx @polkadot-api/check-runtime@latest problems wss://your.chain.rpc
45+
```
46+
47+
---
48+
49+
## Requirements
50+
51+
- **Node.js 22+**
52+
- A **WebSocket RPC URI** for your chain (e.g. `wss://...`).
53+
54+
---
55+
56+
## CLI Usage
57+
58+
The CLI exposes a single subcommand (for now), `problems`, that inspects a live chain and/or a provided WASM artifact (that's applied at a certain state of the chain) and prints any detected issues.
59+
60+
```
61+
check-runtime problems <uri> [options]
62+
```
63+
64+
- `<uri>`: WebSocket RPC endpoint of the chain, e.g. `wss://rpc.ibp.network/polkadot`.
65+
66+
**Options**
67+
68+
| Option | Description |
69+
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
70+
| `--wasm <filenameOrUrl>` | A path to a local runtime WASM file **or** a direct URL to download it. When provided, checks are performed against this WASM at the target height (see `--at`). |
71+
| `--at <block>` | The height **or** block hash at which to check and/or apply the WASM. If omitted, the node’s latest state is used. |
72+
| `--symbol <symbol>` | The native token symbol. If omitted, it is read from the RPC chainspec. |
73+
| `--decimals <decimals>` | The native token decimals. If omitted, it is read from the RPC chainspec. |
74+
75+
### Examples
76+
77+
Check a live chain at head:
78+
79+
```bash
80+
npx @polkadot-api/check-runtime problems wss://sys.ibp.network/statemine
81+
```
82+
83+
Check a specific block:
84+
85+
```bash
86+
npx @polkadot-api/check-runtime problems wss://sys.ibp.network/statemine --at 0xe67351e56ddd9f12f4e67b98c709a58a170b0eb71d168ad0b5bb17fa45becff8
87+
```
88+
89+
Check using a locally built WASM:
90+
91+
```bash
92+
npx @polkadot-api/check-runtime problems wss://sys.ibp.network/statemine \
93+
--wasm ./artifacts/runtime.compact.compressed.wasm
94+
```
95+
96+
Check against a WASM downloaded from a URL:
97+
98+
```bash
99+
npx @polkadot-api/check-runtime problems wss://sys.ibp.network/statemine \
100+
--wasm https://github.com/polkadot-fellows/runtimes/releases/download/v1.7.1/asset-hub-kusama_runtime-v1007001.compact.compressed.wasm
101+
--at 0xe67351e56ddd9f12f4e67b98c709a58a170b0eb71d168ad0b5bb17fa45becff8
102+
```
103+
104+
### Exit codes
105+
106+
- `0`: No problems found: “Everything looks great!”
107+
- `1`: One or more problems detected (messages printed to stderr). This makes the command **CI‑friendly**.
108+
109+
### CI integration
110+
111+
**GitHub Actions** (minimal):
112+
113+
```yaml
114+
name: Runtime checks
115+
on: [push, pull_request]
116+
jobs:
117+
check-runtime:
118+
runs-on: ubuntu-latest
119+
steps:
120+
- uses: actions/checkout@v4
121+
- uses: actions/setup-node@v4
122+
with:
123+
node-version: 22
124+
- run: npx @polkadot-api/check-runtime problems ${{ RPC_URI }} --wasm ${{ TARGET_WASM_FILE }}
125+
```
126+
127+
---
128+
129+
## Programmatic API
130+
131+
### Signature
132+
133+
```ts
134+
import { HexString } from "polkadot-api"
135+
136+
declare const Problem: {
137+
readonly ANCIENT_METADATA: "ANCIENT_METADATA"
138+
readonly MISSING_MODERN_METADATA: "MISSING_MODERN_METADATA"
139+
readonly MISSING_RUNTIME_APIS: "MISSING_RUNTIME_APIS"
140+
readonly DEV_APIS_PRESENT: "DEV_APIS_PRESENT"
141+
readonly MISSING_CHECK_METADATA_HASH_EXTENSION: "MISSING_CHECK_METADATA_HASH_EXTENSION"
142+
readonly DIFFERENT_METADATA_HASHES: "DIFFERENT_METADATA_HASHES"
143+
readonly WRONG_OR_MISSING_METADATA_HASH: "WRONG_OR_MISSING_METADATA_HASH"
144+
}
145+
146+
type Problem = (typeof Problem)[keyof typeof Problem]
147+
148+
declare function getProblems(
149+
uri: string,
150+
options?: Partial<{
151+
wasm: HexString
152+
block: HexString | number
153+
token: Partial<{ symbol: string; decimals: number }>
154+
}>,
155+
): Promise<Array<Problem>>
156+
```
157+
158+
### Parameters
159+
160+
- `uri` **(string, required)**: WebSocket RPC URI to the target chain.
161+
- `options` **(optional)**
162+
- `wasm` **(HexString)**: The runtime code to check, as a hex string. When present, checks are performed against this code (at `block`, if provided).
163+
- `block` **(number | HexString)**: Height (number) or block hash (hex) at which to evaluate the runtime and metadata.
164+
- `token` **(Partial<{ symbol: string; decimals: number }> )**: The native token information. If omitted, values are read from the chain’s spec via RPC.
165+
166+
### Return value
167+
168+
A `Promise<Array<Problem>>` with zero or more problem identifiers. See [Problem reference](#problem-reference) for details.
169+
170+
### Usage examples
171+
172+
**Check a live chain at head**
173+
174+
```ts
175+
import { getProblems } from "@polkadot-api/check-runtime"
176+
177+
const problems = await getProblems("wss://your.chain.rpc")
178+
if (problems.length) {
179+
console.error("Issues detected:", problems)
180+
} else {
181+
console.log("Looks great!")
182+
}
183+
```
184+
185+
**Check a specific WASM at a height**
186+
187+
```ts
188+
import { readFile } from "node:fs/promises"
189+
import { toHex } from "polkadot-api/utils"
190+
import { getProblems } from "@polkadot-api/check-runtime"
191+
192+
const WASM_URI =
193+
"https://github.com/polkadot-fellows/runtimes/releases/download/v1.7.1/asset-hub-kusama_runtime-v1007001.compact.compressed.wasm"
194+
const wasm = toHex(await (await fetch(WASM_URI)).bytes())
195+
196+
const problems = await getProblems("wss://rpc.my-chain.io", {
197+
wasm,
198+
block: 123_456,
199+
})
200+
201+
if (problems.length) {
202+
console.error("Issues detected:", problems)
203+
} else {
204+
console.log("Looks great!")
205+
}
206+
```
207+
208+
---
209+
210+
## Problem reference
211+
212+
Below are the possible Problems. For each, you’ll see what it means at a high level and why it matters.
213+
214+
| Problem | What it means | Why it matters |
215+
| --------------------------------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
216+
| `ANCIENT_METADATA` | The runtime **does not expose modern metadata ≥ v14**. | Tooling that relies on modern metadata (including many SDKs and wallets) will not function correctly. Upgrade the runtime to at least metadata v14. |
217+
| `MISSING_MODERN_METADATA` | The runtime **only exposes metadata v14**, not newer formats (v15/v16). | Some clients expect v15+ for enhanced correctness and hashing; remaining on v14 can limit compatibility and safety checks. Plan to migrate to v15 or v16. |
218+
| `MISSING_RUNTIME_APIS` | The **Runtime APIs** required by modern tooling are missing. | Without them, metadata‑driven tools cannot interact reliably. See guidance linked in the CLI output. |
219+
| `DEV_APIS_PRESENT` | The runtime contains \*\*Development only Runtime APIs. | These APIs are meant for development and should not be present in a production build. |
220+
| `MISSING_CHECK_METADATA_HASH_EXTENSION` | The **CheckMetadataHash** extension is not supported by this runtime's extrinsic. | Some popular **offline** signers may be able to create transactions for this chain. |
221+
| `WRONG_OR_MISSING_METADATA_HASH` | The runtime was **compiled without the correct metadata hash** embedded. | Transactions that correctly use `CheckMetadataHash` will be deemed invalid. |
222+
| `DIFFERENT_METADATA_HASHES` | The **metadata hash differs** between metadata v15 and v16. | Indicates an inconsistency between versions; clients may behave unpredictably. |
223+
224+
> The CLI provides short, actionable messages for each problem and exits with code `1` if any are found.
225+
226+
---
227+
228+
## Notes & limitations
229+
230+
- The tool **does not submit extrinsics** and does not mutate on‑chain state; it uses Chopsticks behind the scenes.
231+
- `--at` / `block` accepts **either** a height (number) **or** a block hash (hex string).
232+
- When `--wasm`/`wasm` is provided **together** with `--at`/`block`, the height is used as the context at which to **check and/or apply** that specific code.
233+
- If `symbol`/`decimals` are not provided, they are read from the chain-spec via RPC. Keep in mind that's not "on-chain" data, ie: it's safer to provide these values.

0 commit comments

Comments
 (0)