Conversation
…ition Phase 0+1 of the BEEFY/MMR bridge migration: adds pallet-beefy, pallet-mmr, and pallet-beefy-mmr to the Vara runtime at indices 32-34 (declared after Session, before GearEthBridge, to preserve the leaf-capture ordering from polkadot-fellows/runtimes#160), with a bridge-snapshot leaf-extra provider and a session-key upgrade for `beefy`. BEEFY ships inactive (`genesis_block: None`); node-side gadget/RPC wiring is deferred to a later phase. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Reuse the existing MaxSetIdSessionEntries constant for pallet_beefy instead of duplicating it as BeefySetIdSessionEntries (same formula, now a single source of truth for babe/grandpa/beefy). - Document the SessionKeys re-encoding hazard on the struct: appending `beefy` changes NextKeys/QueuedKeys' SCALE encoding, so a live-chain upgrade needs the Session::upgrade_keys migration (Phase 2, tracked separately) landed in the same runtime upgrade. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- bridge_leaf.rs: build the leaf preimage in a fixed-size stack array
instead of a heap-allocated Vec (this runs on every block's MMR leaf
construction).
- gear-eth-bridge: bridge_snapshot() drops the redundant Initialized
read — QueueMerkleRoot is only ever `put`, never `kill`ed, once the
bridge initializes, so its presence already implies Initialized.
- integration_tests.rs: factor the 11 repeated
ecdsa::Pair::from_string("//<Name>", None) call sites into a
beefy_key() helper.
- lib.rs: pallet_mmr::Config::INDEXING_PREFIX reuses
sp_mmr_primitives::INDEXING_PREFIX instead of retyping the literal.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…e 2) Session::upgrade_keys translates existing 4-key NextKeys/QueuedKeys entries into the current 5-key SessionKeys, assigning each validator a deterministic placeholder beefy key. Closes the SCALE-decode hazard the BEEFY/MMR runtime composition (2e768ce) introduced for already-bonded validators, and is safe to deploy in the same upgrade since BEEFY stays inactive (genesis_block: None) so the placeholder never has to sign. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds sc-consensus-beefy, sc-consensus-beefy-rpc, mmr-gadget, and mmr-rpc to the node service, following the reference wiring in substrate/bin/node/cli/src/service.rs (pinned SDK rev 298f676c9): - lib.rs: wrap the BABE/GRANDPA import stack with a BEEFY block import, start the BEEFY gossip/justification-request network protocols, and spawn the BEEFY voter and MMR gadgets alongside GRANDPA. The gadgets run unconditionally; runtime activation (GenesisBlock) gates signing. - client.rs: add BeefyApi and MmrApi to RuntimeApiCollection. - rpc/mod.rs: add BeefyDeps and wire sc_consensus_beefy_rpc::Beefy and mmr_rpc::Mmr into create_full, giving beefy_subscribeJustifications, beefy_getFinalizedHead, and mmr_generateProof. - runtime lib.rs: implement pallet_beefy_mmr::BeefyMmrApi (authority-set proofs for BEEFY light clients/relayers), which Phase 1 left out. CLI key registration and node/testing BEEFY key provisioning needed no changes: sc-cli's generic `key insert` already accepts any --key-type, and vara/node/testing/src/keyring.rs already derives a BEEFY key alongside the others. make workspace-hack run after the new dependencies per repo convention. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ukint-vs
force-pushed
the
beefy-mmr-phase-0-1
branch
from
September 19, 2026 11:38
5d48b20 to
96b16ae
Compare
ukint-vs
marked this pull request as ready for review
September 19, 2026 11:41
ukint-vs
marked this pull request as draft
September 19, 2026 11:41
ukint-vs
marked this pull request as ready for review
September 19, 2026 11:42
ukint-vs
marked this pull request as draft
September 19, 2026 11:43
ukint-vs
force-pushed
the
beefy-mmr-phase-0-1
branch
2 times, most recently
from
September 19, 2026 14:53
0dffb97 to
6382de8
Compare
ukint-vs
force-pushed
the
beefy-mmr-phase-0-1
branch
from
September 19, 2026 15:03
6382de8 to
a7d7e6e
Compare
StackOverflowExcept1on
self-requested a review
September 19, 2026 15:45
This was referenced Sep 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
20100, including key ownership and queued-key state. The one-shot migration is gated by the previous on-chain spec version and is covered by try-runtime checks.sc-consensus-beefyimplementation so malformed justification requests are rejected and penalized without terminating the request handler. The rest of the SDK remains pinned at298f676c91d64f15f38ea7fd78f125c5889ab09c.v1.50.2, and fix the typo exposed by the restored check.Architecture
This PR provides the source-chain commitment and proof-serving layer. Gear #5644 adds only an opt-in fast local cadence; gear-bridges #860 consumes these commitments and proves delivery on Ethereum.
flowchart LR Message["send_eth_message"] --> Queue["GearEthBridge queue and root"] Queue --> Snapshot["bridge_snapshot: queue ID and root"] Snapshot --> Extra["VaraBridgeProvider: 45-byte snapshot hash"] Session["Five session keys, including BEEFY ECDSA"] --> Authorities["BEEFY current and next authority sets"] Authorities --> Leaf["pallet_beefy_mmr leaf"] Extra --> Leaf Leaf --> MMR["pallet_mmr: Keccak tree and header digest"] MMR --> Worker["Node BEEFY worker: signed commitments"] MMR --> Index["Offchain indexed MMR nodes"] Worker --> RPC["BEEFY subscription and proof RPCs"] Index --> RPC RPC --> Consumer["External Rust relay and Ethereum client"]Responsibilities and trust boundary
bridge_snapshot()accessor exposes the authoritative initialized state, queue ID and queue root. This PR does not replacesend_eth_message, message hashing or the queue-clearing mechanism.VaraBridgeProvidercommits the bridge snapshot. The preimage isversion:u8 || "vara" || queueId:u64-LE || queueRoot:bytes32(45 bytes); its Keccak hash is the MMR leaf's 32-byte extra field. Version 255 distinguishes uninitialized state from initialized/empty version 0.Session boundaries and snapshot timing
The five-key session layout is BABE, GRANDPA, im-online, authority discovery and BEEFY. The
GrandpaAndGearEthBridgehandler preserves delivery of session callbacks to both existing GRANDPA and bridge logic, then includes BEEFY in the session-handler tuple.Declaration/hook order is part of the bridge commitment contract: Session runs before MMR leaf construction, and MMR construction runs before the bridge's
on_initializecan perform a due queue clear. The bridge updates a changed queue root inon_finalize. Thus a queue snapshot from source block B is proven using the leaf inserted at L=B+1, under a signed anchor C>=L. Consumers must track the first MMR insertion block A separately:index=L-A,leafCount=C-A+1.This ordering lets a consumer retain a message from an old queue and authenticate its historical snapshot after a natural session-driven clear. It does not require resetting runtime storage or simulating session callbacks.
Migration and activation are separate
The spec-20100 migration expands stored four-key records to five keys, including queued keys and ownership bookkeeping. Deterministic placeholder BEEFY public bytes preserve the production state layout; they are not usable signing keys or permission to activate production BEEFY. The one-shot migration is gated by the previous on-chain spec version.
Dev/local presets activate BEEFY at block 1. Production keeps
genesis_block: None; validators must register real BEEFY keys before a separately governed activation. Ethereum deployment, queue-root registration and message delivery are outside this PR and are explained in gear-bridges #860.For review, start with the snapshot accessor/provider and runtime hook order above, then the session migration and node/RPC wiring. Existing test and rollout evidence remains below; production weight benchmarking remains a separate gate.
How to test
make pre-commitcargo nextest run -p sc-consensus-beefy malformed_requests_do_not_stop_handlercargo nextest run -p vara-runtimecargo nextest run -p gear-service -p gear-node-testing -p runtime-fuzzercargo check -p vara-runtime --features runtime-benchmarkscargo check -p vara-runtime --features try-runtimecargo metadata --locked --no-depsmake nodee648518c5e57795df1f7ec432c08ce209de8d954: 24 passed, 0 failed. Docker image, Windows build, fuzzer, and production jobs were skipped by workflow configuration.try-runtimev0.8.0 against a Vara mainnet snapshot: migration runs once, remains idempotent, and all post-upgrade state checks pass.--dev --alice --tmp --enable-offchain-indexing truepreset: BEEFY finalizes from block 1, finalized headers contain BEEFY/MMR digests, andbeefy_subscribeJustificationsreceives a signedbeefy_justificationsnotification.Notes
genesis_block: None). The malformed-request code blocker is backported locally; production activation still requires validator key rotation plus the normal governance and deployment timing.--enable-offchain-indexingbefore the first imported MMR block. Restarting later cannot reconstruct leaves omitted while indexing was disabled.VaraMmrWeightconservatively wraps the upstream weight and accounts for the Vara-specific five reads and one write. No workstation measurements are committed.5181adf4…9980; uninitialized domain plus zero payload hashc2fe11d2…c2de.Checklist
type(scope): description)