paritytech / paritytech/polkadot-cli

Add `storage` subcommand for raw `state_*` storage access

Open
#213 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
10
Forks
2
Avg merge
12h 35m
Merged PRs (30d)
4

Description

Context

Today dot exposes two ways to read storage:

  1. dot [chain.]<pallet>.<item> — typed, metadata-driven access. Limited to storage that lives under twox128(palletName) ++ twox128(itemName); cannot reach well-known keys like :code, :heappages, :extrinsic_index, child-storage prefixes, or anything outside the metadata-described pallet surface.
  2. dot [chain.]rpc.state_getStorage 0x<key> — raw JSON-RPC passthrough (added in #197 / 0a4c5f3). Reaches anything, but is lumped in with ~50 other RPC methods and has no dedicated discovery / help / completion for the storage subset that matters most for debugging.

With the twox64/twox128/twox256 algorithms now in dot hash, users can construct any raw storage key locally — but reading it still requires reaching for the generic rpc passthrough. A dedicated, thin storage subcommand would close the loop and give AI coding agents an explicit verb for raw storage access.

Proposal

New top-level category storage, sibling to rpc / extensions, that wraps the state_* family. Raw hex in, raw hex out — no metadata coupling, no auto-decoding.

dot [chain.]storage                              # list operations
dot [chain.]storage.get   <hex_key>          [--at <hash>]   # state_getStorage
dot [chain.]storage.hash  <hex_key>          [--at <hash>]   # state_getStorageHash
dot [chain.]storage.size  <hex_key>          [--at <hash>]   # state_getStorageSize
dot [chain.]storage.keys  <hex_prefix>       [--count N] [--start-key 0x…] [--at <hash>]   # state_getKeysPaged
dot [chain.]storage.query <hex_key>…         [--at <hash>]   # state_queryStorageAt

Inherited from global flags: --chain, --rpc, --output, --json, --help.

Implementation sketch
  • src/utils/parse-dot-path.ts — add "storage" to DotCategory and CATEGORY_ALIASES.
  • src/commands/storage.ts (new) — modelled on src/commands/rpc.ts's handleRpc(). Single handler dispatches on parsed.pallet (op name); validates hex args locally (/^0x([0-9a-fA-F]{2})*$/); calls rpcRequest() from src/core/rpc.ts.
  • src/cli.ts — add CAC options --count and --start-key; extend isFlatCategory (line 205) and the switch (next to case "rpc" at line 293) to include "storage". Reuse the existing --at flag.
  • src/completions/complete.ts — add "storage" to CATEGORIES and a completeStorageCategory() returning the hardcoded op list.
  • src/commands/storage.test.ts (new) — mirror rpc.test.ts validation patterns. No rpc-methods.json cache fixture needed (we don't gate on remote method discovery — state_* is core).
  • Per-op --help text and the list view should surface well-known keys (:code = 0x3a636f6465, :heappages = 0x3a686561707061676573, :extrinsic_index) as examples — pure docs, no opinionated resolution.
Why thin / unopinionated

The killer feature here is predictability for coding agents: an agent that knows "read raw storage" can reach for storage.get without first learning the entire JSON-RPC surface. Keeping it thin (no --decode, no :code-as-keyword) means the contract is one short page and never lies.

Possible benefits

  • Closes the loop with twox in dot hash: dot hash twox128 System → concat → dot polkadot.storage.get $PFX becomes a copy-pasteable two-liner.
  • Reads well-known keys (:code, :heappages, etc.) that are not in metadata.
  • Curated discoverability: dot polkadot.storage lists 5 verbs vs hunting one of 50 RPC methods.
  • Tab completion for ops.
  • Tighter pre-flight validation (hex regex, block-hash regex, count range) than the generic rpc passthrough.

Possible drawbacks / open questions

  • Surface bloat. Everything here is reachable through rpc.state_* already. The new subcommand is UX sugar, not new capability. Counter: explicit verbs help agents materially; the cost is ~200 lines + tests.
  • Block-hash keyword resolution. Should --at best / --at finalized resolve via chain_getBlockHash / chain_getFinalizedHead? Initial proposal says no (composable as --at $(dot <chain>.rpc.chain_getFinalizedHead)), but worth confirming.
  • state_subscribeStorage. Existing rpc handler already rejects subscriptions; storage should do the same and not expose it.
  • state_queryStorage (historical range across blocks): out of scope — heavy and usually disabled on public nodes.

Out of scope (intentional)

  • Auto-decoding values via metadata (would re-couple to getUnsafeApi / parseStorageKeys).
  • state_subscribeStorage (streaming).
  • state_queryStorage (historical range).
  • Built-in :code-as-keyword translation (drifts toward opinionated; users can compose).

Verification

  1. bun test src/commands/storage.test.ts — handler validation & dispatch.
  2. bun test src/utils/parse-dot-path.test.ts — category recognised.
  3. bun test — full suite green; no regressions in rpc / query flat-category dispatch.
  4. Manual against a live chain:
    • dot polkadot.storage → lists 5 ops.
    • dot polkadot.storage.get 0x3a636f6465 → returns the runtime WASM (huge hex).
    • dot polkadot.storage.hash 0x3a636f6465 → cheap runtime-upgrade detector.
    • dot polkadot.storage.keys 0x26aa394eea5630e07c48ae0c9558cef7 --count 5 → first 5 keys under the System pallet prefix.
  5. Confirm completion: dot polkadot.storage.<TAB> yields the 5 ops.

Related

  • #197 / 0a4c5f3 — dot [chain.]rpc.<method> (existing escape hatch this would specialise).
  • Companion work landing alongside this issue: twox64/twox128/twox256 added to dot hash (prerequisite for constructing storage keys locally).

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 with src/utils/parse-dot-path.ts, src/commands/rpc.ts, and src/cli.ts to trace category parsing and flat-command dispatch. Then mirror the validation and dispatch patterns in src/commands/rpc.test.ts while adding the named completion and CLI tests. Done means the five storage operations, flags, help/list output, validation, completion, and full test suite behave as specified.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, cli
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
58/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.