paritytech / paritytech/polkadot-cli

Tracking: Extrinsic V5 support — metadata negotiation, extension versioning, capability-gated signing

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

Nobody has claimed this yet.

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

Description

Umbrella issue for moving dot onto Extrinsic V5 where the network actually supports it, and for
fixing the metadata-version handling that blocks it.

Full research write-up: https://claude.ai/code/artifact/bd81821b-e454-4e12-9d75-168a3b9fabbe

The short version

We cannot "just move to v5", and v4 is not deprecated. But there is real, valuable work here, and
one live bug worth fixing on its own merits.

  1. Extrinsic v4 is not deprecated. RFC-124, the actual Extrinsic V5 specification, is still
    open and unmerged. Every one of the 20 chains probed advertises extrinsic.version = [4,5].
    No removal timeline exists.
  2. A v5 General transaction has no signature field. Authorization moves into a transaction
    extension — pallet-verify-signature, metadata identifier VerifyMultiSignature. If a runtime
    doesn't carry it, there is nowhere to put a signature.
  3. Almost no chain carries it. Only people chains do. On Polkadot, Kusama, Westend, Paseo and
    every asset hub / bridge hub / coretime / collectives / bulletin, v4 is not a legacy fallback —
    it is the only way to sign anything.
  4. So the policy is "v5 when the chain can authorize it, v4 otherwise" — gated on the extension
    being present, not on versions containing 5.
  5. We already emit v5 where we can. dot tx --unsigned produces a real v5 General extrinsic.
  6. VerifyMultiSignature: Disabled in the current code is correct, not a bug. Under v4 the
    signature lives in the extrinsic's own signature field, so the extension must be inert.

Capability matrix (probed live, 2026-08-13)

Chain VerifyMultiSignature? Must use
paseo-people, preview-people, nextv2-people yes v5 General
polkadot, polkadot-asset-hub, polkadot-people, polkadot-bulletin no v4 Signed
polkadot bridge-hub / coretime / collectives no v4 Signed
kusama, kusama-asset-hub no v4 Signed
westend, westend-asset-hub no v4 Signed
paseo, paseo-asset-hub, paseo-asset-hub-next no v4 Signed
preview-relay, preview-asset-hub, preview-bulletin no v4 Signed

Every chain: metadataVersions = [14,15,16], extrinsic.version = [4,5], extension versions {0}.

Proven on chain

Not argued from documentation — implemented and submitted:

Test Chain Result
v4 signed on a chain that has the extension preview-people Finalized, block #171737, ExtrinsicSuccess
v5 General, signed preview-people Included — nonce 54 -> 55, tx 0xa76ab997aab6c0683a1debb59ee7e765b595656e12e2c5d380e402dba6f4b369
v5 General, signed nextv2-people Payment, not BadProof — signature verified, account unfunded
v5 General, no signature extension polkadot-asset-hub UnknownOrigin (0x01000c)

A working prototype is embedded in #294.

Work items

  • #292 — Negotiate the highest supported metadata version instead of pinning v15
  • #293 — Select the transaction-extension version from metadata instead of taking the first key
  • #294 — Capability-gated Extrinsic V5 General signing
  • #295 — --ext silently ignores builtin extensions, making CheckMetadataHash unreachable

Suggested order: #292 -> #293 -> #294. #295 is independent and can go any time.

#292 is worth doing regardless of v5: it fixes a live bug where which metadata version dot
operates on depends on your command history
(read commands pin v15, dot tx lets polkadot-api
write v16 into the same cache file with no fingerprint).

Invariants we must not lose

These were expensive to establish. Each has bitten someone already.

  • CheckMetadataHash must always be computed from metadata v15, even when we read v16 — the
    merkleized hash diverges between the two. Direct ruling from bkchr after it broke signing on
    Kusama Asset Hub. See #292.
  • transaction_extensions_by_version is keyed by extension version, not extrinsic version.
    The frame-metadata doc comment says "extrinsic" and is wrong. v4 always uses key 0. See #293.
  • Metadata_metadata / state_getMetadata returns v14 forever, by construction. It is a
    fallback, never a negotiation target.
  • Metadata v15 reports the minimum supported extrinsic version, and has no extension-version
    map. The day v4 is dropped, v14/v15 become structurally unusable. This is the real deadline.
  • V5 signer payloads are always blake2_256-hashed, unlike v4's >256-byte rule. The
    extension-version byte is part of the payload. The cut is at the last authorization extension.
  • VerifyMultiSignature::Signed is a struct {signature, account}, and Disabled = variant 0,
    Signed = variant 1. Encode by name from metadata; subxt declares them in the opposite order.

Ecosystem constraints

  • polkadot-api ships no v5 transaction builder — not in 2.2.2 (ours), not in 3.0.0-rc.5, not
    in the newest canary. Every signer hardcodes createV4Tx; the pjs signer throws "Only extrinsic
    v4 is supported"
    . Tracking issue polkadot-api/polkadot-api#760 is open and unstarted; the
    maintainer is waiting on RFC-124 to merge. So we write our own signer against
    PolkadotSigner.signTx, which returns complete extrinsic bytes that papi broadcasts untouched —
    the approach papi's maintainer recommends in that thread.
  • papi 3.0 does not help. Its TxCreator has a txExtVersion field but every shipped creator
    throws on anything but 0. It broke in four of five RCs and has been stalled since 2026-07-29.
    Revisit once it is stable and #760 is closed.
  • subxt defaults to v4 whenever v4 is advertised. Our policy is more aggressive than the
    reference client, which is precisely why it must be gated. subxt also does not gate v5 signing,
    so it will build signature-less General transactions that die as UnknownOrigin — don't copy it.
  • truapi is the reference implementation to follow (rust/crates/truapi-server/src/host_logic/extrinsic.rs,
    build_signed_extrinsic_v5). It delegates the implication hash to frame-decode and signature
    semantics to subxt rather than hand-rolling either.

Risk: this exact change already broke production

June 2025 — chains adopting metadata v16 caused polkadot-js to flip to Extrinsic V5. Signing broke
on Westend Asset Hub and Rococo. The default was reverted to v4 within a day
(polkadot-js/apps#11602, reverted by polkadot-js/api#6164: "we've decided to temporarily disable
ExtrinsicV5 and fall back to ExtrinsicV4 as the default until full support is in place"
).

Our differences must be the capability gate and an opt-in period. Do not flip defaults in the same
change that introduces the v5 code path.

Related existing issues

  • #253 — exposing the tx signing payload / inherited_implication for external proofs. This work
    directly unblocks it
    ; the v5 implication formula is exactly what it needs. Coordinate so the
    payload seam is built once.
  • #252, #240 — transaction-extension discoverability and display; overlaps #293.
  • #251 — --ext composability gaps; overlaps #295.
  • #284 — Ethereum/secp256k1 accounts; relevant to the Ecdsa/Eth MultiSignature variants.

Reproducing the research

Probes were run from a clean worktree off 031c4ba using only deps the repo already has
(polkadot-api/ws, @polkadot-api/substrate-client, @polkadot-api/substrate-bindings,
@polkadot-api/metadata-builders, @noble/hashes, @polkadot-labs/hdkd).

Always use an isolated DOT_HOME (export DOT_HOME=$(mktemp -d)) — never the real one.

Test baseline at time of writing: 1789 pass, 2 fail, both pre-existing network flakiness under
--concurrent (tx.test.ts "pallet-only with json" / "category-only with json"); they pass in
isolation.

References

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

This is an umbrella issue: start by reading work items #292–#295 and the prototype in #294, then inspect rust/crates/truapi-server/src/host_logic/extrinsic.rs and build_signed_extrinsic_v5. Treat metadata negotiation, extension-version selection, capability gating, and builtin extension handling as separate scopes; done requires the relevant subissues to pass without changing v4 defaults.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.