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.
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.
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
, which is calculated based on the following parameters:
bridge_origin_universal_location
(from the latest XCM)bridge_destination_universal_location
(from the latest XCM)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
.
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.
Transact(pallet-xcm-bridge-hub::<Instance2>::Call::open_bridge(..))
-> which generates a lane_id
.lane_id
.ExportXcm
to the BridgeHub.ExportXcm
to the BridgeHub.Pros:
Cons:
Transact(pallet-xcm-bridge-hub::<Instance2>::Call::open_bridge(..))
, which generates a lane_id
.lane_id
.ExportXcm
, eliminating the extra hop.ExportXcm
to the AssetHub, but this provides more options for paying fees.Pros:
Cons:
header_hash
and state_root
) from the BridgeHub to the AssetHub, so pallet-bridge-messages::<Instance2>
can verify received bridged messages.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
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.
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:
pallet-bridge-messages::<Instance2>
, generating a new calculated LaneId(H256)
.pallet-xcm-bridge-hub::<Instance2>
as the XCM exporter.pallet-bridge-messages::<Instance1>
.pallet-bridge-messages::<Instance1>
from the BridgeHub.pallet-bridge-relayers::<Instance1>
.