The Same Bridge, the Parity Way — and the Bill

We rebuilt our trustless bridge with the stack that runs Polkadot↔Kusama: pallet-bridge-grandpa plus ordered message lanes. Same trust model, different machinery — and this time every proof lands as a signed transaction with a fee on the record. The head-to-head, measured.

In ISMP Bridging with Satsuma we bridged two satsuma chains with : on-chain , , an untrusted courier. That’s not the only implementation of the idea. Parity has shipped it for years as parity-bridges-common — the stack that moves value between Polkadot and Kusama today.

So we built the same bridge again. Same two 500ms chains, same feature (literally the same pallet-xtransfer grew a second ), same untrusted role. Different machinery. This is the head-to-head.

End-to-end transfer
6.5 s
p50 · ISMP did 4.0 s
Finality import
0.00144 UNIT
per signed proof tx
Message delivery
0.00087 UNIT
per proven batch
Trust model
identical
GRANDPA light client

Same idea, different shape

Both stacks do exactly two things on-chain: verify the peer’s GRANDPA finality, then verify state proofs against the finalized root. The differences are all in the plumbing:

  • pallet-bridge-grandpa is a header chain: relayers feed it the peer’s finalized headers with (submit_finality_proof_ex), it keeps the verified head. Justifications on our single-validator chains are a tidy 178 bytes.
  • pallet-bridge-messages adds ordered : outbound messages get consecutive , deliveries carry storage proofs of the outbound queue (~1 KB per batch), inbound tracking enforces exactly-once, in-order dispatch, and a third transaction type — the confirmation — proves delivery back to the source so it can prune its queue.

Where ISMP gives you a request/response protocol with timeouts and refunds, lanes give you a conveyor belt: strict ordering, explicit confirmation, nothing else. Our transfer pallet needed a custom dispatcher on the receiving side (decode payload → mint) — ~130 lines of runtime config in total.

The demo

terminal recording

Same choreography as before: two sovereign chains, seeds each side’s light client with the other’s , the relayer starts working, and 5 UNIT crosses A→B and B→A — verified, minted, balanced. The difference you can see is step 6: the bill. Every relayer action is a signed transaction with a fee:

Relayer actionFee (UNIT)Size
Finality import0.001440550 B tx (178 B justification)
Message delivery0.000865~1 KB storage proof
Delivery confirmation~0.000900lane state proof

A demo run’s total came to ~0.025 UNIT of relayer spend — versus zero for ISMP, whose datagrams ride in unsigned, proof-validated extrinsics admitted by the on the strength of their proofs alone. Production Parity-stack deployments bolt on pallet-bridge-relayers to reimburse relayers from bridge fees; between two chains we operate ourselves, the “bill” is money moving between our own pockets — but it sizes the subsidy honestly.

The measured head-to-head

Ten transfers each way, same machine, same block time:

ISMP direct peeringParity bridges
Delivery p50 / p904.0 s / 5.0 s6.5 s / 7.0 s
Message proof~300 B~1 KB
Finality artifact1.2–2 KB (justification + ancestry)178 B justification
Relayer cost per message0~0.0023 UNIT (finality+delivery+confirm)
User fee0.0006 UNIT0.0006 UNIT
Orderingunordered, per-request timeoutsstrictly ordered lanes
ReachHyperbridge → EVM chains laterSubstrate↔Substrate (BridgeHub lineage)

The latency gap is plumbing, not cryptography: our lane relayer needs two sequential transactions (finality, then delivery) where the ISMP relayer ships consensus + request in one pass. Both bridges’ true heartbeat is the justification cadence — we generate one every 4 blocks (2 s).

0 s2 s4 s6 sISMPmint · 4.0 sjustification wait1 tx · consensus + requestParitymint · 6.5 stx 1 · finality importtx 2 · message delivery+ confirm

Which one should a satsuma-class chain use?

ISMP direct peering is our default. Faster in practice, 3x smaller message proofs, request/response + timeout/refund semantics that map straight onto product features, no funded relayer account required — and the same pallets upgrade into a connection when we want reach beyond chains we operate.

The Parity stack is the conservative pick when strict per-lane ordering is a hard requirement, when “this exact code runs Polkadot↔Kusama” is the sentence your auditor wants to read, or when you need a crates.io-only supply chain (Polytope’s aggressive version yanking made us pin git tags and seed a lockfile — real, if minor, operational friction). Its relayer was also the easiest code of the whole study: 208 lines of JavaScript against plain RPC.

Either way, the conclusion of the pair of posts stands: two sovereign chains can hold each other to cryptographic truth — no custodian, no committee, no favors. The technology is here, it’s open source, and it runs at satsuma’s block time.

Caveats

Same list as the ISMP post — single-validator chains (178 B justifications grow with the authority set), loopback latency, no relayer incentive layer. Plus two stack-specific ones: message lanes must be opened at (there’s no extrinsic; production uses pallet-xcm-bridge-hub), and our JS relayer is a prototype — the production substrate-relay binary exists but is built around Parity’s own chain pairs.