|
| 1 | +## Overview |
| 2 | + |
| 3 | +Rainbow Bridge ETHβNEAR light client. An on-chain Ethereum light client contract on NEAR that tracks Ethereum beacon chain finality via sync committee updates, plus a relayer that feeds it data. |
| 4 | + |
| 5 | +## Repository Layout |
| 6 | + |
| 7 | +Two Cargo workspaces plus a standalone crate: |
| 8 | + |
| 9 | +- **`contracts/near/`** β NEAR smart contracts workspace (`eth2-client`, `eth-prover`, `eth-types`) |
| 10 | +- **`eth2near/`** β Legacy relayer workspace (7 crates) |
| 11 | +- **`relayer/`** β New relayer (standalone, Rust edition 2024) |
| 12 | + |
| 13 | +The eth2 light client lives in `contracts/near/eth2-client/`. Supporting crates: |
| 14 | +- `eth-types` β Ethereum execution/consensus type definitions (BlockHeader, BeaconBlockHeader, SyncCommittee, etc.) |
| 15 | +- `eth2-utility` β Consensus logic: network configs, fork handling, merkle proof verification, sync committee period computation |
| 16 | +- `eth2_hashing` β WASM-compatible Keccak256 (patched ethereum_hashing for NEAR SDK) |
| 17 | + |
| 18 | +## Test, Lint |
| 19 | + |
| 20 | +All contract commands run from `contracts/near/`: |
| 21 | + |
| 22 | +```bash |
| 23 | +# Test (the canonical CI sequence β builds test WASM first, then runs tests twice: with and without default features) |
| 24 | +cd contracts/near/eth2-client && ./test.sh |
| 25 | + |
| 26 | +# Run all tests |
| 27 | +cd contracts/near && cargo test -p eth2-client |
| 28 | + |
| 29 | +# Unit tests only (no mainnet feature, allows validate_updates=false) |
| 30 | +cd contracts/near && cargo test -p eth2-client --no-default-features -- --nocapture |
| 31 | + |
| 32 | +# Lint |
| 33 | +cd contracts/near && cargo clippy |
| 34 | +cd contracts/near && cargo fmt --check |
| 35 | +``` |
| 36 | + |
| 37 | +**Feature flags** (eth2-client): `default = ["logs", "mainnet"]` |
| 38 | +- `mainnet` β enforces `validate_updates` and `verify_bls_signatures` on init |
| 39 | +- `logs` β enables `env::log_str()` output |
| 40 | +- Unit tests marked `#[cfg(not(feature = "mainnet"))]` only run with `--no-default-features` |
| 41 | + |
| 42 | +**CI** (`.github/workflows/contracts-near.yml`): runs `make build-eth2-client`, `./test.sh`, and relayer tests. Requires `git-lfs` for test data. |
| 43 | + |
| 44 | +## Contract State Machine |
| 45 | + |
| 46 | +The eth2-client alternates between two modes (`ClientMode` enum): |
| 47 | + |
| 48 | +``` |
| 49 | + βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| 50 | + β β |
| 51 | + βΌ β |
| 52 | +SubmitLightClientUpdate β |
| 53 | + β submit_beacon_chain_light_client_update(update) β |
| 54 | + β 1. verify_finality_branch: merkle proof that β |
| 55 | + β update.finalized_header is in attested_header β |
| 56 | + β 2. check β₯2/3 sync committee participation β |
| 57 | + β 3. verify_bls_signatures (aggregate BLS via β |
| 58 | + β NEAR host fns: bls12381_p1_sum, pairing_check) β |
| 59 | + β 4. commit: if period advanced (PβP+1), rotate β |
| 60 | + β current_sync_committee β next, next β from update β |
| 61 | + β 5. set finalized_beacon_header, switch mode β |
| 62 | + β β |
| 63 | + βΌ β |
| 64 | +SubmitHeader β |
| 65 | + β submit_execution_header(block_header) ΓN β |
| 66 | + β β called once per block, newestβoldest β |
| 67 | + β β first call: block whose hash matches β |
| 68 | + β finalized_beacon_header.execution_block_hash β |
| 69 | + β β each subsequent: parent of the previous β |
| 70 | + β β inserts block_numberβblock_hash in LookupMap β |
| 71 | + β β GCs blocks beyond hashes_gc_threshold β |
| 72 | + β β last call: block_number == old_finalized + 1, β |
| 73 | + β verifies parent_hash links to old finalized hash βββββ |
| 74 | + β (chain is "closed"), updates finalized_execution_header |
| 75 | +``` |
| 76 | + |
| 77 | +**Period constraint**: light client updates can advance by at most 1 sync committee period (`update_period == finalized_period || finalized_period + 1`). This bounds the execution block gap (and thus GC work) to at most one period's worth of blocks per cycle. |
| 78 | + |
| 79 | +**GC**: `gc_finalized_execution_blocks` removes old entries from `finalized_execution_blocks` LookupMap. Bounded to `MAX_GC_BLOCKS_PER_CALL` (= one period = 8192) removals per call. In steady state this removes exactly 1 block per `submit_execution_header` call. |
| 80 | + |
| 81 | +## Key Protocol Constants |
| 82 | + |
| 83 | +Defined in `eth2-utility/src/consensus.rs`, per the [Ethereum Consensus Spec](https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md): |
| 84 | + |
| 85 | +- `SLOTS_PER_EPOCH = 32` (~6.4 min) |
| 86 | +- `EPOCHS_PER_SYNC_COMMITTEE_PERIOD = 256` |
| 87 | +- One sync committee period = 32 Γ 256 = 8192 slots β 27 hours |
| 88 | +- `MIN_SYNC_COMMITTEE_PARTICIPANTS = 1` (contract enforces β₯2/3 of 512) |
| 89 | +- `hashes_gc_threshold` is typically 51000 (~7 days of blocks) |
| 90 | + |
| 91 | +## Test Data |
| 92 | + |
| 93 | +Test data lives in `contracts/near/eth2-client/src/data/` (LFS-tracked JSON files). Sepolia is the primary test network. Regenerate with: |
| 94 | +```bash |
| 95 | +cd contracts/near/eth2-client/src/data && uv run dump_sepolia_data.py |
| 96 | +``` |
| 97 | + |
| 98 | +## New Relayer (`relayer/`) |
| 99 | + |
| 100 | +Standalone binary with CLI subcommands: `run` (continuous), `run-job` (single execution for Cloud Run), `init`, `generate-config`, `validate-config`. Config via TOML or env vars with `RELAYER_` prefix. Uses Lighthouse types for beacon chain, Alloy for execution RPC, near-fetch for NEAR. |
0 commit comments