Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Electra upgrade #178

Draft
wants to merge 8 commits into
base: snowbridge
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions bridges/snowbridge/pallets/ethereum-client/src/benchmarking/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ use frame_support::{migrations::SteppedMigration, weights::WeightMeter};
use frame_system::RawOrigin;
use hex_literal::hex;

use snowbridge_beacon_primitives::Fork;
use snowbridge_pallet_ethereum_client_fixtures::*;

use snowbridge_beacon_primitives::{
fast_aggregate_verify, prepare_aggregate_pubkey, prepare_aggregate_signature,
verify_merkle_branch,
fast_aggregate_verify,
merkle_proof::{generalized_index_length, subtree_index},
prepare_aggregate_pubkey, prepare_aggregate_signature, verify_merkle_branch,
};
use util::*;

Expand Down Expand Up @@ -122,13 +124,43 @@ mod benchmarks {
let update = make_sync_committee_update();
let block_root: H256 = update.finalized_header.hash_tree_root().unwrap();

let fork_versions = ForkVersions {
genesis: Fork {
version: [0, 0, 0, 0], // 0x00000000
epoch: 0,
},
altair: Fork {
version: [1, 0, 0, 0], // 0x01000000
epoch: 0,
},
bellatrix: Fork {
version: [2, 0, 0, 0], // 0x02000000
epoch: 0,
},
capella: Fork {
version: [3, 0, 0, 0], // 0x03000000
epoch: 0,
},
deneb: Fork {
version: [4, 0, 0, 0], // 0x04000000
epoch: 0,
},
electra: Fork {
version: [5, 0, 0, 0], // 0x05000000
epoch: 80000000000,
},
};
let finalized_root_g_index = EthereumBeaconClient::<T>::finalized_root_gindex_at_slot(
update.attested_header.slot,
fork_versions,
);
#[block]
{
verify_merkle_branch(
block_root,
&update.finality_branch,
config::FINALIZED_ROOT_SUBTREE_INDEX,
config::FINALIZED_ROOT_DEPTH,
subtree_index(finalized_root_g_index),
generalized_index_length(finalized_root_g_index),
update.attested_header.state_root,
);
}
Expand Down
15 changes: 15 additions & 0 deletions bridges/snowbridge/pallets/ethereum-client/src/config/altair.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>

/// Generalized Indices
/// related to Merkle proofs
/// get_generalized_index(BeaconState, 'block_roots')
pub const BLOCK_ROOTS_INDEX: usize = 37;
/// get_generalized_index(BeaconState, 'finalized_checkpoint', 'root')
pub const FINALIZED_ROOT_INDEX: usize = 105;
/// get_generalized_index(BeaconState, 'current_sync_committee')
pub const CURRENT_SYNC_COMMITTEE_INDEX: usize = 54;
/// get_generalized_index(BeaconState, 'next_sync_committee')
pub const NEXT_SYNC_COMMITTEE_INDEX: usize = 55;
/// get_generalized_index(BeaconBlockBody, 'execution_payload')
pub const EXECUTION_HEADER_INDEX: usize = 25;
15 changes: 15 additions & 0 deletions bridges/snowbridge/pallets/ethereum-client/src/config/electra.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>

/// Generalized Indices
/// related to Merkle proofs
/// get_generalized_index(BeaconState, 'block_roots')
pub const BLOCK_ROOTS_INDEX: usize = 69;
/// get_generalized_index(BeaconState, 'finalized_checkpoint', 'root')
pub const FINALIZED_ROOT_INDEX: usize = 169;
/// get_generalized_index(BeaconState, 'current_sync_committee')
pub const CURRENT_SYNC_COMMITTEE_INDEX: usize = 86;
/// get_generalized_index(BeaconState, 'next_sync_committee')
pub const NEXT_SYNC_COMMITTEE_INDEX: usize = 87;
/// get_generalized_index(BeaconBlockBody, 'execution_payload')
pub const EXECUTION_HEADER_INDEX: usize = 25;
30 changes: 2 additions & 28 deletions bridges/snowbridge/pallets/ethereum-client/src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
use snowbridge_beacon_primitives::merkle_proof::{generalized_index_length, subtree_index};
use static_assertions::const_assert;

/// Generalized Indices
/// related to Merkle proofs
/// get_generalized_index(BeaconState, 'block_roots')
pub const BLOCK_ROOTS_INDEX: usize = 37;
pub const BLOCK_ROOTS_SUBTREE_INDEX: usize = subtree_index(BLOCK_ROOTS_INDEX);
pub const BLOCK_ROOTS_DEPTH: usize = generalized_index_length(BLOCK_ROOTS_INDEX);

/// get_generalized_index(BeaconState, 'finalized_checkpoint', 'root')
pub const FINALIZED_ROOT_INDEX: usize = 105;
pub const FINALIZED_ROOT_SUBTREE_INDEX: usize = subtree_index(FINALIZED_ROOT_INDEX);
pub const FINALIZED_ROOT_DEPTH: usize = generalized_index_length(FINALIZED_ROOT_INDEX);

/// get_generalized_index(BeaconState, 'current_sync_committee')
pub const CURRENT_SYNC_COMMITTEE_INDEX: usize = 54;
pub const CURRENT_SYNC_COMMITTEE_SUBTREE_INDEX: usize = subtree_index(CURRENT_SYNC_COMMITTEE_INDEX);
pub const CURRENT_SYNC_COMMITTEE_DEPTH: usize =
generalized_index_length(CURRENT_SYNC_COMMITTEE_INDEX);

/// get_generalized_index(BeaconState, 'next_sync_committee')
pub const NEXT_SYNC_COMMITTEE_INDEX: usize = 55;
pub const NEXT_SYNC_COMMITTEE_SUBTREE_INDEX: usize = subtree_index(NEXT_SYNC_COMMITTEE_INDEX);
pub const NEXT_SYNC_COMMITTEE_DEPTH: usize = generalized_index_length(NEXT_SYNC_COMMITTEE_INDEX);

/// get_generalized_index(BeaconBlockBody, 'execution_payload')
pub const EXECUTION_HEADER_INDEX: usize = 25;
pub const EXECUTION_HEADER_SUBTREE_INDEX: usize = subtree_index(EXECUTION_HEADER_INDEX);
pub const EXECUTION_HEADER_DEPTH: usize = generalized_index_length(EXECUTION_HEADER_INDEX);
pub mod altair;
pub mod electra;

/// Sizes related to SSZ encoding
pub const MAX_EXTRA_DATA_BYTES: usize = 32;
Expand Down
9 changes: 7 additions & 2 deletions bridges/snowbridge/pallets/ethereum-client/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use super::*;
use frame_support::ensure;
use snowbridge_beacon_primitives::ExecutionProof;

use snowbridge_beacon_primitives::merkle_proof::{generalized_index_length, subtree_index};
use snowbridge_core::inbound::{
VerificationError::{self, *},
*,
Expand Down Expand Up @@ -115,12 +116,16 @@ impl<T: Config> Pallet<T> {
.hash_tree_root()
.map_err(|_| Error::<T>::BlockBodyHashTreeRootFailed)?;

let execution_header_g_index = Self::execution_header_gindex_at_slot(
execution_proof.header.slot,
T::ForkVersions::get(),
);
ensure!(
verify_merkle_branch(
execution_header_root,
&execution_proof.execution_branch,
config::EXECUTION_HEADER_SUBTREE_INDEX,
config::EXECUTION_HEADER_DEPTH,
subtree_index(execution_header_g_index),
generalized_index_length(execution_header_g_index),
execution_proof.header.body_root
),
Error::<T>::InvalidExecutionHeaderProof
Expand Down
106 changes: 92 additions & 14 deletions bridges/snowbridge/pallets/ethereum-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ use frame_support::{
};
use frame_system::ensure_signed;
use snowbridge_beacon_primitives::{
fast_aggregate_verify, verify_merkle_branch, verify_receipt_proof, BeaconHeader, BlsError,
CompactBeaconState, ForkData, ForkVersion, ForkVersions, PublicKeyPrepared, SigningData,
fast_aggregate_verify,
merkle_proof::{generalized_index_length, subtree_index},
verify_merkle_branch, verify_receipt_proof, BeaconHeader, BlsError, CompactBeaconState,
ForkData, ForkVersion, ForkVersions, PublicKeyPrepared, SigningData,
};
use snowbridge_core::{BasicOperatingMode, RingBufferMap};
use sp_core::H256;
Expand Down Expand Up @@ -242,13 +244,18 @@ pub mod pallet {
.hash_tree_root()
.map_err(|_| Error::<T>::SyncCommitteeHashTreeRootFailed)?;

let fork_versions = T::ForkVersions::get();
let sync_committee_g_index = Self::current_sync_committee_gindex_at_slot(
update.header.slot,
fork_versions.clone(),
);
// Verifies the sync committee in the Beacon state.
ensure!(
verify_merkle_branch(
sync_committee_root,
&update.current_sync_committee_branch,
config::CURRENT_SYNC_COMMITTEE_SUBTREE_INDEX,
config::CURRENT_SYNC_COMMITTEE_DEPTH,
subtree_index(sync_committee_g_index),
generalized_index_length(sync_committee_g_index),
update.header.state_root
),
Error::<T>::InvalidSyncCommitteeMerkleProof
Expand All @@ -262,12 +269,14 @@ pub mod pallet {
// This is used for ancestry proofs in ExecutionHeader updates. This verifies the
// BeaconState: the beacon state root is the tree root; the `block_roots` hash is the
// tree leaf.
let block_roots_g_index =
Self::block_roots_gindex_at_slot(update.header.slot, fork_versions);
ensure!(
verify_merkle_branch(
update.block_roots_root,
&update.block_roots_branch,
config::BLOCK_ROOTS_SUBTREE_INDEX,
config::BLOCK_ROOTS_DEPTH,
subtree_index(block_roots_g_index),
generalized_index_length(block_roots_g_index),
update.header.state_root
),
Error::<T>::InvalidBlockRootsRootMerkleProof
Expand Down Expand Up @@ -345,8 +354,13 @@ pub mod pallet {
Error::<T>::InvalidFinalizedHeaderGap
);

// Verify that the `finality_branch`, if present, confirms `finalized_header` to match
// the finalized checkpoint root saved in the state of `attested_header`.
let fork_versions = T::ForkVersions::get();
let finalized_root_g_index = Self::finalized_root_gindex_at_slot(
update.attested_header.slot,
fork_versions.clone(),
); // TODO check attested / finalized header slot
// Verify that the `finality_branch`, if present, confirms `finalized_header` to match
// the finalized checkpoint root saved in the state of `attested_header`.
let finalized_block_root: H256 = update
.finalized_header
.hash_tree_root()
Expand All @@ -355,8 +369,8 @@ pub mod pallet {
verify_merkle_branch(
finalized_block_root,
&update.finality_branch,
config::FINALIZED_ROOT_SUBTREE_INDEX,
config::FINALIZED_ROOT_DEPTH,
subtree_index(finalized_root_g_index),
generalized_index_length(finalized_root_g_index),
update.attested_header.state_root
),
Error::<T>::InvalidHeaderMerkleProof
Expand All @@ -365,12 +379,16 @@ pub mod pallet {
// Though following check does not belong to ALC spec we verify block_roots_root to
// match the finalized checkpoint root saved in the state of `finalized_header` so to
// cache it for later use in `verify_ancestry_proof`.
let block_roots_g_index = Self::block_roots_gindex_at_slot(
update.finalized_header.slot,
fork_versions.clone(),
);
ensure!(
verify_merkle_branch(
update.block_roots_root,
&update.block_roots_branch,
config::BLOCK_ROOTS_SUBTREE_INDEX,
config::BLOCK_ROOTS_DEPTH,
subtree_index(block_roots_g_index),
generalized_index_length(block_roots_g_index),
update.finalized_header.state_root
),
Error::<T>::InvalidBlockRootsRootMerkleProof
Expand All @@ -390,12 +408,16 @@ pub mod pallet {
Error::<T>::InvalidSyncCommitteeUpdate
);
}
let next_sync_committee_g_index = Self::next_sync_committee_gindex_at_slot(
update.attested_header.slot,
fork_versions,
);
ensure!(
verify_merkle_branch(
sync_committee_root,
&next_sync_committee_update.next_sync_committee_branch,
config::NEXT_SYNC_COMMITTEE_SUBTREE_INDEX,
config::NEXT_SYNC_COMMITTEE_DEPTH,
subtree_index(next_sync_committee_g_index),
generalized_index_length(next_sync_committee_g_index),
update.attested_header.state_root
),
Error::<T>::InvalidSyncCommitteeMerkleProof
Expand Down Expand Up @@ -599,6 +621,9 @@ pub mod pallet {

/// Returns the fork version based on the current epoch.
pub(super) fn select_fork_version(fork_versions: &ForkVersions, epoch: u64) -> ForkVersion {
if epoch >= fork_versions.electra.epoch {
return fork_versions.electra.version
}
if epoch >= fork_versions.deneb.epoch {
return fork_versions.deneb.version
}
Expand Down Expand Up @@ -670,5 +695,58 @@ pub mod pallet {

Pays::Yes
}

pub fn finalized_root_gindex_at_slot(slot: u64, fork_versions: ForkVersions) -> usize {
let epoch = compute_epoch(slot, config::SLOTS_PER_EPOCH as u64);

if epoch >= fork_versions.electra.epoch {
return config::electra::FINALIZED_ROOT_INDEX;
}

config::altair::FINALIZED_ROOT_INDEX
}

pub fn current_sync_committee_gindex_at_slot(
slot: u64,
fork_versions: ForkVersions,
) -> usize {
let epoch = compute_epoch(slot, config::SLOTS_PER_EPOCH as u64);

if epoch >= fork_versions.electra.epoch {
return config::electra::CURRENT_SYNC_COMMITTEE_INDEX;
}

config::altair::CURRENT_SYNC_COMMITTEE_INDEX
}

pub fn next_sync_committee_gindex_at_slot(slot: u64, fork_versions: ForkVersions) -> usize {
let epoch = compute_epoch(slot, config::SLOTS_PER_EPOCH as u64);

if epoch >= fork_versions.electra.epoch {
return config::electra::NEXT_SYNC_COMMITTEE_INDEX;
}

config::altair::NEXT_SYNC_COMMITTEE_INDEX
}

pub fn block_roots_gindex_at_slot(slot: u64, fork_versions: ForkVersions) -> usize {
let epoch = compute_epoch(slot, config::SLOTS_PER_EPOCH as u64);

if epoch >= fork_versions.electra.epoch {
return config::electra::BLOCK_ROOTS_INDEX;
}

config::altair::BLOCK_ROOTS_INDEX
}

pub fn execution_header_gindex_at_slot(slot: u64, fork_versions: ForkVersions) -> usize {
let epoch = compute_epoch(slot, config::SLOTS_PER_EPOCH as u64);

if epoch >= fork_versions.electra.epoch {
return config::electra::EXECUTION_HEADER_INDEX;
}

config::altair::EXECUTION_HEADER_INDEX
}
}
}
6 changes: 5 additions & 1 deletion bridges/snowbridge/pallets/ethereum-client/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,12 @@ parameter_types! {
epoch: 0,
},
deneb: Fork {
version: [4, 0, 0, 0], // 0x90000073
version: [4, 0, 0, 0], // 0x04000000
epoch: 0,
},
electra: Fork {
version: [5, 0, 0, 0], // 0x05000000
epoch: 80000000000,
}
};
}
Expand Down
Loading
Loading