paritytech / paritytech/polkadot-cli

Investigate chain spec / chain properties support

Open
#199 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

agent:done good first issue
Dominant language
TypeScript
Stars
10
Forks
2
Avg merge
12h 35m
Merged PRs (30d)
4

Description

Background

Substrate chains carry a chain spec — a JSON blob produced at genesis — that holds:

  • Identity: `name`, `id`, `chainType`
  • Networking: `bootNodes`, `telemetryEndpoints`, `protocolId`
  • `properties`: `{ tokenDecimals, tokenSymbol, ss58Format }`
  • `forkBlocks`, `badBlocks`, `codeSubstitutes`, `lightSyncState`
  • `genesis` (initial state + runtime wasm)

The `properties` block in particular is information `dot` currently does not surface — and not having it leads users (and the dot-cli skill) to hardcode token decimals per chain. That's the same antipattern that bit the in-tree `scripting-patterns.md` example: `NATIVE_DECIMALS=12` for the preview environment, `NATIVE_DECIMALS=10` for paseo-people-next, baked into config files. A faucet built on top of those numbers silently goes wrong when run against the wrong network. The chain knows the answer; we should ask it instead of guessing.

This issue is to investigate whether and how `polkadot-cli` should consume chain-spec data, and what the trade-offs look like.

What's in scope

Two distinct slices:

  1. Chain properties (cheap, RPC-served): `tokenDecimals`, `tokenSymbol`, `ss58Format`. Available on every Substrate node via `system_properties` (legacy) or `chainSpec_v1_properties` (modern chainHead family).
  2. Full chain spec (heavy, mostly out-of-band): the whole JSON, including genesis state and embedded wasm. Multi-MB. Source of truth is the node binary (` build-spec --chain `) or published files (e.g. `paritytech/polkadot-sdk`'s `cumulus/parachains/chain-specs/*.json`, `paritytech/chainspecs`, smoldot's `well-known-chains`).

These are very different shapes of feature. We should be deliberate about which one(s) to support.

Possible benefits

  • Replaces hardcoded decimals everywhere. The faucet incident, the `scripting-patterns.md` config files, and any agent-generated script that needs to reason about balances all benefit. One `dot` call replaces a per-environment branch.
  • Nicer balance rendering. `dot polkadot.query.System.Account alice` could show `1.234 DOT` alongside the raw plancks once we know the decimals + symbol.
  • Better address output. `dot account inspect` already accepts `--prefix`; with `ss58Format` known per chain, it could default to the right prefix automatically (Polkadot 0, Kusama 2, Substrate 42).
  • Smoother `dot chain add` UX. `dot chain add my-chain --rpc ` could pre-fill name / decimals / symbol / ss58 from the chain itself, no manual flags. Even better: `dot chain add --from-spec ` for full bootstrap from a published chain-spec JSON.
  • Foundation for a future light-client mode. If `dot` ever wants to use smoldot, we'd need real chain-spec ingestion. Building the import path now means the work isn't wasted later.
  • Clearer "what is this chain" introspection. Could feed the `dot metadata` JSON dump (#170, PR #194) so the runtime fingerprint header includes `tokenDecimals` / `tokenSymbol`.

Possible drawbacks / open questions

  • Two RPC families. `system_properties` is the legacy method but universally implemented; `chainSpec_v1_properties` is the modern chainHead variant. Some endpoints expose only one. Pick one, fall back to the other, or document both?
  • Multi-token edge case. Some chains return `tokenDecimals` and `tokenSymbol` as arrays instead of scalars (chains intentionally listing multiple native-ish tokens). How do we expose that? Pick the first? Surface the array? Refuse and tell the user?
  • Empty-properties endpoints. Some custom / minimal chains return `{}` — no decimals at all. Need a graceful fallback.
  • Caching policy. Properties are effectively immutable per genesis, so caching forever is fine. But if a chain operator restarts with a new spec at the same RPC URL, the cache is stale. Tie cache invalidation to the runtime fingerprint we're already storing for stale-metadata detection (PR #194)?
  • Full-spec ingestion is a different beast. Mostly a multi-MB JSON parse plus genesis-state validation logic. Not justified by the faucet use case alone — only worth it if we're also pursuing light-client or chain-bootstrap features.
  • Source-of-truth divergence. The properties block on a running node can in principle drift from what's in the binary's embedded spec (operator config errors). RPC is what users will hit, so trust the RPC.
  • Privacy / signal. Calling `system_properties` adds one round-trip per command if we fetch live each time. Cache once on `dot chain add` and on `dot chain update` to avoid that cost.

Possible implementation directions

In order of increasing scope:

  1. `dot chain properties ` command. Thin wrapper around `system_properties` / `chainSpec_v1_properties`. ~30 lines. Returns `{ tokenDecimals, tokenSymbol, ss58Format }` as JSON. Lets scripts replace `NATIVE_DECIMALS=12` with `NATIVE_DECIMALS=$(dot chain properties polkadot --json | jq .tokenDecimals)`. Self-contained; doesn't touch any other code.
  2. Persist properties in `config.json`. On `dot chain add` and `dot chain update`, fetch properties once and save them in the chain's config entry. `dot chain list` shows them. `dot account inspect` defaults `--prefix` from there. Existing chain entries get a backfill on next update.
  3. Use them for balance rendering. `dot query` and `dot tx` output starts showing `1.234 DOT` next to raw plancks when the storage value is a known balance type and we have decimals/symbol cached.
  4. `dot chain add --from-spec `. Parse a published chain-spec JSON (Substrate `build-spec` output) and prefill the chain entry with name, decimals, symbol, ss58, and bootnodes if available. No genesis-state ingestion; just the metadata fields.
  5. Full chain-spec import / light-client mode. Out of scope here — track separately if pursued.

(1) clearly pays for itself for the faucet / hardcoded-decimals problem alone. (2)+(3) build on it. (4) is a separable nice-to-have. (5) is a different feature.

Related

  • #170 / PR #194 — `dot metadata ` already prints a runtime fingerprint header; chain properties would slot in alongside it.
  • #196 — Expose known RPC methods. `system_properties` is one such method; the work here may overlap.
  • #197 — Enable calling custom RPC methods. A generic `dot rpc ` would let advanced users hit `system_properties` directly even before we add a dedicated command. Could be a stepping stone.

Decision needed

  • Which of the implementation slices (1–5) are worth pursuing?
  • Prefer `system_properties` or `chainSpec_v1_properties` as the source? (Probably both, with a fallback chain.)
  • How to handle multi-token / array-typed responses?

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the existing dot chain add and dot chain update entry points, then review #196, #197, and PR #194 for RPC and metadata patterns. Compare system_properties with chainSpec_v1_properties, including array and empty responses; done means a documented recommendation for the supported slice, fallback behavior, caching, and scope boundaries.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, cli
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.