14 releases (breaking)
0.10.0 | Sep 26, 2024 |
---|---|
0.9.0 | Jul 18, 2024 |
0.8.0 | Jul 13, 2024 |
0.3.1 | Mar 26, 2024 |
#4 in #merkle-root
1,395 downloads per month
Used in 4 crates
2.5MB
50K
SLoC
Ethereum Outbound Queue
Sends messages from an origin in the Polkadot ecosystem to Ethereum.
Release
Polkadot SDK stable2409
lib.rs
:
Pallet for committing outbound messages for delivery to Ethereum
Overview
Messages come either from sibling parachains via XCM, or BridgeHub itself
via the snowbridge-pallet-system
:
snowbridge_router_primitives::outbound::EthereumBlobExporter::deliver
snowbridge_pallet_system::Pallet::send
The message submission pipeline works like this:
- The message is first validated via the implementation for
snowbridge_core::outbound::SendMessage::validate
- The message is then enqueued for later processing via the implementation for
snowbridge_core::outbound::SendMessage::deliver
- The underlying message queue is implemented by
Config::MessageQueue
- The message queue delivers messages back to this pallet via the implementation for
frame_support::traits::ProcessMessage::process_message
- The message is processed in
Pallet::do_process_message
: a. Assigned a nonce b. ABI-encoded, hashed, and stored in theMessageLeaves
vector - At the end of the block, a merkle root is constructed from all the leaves in
MessageLeaves
. - This merkle root is inserted into the parachain header as a digest item
- Offchain relayers are able to relay the message to Ethereum after: a. Generating a merkle
proof for the committed message using the
prove_message
runtime API b. Reading the actual message content from theMessages
vector in storage
On the Ethereum side, the message root is ultimately the thing being verified by the Polkadot light client.
Message Priorities
The processing of governance commands can never be halted. This effectively allows us to pause processing of normal user messages while still allowing governance commands to be sent to Ethereum.
Fees
An upfront fee must be paid for delivering a message. This fee covers several components:
- The weight of processing the message locally
- The gas refund paid out to relayers for message submission
- An additional reward paid out to relayers for message submission
Messages are weighed to determine the maximum amount of gas they could consume on Ethereum. Using this upper bound, a final fee can be calculated.
The fee calculation also requires the following parameters:
- Average ETH/DOT exchange rate over some period
- Max fee per unit of gas that bridge is willing to refund relayers for
By design, it is expected that governance should manually update these
parameters every few weeks using the set_pricing_parameters
extrinsic in the
system pallet.
This is an interim measure. Once ETH/DOT liquidity pools are available in the Polkadot network, we'll use them as a source of pricing info, subject to certain safeguards.
Fee Computation Function
LocalFee(Message) = WeightToFee(ProcessMessageWeight(Message))
RemoteFee(Message) = MaxGasRequired(Message) * Params.MaxFeePerGas + Params.Reward
RemoteFeeAdjusted(Message) = Params.Multiplier * (RemoteFee(Message) / Params.Ratio("ETH/DOT"))
Fee(Message) = LocalFee(Message) + RemoteFeeAdjusted(Message)
By design, the computed fee includes a safety factor (the Multiplier
) to cover
unfavourable fluctuations in the ETH/DOT exchange rate.
Fee Settlement
On the remote side, in the gateway contract, the relayer accrues
Min(GasPrice, Message.MaxFeePerGas) * GasUsed() + Message.Reward
Or in plain english, relayers are refunded for gas consumption, using a
price that is a minimum of the actual gas price, or Message.MaxFeePerGas
.
Extrinsics
Call::set_operating_mode
: Set the operating mode
Runtime API
prove_message
: Generate a merkle proof for a committed messagecalculate_fee
: Calculate the delivery fee for a message
Dependencies
~22–37MB
~628K SLoC