Ethereum Bridging using Light Clients - Rainbow Costing
This research was done in conjunction with the Harmony team in early 2022.
A review of how Bridging costs can be reduced using light clients. Taking the near Rainbow Bridge as an example.
- date: 2022-02-23
- author: John Whitton
- contributors: Thanks to Aaron Li for their helpful suggestions.
Table of Contents
Introduction
In this article we review the use of light clients and how they can improve trust and costing for bridges.
Bridge Transaction Walk Through
Following is a walkthough of a funds transfer from Ethereum to a target chain (In this example Near), complete with light client updates, block propogation and proofs to ensure the transaction validity.
Actors
From the diagram above you'll notice that there are many actors involved, below is an overview of the actors and the operations they perform.
- Accounts
- User Account : The user is the owner of the funds being transferred and is responsible for signing the transactions to authorize bridging them accross chains. In this example they have accounts on Ethereum and NEAR
- Target Chain Relayer Acccount: The relayer account is responsible for relaying messages from Ethereum to the target chain. *Note this is connected to a relayer which is responsible for tasks such as querying latest block headers and getting light client status updates. Source code is here.
- Target Chain Bridge Validator Accounts: are responsible for validating light client update proposals and sending approval votes to DAO Eth Client Contract.
- Ethereum Components
- ERC20 Token Contract: this is the token contract securing the funds in this examle USDT (Tether). Source code is here
- Bridge Contract: Responsible for deposits and withdrawals of tokens on Ethereum as well as various proving and propogation mechanisms such as checking of Signatures and adding Light Client Blocks. Source code is here
- Target Chain (NEAR) Components
- Validator DAO Contract: Responsible for receivng light client update proposals from the relayer and gathering approval votes for these propoals from Validators and submitting light client updates once the proposal is approved by the Validators. Source code is here
- Etherum 2 Client: The Ethereum 2 client is responsbile for processing light client updates and receiving execution header blocks from Ethereum via the relayer. Source code is here. Note: this replaced the Ethereum 1 client source code here
- Ethereum Prover : The Ethereum Prover is used to prove transactions are included in a valid block Header. Source code is here
- Bridge Contract: The Bridge contract is responsible for managing tokens including creating new tokens, setting metadata and depositing and withdrawal of tokens. Source code is here.
- NEAR Token Contract: The target chain representation of the token (USDT) managed by the target chain bridge contract.
Sample TransactionFlow
- Block Propogation
- Get the Latest Slot: The relayer loops polling Ethereum every 12 seconds to get the latest slot. It then checks if it is for a new epoch and if so (every 6 minutes) submits an execution header (with 32 blocks in it) and a light client update with the latest approved epochs and updated sync_comittee. Relayer source code for the loop is here for retrieving the latest slot is here, for submitting execution blocks is here and for sending light client updates is here.
- Send Block Headers (submit_execution_header): Batch transaction which submits 32 block headers to client-eth2.bridge.near for Ethereum Blocks 16493592 to 16493623. (The second slot in epoch 176,936 to the first slot in epoch 176,937). Executed every 6 minutes when the first slot of a new epoch is found.
- Create Light Client update proposal(add_proposal): calls bridge-validator.sputnik-dao.near to add proposal 17410 for slot 5,661,984 in epoch 176,937.
- Approve Proposal (act_proposal): sends a VoteApprove action for proposal 17410 from a bridge validator to the Validator DAO Contract.
- act_proposal in contract bridge-validator.sputnik-dao.near
- submit_beacon_chain_light_client_update in client-eth2.bridge.near
- on_proposal_callback in contract bridge-validator.sputnik-dao.near
- Get the Latest Slot: The relayer loops polling Ethereum every 12 seconds to get the latest slot. It then checks if it is for a new epoch and if so (every 6 minutes) submits an execution header (with 32 blocks in it) and a light client update with the latest approved epochs and updated sync_comittee. Relayer source code for the loop is here for retrieving the latest slot is here, for submitting execution blocks is here and for sending light client updates is here.
- Funds Transfer Transaction Flow
- Lock Funds On Ethereum: Locking 10,000 USDT to send to user on NEAR.
- Deposit Funds on Target Chain Bridge Contract (deposit)
- deposit in contract factory.bridge.near
- verify_log_entry in contract prover.bridge.near
- block_hash_safe in contract client-eth2.bridge.near
- finish_deposit in contract factory.bridge.near : mint of 10,000 USDT.
- Find and review the source code for the validator light client approval update. Note: the eth2_client has a validate_light_client_update which is configurable and is used for debugging purposes.
Bridging Resources Required
Here is the storage and compuational costs per component.
Component | Data | Storage | Notes |
---|---|---|---|
Ethereum 2 Client | --- | --- | --- |
Prover | not applicable | 0 bytes | |
DAO Contract |
TODO Review the following data structure and elements and move into the table above commenting on any mandatory requirements and structures that can be improved.
pub struct Eth2Client {
/// If set, only light client updates by the trusted signer will be accepted
trusted_signer: Option<AccountId>,
/// Mask determining all paused functions
paused: Mask,
/// Whether the client validates the updates.
/// Should only be set to `false` for debugging, testing, and diagnostic purposes
validate_updates: bool,
/// Whether the client verifies BLS signatures.
verify_bls_signatures: bool,
/// We store the hashes of the blocks for the past `hashes_gc_threshold` headers.
/// Events that happen past this threshold cannot be verified by the client.
/// It is desirable that this number is larger than 7 days' worth of headers, which is roughly
/// 51k Ethereum blocks. So this number should be 51k in production.
hashes_gc_threshold: u64,
/// Network. e.g. mainnet, kiln
network: Network,
/// Hashes of the finalized execution blocks mapped to their numbers. Stores up to `hashes_gc_threshold` entries.
/// Execution block number -> execution block hash
finalized_execution_blocks: LookupMap<u64, H256>,
/// All unfinalized execution blocks' headers hashes mapped to their `HeaderInfo`.
/// Execution block hash -> ExecutionHeaderInfo object
unfinalized_headers: UnorderedMap<H256, ExecutionHeaderInfo>,
/// `AccountId`s mapped to their number of submitted headers.
/// Submitter account -> Num of submitted headers
submitters: LookupMap<AccountId, u32>,
/// Max number of unfinalized blocks allowed to be stored by one submitter account
/// This value should be at least 32 blocks (1 epoch), but the recommended value is 1024 (32 epochs)
max_submitted_blocks_by_account: u32,
// The minimum balance that should be attached to register a new submitter account
min_storage_balance_for_submitter: Balance,
/// Light client state
finalized_beacon_header: ExtendedBeaconBlockHeader,
finalized_execution_header: LazyOption<ExecutionHeaderInfo>,
current_sync_committee: LazyOption<SyncCommittee>,
next_sync_committee: LazyOption<SyncCommittee>,
}
References
Explorer and Interactive Links-
Near
- eth-prover
- eth-client
- factory (manages tokens)
- dao
- aurora
-
Ethereum
- beaconcha.in
- Near Bridge