# Bridges: Permissionless Lanes
**TLDR:**
We are introducing a new "permissionless lanes" feature, which allows for the dynamic management of opening and closing lanes instead of the current method of hard-coding them in the source code.
## Current State of the Polkadot/Kusama Bridge
The existing Polkadot/Kusama (P/K) bridge deployment involves deploying several bridge-related pallets on both BridgeHubs.
- `pallet-bridge-grandpa` (for syncing GRANDPA finality, e.g., BHP follows Kusama finality, and BHK follows Polkadot finality)
- `pallet-bridge-parachains` (for syncing parachain finality on the opposite BridgeHub)
- `pallet-bridge-messages` (for syncing messages with the bridged side)
- `pallet-xcm-bridge-hub` (acts as an XCM exporter for bridged consensus and an XCM dispatcher/router for incoming bridged messages)
- `pallet-bridge-relayers` (for registering relayers and collecting rewards)
The currently deployed `pallet-bridge-messages::<Instance1>` only supports the `LaneId` format `[u8; 4]`, and it has a single hard-coded lane `[0, 0, 0, 1]` for bridging Polkadot and Kusama AssetHubs.

## Permissionless Lanes Feature
This feature allows approved origins (relay chains, sibling parachains) to dynamically open and close bridges (via BridgeHubs) with another bridged (substrate-like) consensus, using only `xcm::Transact` and `OriginKind::Xcm`.
The `pallet-xcm-bridge-hub` will manage (open and close) bridges between chains with different consensuses. The new extrinsics, `fn open_bridge` and `fn close_bridge`, facilitate this. Internally, these create or remove inbound and outbound lanes in the `pallet-bridge-messages` instance.
Each lane represents a unique connection between two chains with different consensuses and is identified by a `LaneId`. A `LaneId` is generated when a new bridge is requested via `fn open_bridge`. It’s essential to ensure the same `LaneId` on both sides of the bridge, as the relayer can only relay messages when the `LaneId` matches on both ends. To achieve this, we introduced a new `LaneId` type, [`HashedLaneId`](https://github.com/paritytech/polkadot-sdk/blob/8279d1046cca51a317dec15df5a9b29240545163/bridges/primitives/messages/src/lane.rs#L102-L135), which is calculated based on the following parameters:
- Source: `bridge_origin_universal_location` (from the latest XCM)
- Destination: `bridge_destination_universal_location` (from the latest XCM)
- XCM version (both sides of the bridge must use the same parameters to generate an identical `LaneId`)
The core concept involves ordering the source and destination universal locations and then calculating a hash (`H256`). The universal location is a `xcm::InteriorLocation` that must start with `GlobalConsensus(NetworkId)`. The source universal location is derived from the origin that calls the `open_bridge` extrinsic. This algorithm ensures the same `LaneId` on both sides of the bridge.
We introduced the new 32-byte `H256` `HashedLaneId` for several reasons. First, the 4-byte `[u8; 4]` format could not reliably hold the new calculated hash without conflicts. Second, upgrading the Polkadot/Kusama BridgeHubs is asynchronous, making it difficult to migrate existing `pallet-bridge-messages` to the new `HashedLaneId`. Since `LaneId` is part of the message proofs, upgrading only Kusama BridgeHub to the new `HashedLaneId` would prevent the un-upgraded Polkadot BridgeHub from understanding incoming messages.
The solution is to deploy a new `pallet-bridge-messages::<Instance2>` dedicated to permissionless lanes using `LaneId(H256)`, while retaining `pallet-bridge-messages::<Instance1>` with `LaneId([u8; 4])` for AssetHubs. This approach also allows for the potential removal of `Instance1` in the future, leaving only `Instance2`.
# Deployment Plan
We need to deploy additional instances of the following pallets:
- `pallet-bridge-messages::<Instance2>` (for syncing permissionless lane messages with `HashedLaneId`)
- `pallet-xcm-bridge-hub::<Instance2>` (as a dedicated XCM exporter/dispatcher for these bridged messages)
- `pallet-bridge-relayers::<Instance2>` (for registering relayers and collecting rewards)
We are considering two possible variants for this deployment.
## Deployment on the BridgeHubs
- Deploy the specified pallets on the BridgeHub.
- Parachains (either sibling chains or AssetHub) can open a channel via XCM on both sides using `Transact(pallet-xcm-bridge-hub::<Instance2>::Call::open_bridge(..))` -> which generates a `lane_id`.
- A relayer needs to be set up to relay messages for the new `lane_id`.
- AssetHub still needs to send HRMP messages with `ExportXcm` to the BridgeHub.
- Other parachains also need to send HRMP messages with `ExportXcm` to the BridgeHub.
**Pros:**
- Easier setup, as we only need to add new instances on the BridgeHubs.
**Cons:**
- Still requires one extra hop (through the BridgeHub) for the AssetHub scenario.
- BridgeHubs only recognize the native tokens (DOT or KSM), which can be used exclusively for rewards and delivery fees.

## Deployment on the AssetHubs
- Deploy the specified pallets on the AssetHub.
- Parachains (sibling chains or AssetHub) can open a channel via XCM on both sides using `Transact(pallet-xcm-bridge-hub::<Instance2>::Call::open_bridge(..))`, which generates a `lane_id`.
- A relayer needs to be set up to relay messages for the new `lane_id`.
- AssetHub **does not need** to send HRMP messages; instead, it can directly execute `ExportXcm`, eliminating the extra hop.
- Other parachains need to send HRMP messages with `ExportXcm` to the AssetHub, but this provides more options for paying fees.
**Pros:**
- No extra hop needed for AssetHubs, allowing direct message export.
- Lower bridge fees for the sender, since the extra hop is avoided.
- "Any" asset can be used for delivery fees or rewards on the AssetHubs.
**Cons:**
- We need to sync finality proofs (bridged `header_hash` and `state_root`) from the BridgeHub to the AssetHub, so `pallet-bridge-messages::<Instance2>` can verify received bridged messages.

### Subscribe/Query/Sync Service for Finality Proofs
The basic idea is that the `pallet-bridge-messages` must validate received proofs from the bridged chain, which requires a verified/proven `bridged_header_hash` and `state_root` from finality pallets. However, we don’t want to deploy finality pallets everywhere.
Currently, this information is verified and stored in the `pallet-bridge-parachains`'s [`ImportedParaHeads`](https://github.com/paritytech/polkadot-sdk/blob/c77095f51119d2eccdc54d2f3518bed0ffbd6d53/bridges/modules/parachains/src/lib.rs#L288-L299) **deployed** on the **BridgeHubs**.
Essentially, we need a solution that **propagates (makes available)** this information (`bridged_header_hash` and `state_root`) to the (para)chain where we want to deploy `pallet-bridge-messages`.
This parachain could trigger a call on the BridgeHub's `pallet-bridge-parachains` to subscribe for new verified bridged data (`bridged_header_hash` and `state_root`). This data would then be made available to the parachain (e.g., the BridgeHub would send it via XCM using `Transact(update_proofs(bridged_header_hash, state_root))`, and the parachain would deploy a simple pallet to store this data).
For more possible solutions, see: [GitHub Issue #5827](https://github.com/paritytech/polkadot-sdk/issues/5827).
## Removing the Old `pallet-bridge-messages::<Instance1>`
Regardless of where `pallet-bridge-messages::<Instance2>` is deployed for permissionless lanes, we plan to remove the old instance and migrate everything to the new one. The goal is to end up with a single `pallet-bridge-messages` instance. Here are the steps to proceed:
1. Open a permissionless lane for AssetHubs in the new instance, `pallet-bridge-messages::<Instance2>`, generating a new calculated `LaneId(H256)`.
2. Once the lane is created on both sides:
- We will launch new relayers (or modify existing ones).
- We will start changing XCM routing on AssetHubs to use the new `pallet-xcm-bridge-hub::<Instance2>` as the XCM exporter.
- This ensures no more messages will be generated for the old `pallet-bridge-messages::<Instance1>`.
3. Once the XCM routing is changed on both AssetHubs and there are no in-flight messages, we can disable dispatch or remove the old `pallet-bridge-messages::<Instance1>` from the BridgeHub.
4. Lastly, we will migrate or transfer any remaining rewards from the old `pallet-bridge-relayers::<Instance1>`.
- If all rewards have been claimed, we can safely remove it.