Skip to content

Commit

Permalink
Make snowbridge-ethereum-beacon-client generic over the network it …
Browse files Browse the repository at this point in the history
…is built for
  • Loading branch information
nazar-pc committed Mar 14, 2023
1 parent 794f9e1 commit 80c2ad4
Show file tree
Hide file tree
Showing 13 changed files with 157 additions and 80 deletions.
1 change: 1 addition & 0 deletions parachain/pallets/ethereum-beacon-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,5 @@ runtime-benchmarks = [
"frame-system/runtime-benchmarks",
"hex-literal"
]
# Feature only used for testing and benchmarking
minimal = []
13 changes: 2 additions & 11 deletions parachain/pallets/ethereum-beacon-client/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
#[cfg(feature = "minimal")]
mod minimal;

#[cfg(not(feature = "minimal"))]
mod mainnet;

#[cfg(feature = "minimal")]
pub use minimal::*;

#[cfg(not(feature = "minimal"))]
pub use mainnet::*;
pub mod mainnet;
pub mod minimal;

pub const CURRENT_SYNC_COMMITTEE_INDEX: u64 = 22;
pub const CURRENT_SYNC_COMMITTEE_DEPTH: u64 = 5;
Expand Down
71 changes: 48 additions & 23 deletions parachain/pallets/ethereum-beacon-client/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! # Ethereum Beacon Client
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]

pub mod config;
mod merkleization;
Expand Down Expand Up @@ -102,6 +104,11 @@ pub mod pallet {
type ForkVersions: Get<ForkVersions>;
type WeightInfo: WeightInfo;
type WeakSubjectivityPeriodSeconds: Get<u64>;

const SLOTS_PER_EPOCH: u64;
const EPOCHS_PER_SYNC_COMMITTEE_PERIOD: u64;
const SYNC_COMMITTEE_SIZE: usize;
const BLOCK_ROOT_AT_INDEX_PROOF_DEPTH: u64;
}

#[pallet::event]
Expand Down Expand Up @@ -211,12 +218,15 @@ pub mod pallet {
}

#[pallet::genesis_build]
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
impl<T: Config> GenesisBuild<T> for GenesisConfig<T>
where
[(); T::SYNC_COMMITTEE_SIZE]: Sized,
{
fn build(&self) {
log::info!(
target: "ethereum-beacon-client",
"💫 Sync committee size is: {}",
config::SYNC_COMMITTEE_SIZE
T::SYNC_COMMITTEE_SIZE
);

if let Some(initial_sync) = self.initial_sync.clone() {
Expand All @@ -226,7 +236,10 @@ pub mod pallet {
}

#[pallet::call]
impl<T: Config> Pallet<T> {
impl<T: Config> Pallet<T>
where
[(); T::SYNC_COMMITTEE_SIZE]: Sized,
{
#[pallet::call_index(0)]
#[pallet::weight(T::WeightInfo::sync_committee_period_update())]
#[transactional]
Expand Down Expand Up @@ -355,9 +368,12 @@ pub mod pallet {
}
}

impl<T: Config> Pallet<T> {
impl<T: Config> Pallet<T>
where
[(); T::SYNC_COMMITTEE_SIZE]: Sized,
{
fn process_initial_sync(initial_sync: InitialSyncOf<T>) -> DispatchResult {
Self::verify_sync_committee(
Self::verify_sync_committee::<{ T::SYNC_COMMITTEE_SIZE }>(
initial_sync.current_sync_committee.clone(),
initial_sync.current_sync_committee_branch,
initial_sync.header.state_root,
Expand Down Expand Up @@ -398,11 +414,12 @@ pub mod pallet {
update.attested_header.slot >= update.finalized_header.slot,
Error::<T>::InvalidSyncCommitteeHeaderUpdate
);
let sync_committee_bits =
get_sync_committee_bits(update.sync_aggregate.sync_committee_bits.clone())
.map_err(|_| Error::<T>::InvalidSyncCommitteeBits)?;
let sync_committee_bits = get_sync_committee_bits::<_, { T::SYNC_COMMITTEE_SIZE }>(
update.sync_aggregate.sync_committee_bits.clone(),
)
.map_err(|_| Error::<T>::InvalidSyncCommitteeBits)?;
Self::sync_committee_participation_is_supermajority(sync_committee_bits.clone())?;
Self::verify_sync_committee(
Self::verify_sync_committee::<{ T::SYNC_COMMITTEE_SIZE }>(
update.next_sync_committee.clone(),
update.next_sync_committee_branch,
update.attested_header.state_root,
Expand Down Expand Up @@ -501,9 +518,10 @@ pub mod pallet {
return Err(Error::<T>::BridgeBlocked.into())
}

let sync_committee_bits =
get_sync_committee_bits(update.sync_aggregate.sync_committee_bits.clone())
.map_err(|_| Error::<T>::InvalidSyncCommitteeBits)?;
let sync_committee_bits = get_sync_committee_bits::<_, { T::SYNC_COMMITTEE_SIZE }>(
update.sync_aggregate.sync_committee_bits.clone(),
)
.map_err(|_| Error::<T>::InvalidSyncCommitteeBits)?;
Self::sync_committee_participation_is_supermajority(sync_committee_bits.clone())?;

let block_root: H256 =
Expand Down Expand Up @@ -608,9 +626,10 @@ pub mod pallet {
let sync_committee = Self::get_sync_committee_for_period(current_period)?;

let validators_root = <ValidatorsRoot<T>>::get();
let sync_committee_bits =
get_sync_committee_bits(update.sync_aggregate.sync_committee_bits.clone())
.map_err(|_| Error::<T>::InvalidSyncCommitteeBits)?;
let sync_committee_bits = get_sync_committee_bits::<_, { T::SYNC_COMMITTEE_SIZE }>(
update.sync_aggregate.sync_committee_bits.clone(),
)
.map_err(|_| Error::<T>::InvalidSyncCommitteeBits)?;

Self::verify_signed_header(
sync_committee_bits,
Expand Down Expand Up @@ -706,14 +725,14 @@ pub mod pallet {

log::info!(
target: "ethereum-beacon-client",
"💫 Depth: {} leaf_index: {}", config::BLOCK_ROOT_AT_INDEX_PROOF_DEPTH, leaf_index
"💫 Depth: {} leaf_index: {}", T::BLOCK_ROOT_AT_INDEX_PROOF_DEPTH, leaf_index
);

ensure!(
Self::is_valid_merkle_branch(
beacon_block_root,
block_root_proof,
config::BLOCK_ROOT_AT_INDEX_PROOF_DEPTH,
T::BLOCK_ROOT_AT_INDEX_PROOF_DEPTH,
leaf_index,
finalized_block_root_hash
),
Expand Down Expand Up @@ -751,7 +770,7 @@ pub mod pallet {

let fork_version = Self::compute_fork_version(Self::compute_epoch_at_slot(
signature_slot,
config::SLOTS_PER_EPOCH,
T::SLOTS_PER_EPOCH,
));
let domain_type = config::DOMAIN_SYNC_COMMITTEE.to_vec();
// Domains are used for for seeds, for signatures, and for selecting aggregators.
Expand Down Expand Up @@ -831,15 +850,18 @@ pub mod pallet {
Ok(hash_root.into())
}

fn verify_sync_committee(
fn verify_sync_committee<const SYNC_COMMITTEE_SIZE: usize>(
sync_committee: SyncCommitteeOf<T>,
sync_committee_branch: BoundedVec<H256, T::MaxProofBranchSize>,
header_state_root: H256,
depth: u64,
index: u64,
) -> DispatchResult {
let sync_committee_root = merkleization::hash_tree_root_sync_committee(sync_committee)
.map_err(|_| Error::<T>::SyncCommitteeHashTreeRootFailed)?;
let sync_committee_root = merkleization::hash_tree_root_sync_committee::<
_,
SYNC_COMMITTEE_SIZE,
>(sync_committee)
.map_err(|_| Error::<T>::SyncCommitteeHashTreeRootFailed)?;

ensure!(
Self::is_valid_merkle_branch(
Expand Down Expand Up @@ -968,7 +990,7 @@ pub mod pallet {
}

pub(super) fn compute_current_sync_period(slot: u64) -> u64 {
slot / config::SLOTS_PER_EPOCH / config::EPOCHS_PER_SYNC_COMMITTEE_PERIOD
slot / T::SLOTS_PER_EPOCH / T::EPOCHS_PER_SYNC_COMMITTEE_PERIOD
}

/// Return the domain for the domain_type and fork_version.
Expand Down Expand Up @@ -1127,7 +1149,10 @@ pub mod pallet {
}
}

impl<T: Config> Verifier for Pallet<T> {
impl<T: Config> Verifier for Pallet<T>
where
[(); T::SYNC_COMMITTEE_SIZE]: Sized,
{
/// Verify a message by verifying the existence of the corresponding
/// Ethereum log in a block. Returns the log if successful.
fn verify(message: &Message) -> Result<(Log, u64), DispatchError> {
Expand Down
28 changes: 16 additions & 12 deletions parachain/pallets/ethereum-beacon-client/src/merkleization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,20 @@ impl TryFrom<BeaconHeader> for SSZBeaconBlockHeader {
}
}

impl<SyncCommitteeBitsSize: Get<u32>, SignatureSize: Get<u32>>
TryFrom<SyncAggregate<SyncCommitteeBitsSize, SignatureSize>> for SSZSyncAggregate
impl<
SyncCommitteeBitsSize: Get<u32>,
SignatureSize: Get<u32>,
const SYNC_COMMITTEE_SIZE: usize,
> TryFrom<SyncAggregate<SyncCommitteeBitsSize, SignatureSize>>
for SSZSyncAggregate<SYNC_COMMITTEE_SIZE>
{
type Error = MerkleizationError;

fn try_from(
sync_aggregate: SyncAggregate<SyncCommitteeBitsSize, SignatureSize>,
) -> Result<Self, Self::Error> {
Ok(SSZSyncAggregate {
sync_committee_bits: Bitvector::<{ config::SYNC_COMMITTEE_SIZE }>::deserialize(
&sync_aggregate.sync_committee_bits,
)?,
sync_committee_bits: Bitvector::deserialize(&sync_aggregate.sync_committee_bits)?,
sync_committee_signature: Vector::<u8, 96>::from_iter(
sync_aggregate.sync_committee_signature,
),
Expand Down Expand Up @@ -121,7 +123,7 @@ pub fn hash_tree_root_execution_header<
hash_tree_root(ssz_execution_payload)
}

pub fn hash_tree_root_sync_committee<S: Get<u32>>(
pub fn hash_tree_root_sync_committee<S: Get<u32>, const SYNC_COMMITTEE_SIZE: usize>(
sync_committee: SyncCommittee<S>,
) -> Result<[u8; 32], MerkleizationError> {
let mut pubkeys_vec = Vec::new();
Expand All @@ -132,10 +134,9 @@ pub fn hash_tree_root_sync_committee<S: Get<u32>>(
pubkeys_vec.push(conv_pubkey);
}

let pubkeys =
Vector::<Vector<u8, { config::PUBKEY_SIZE }>, { config::SYNC_COMMITTEE_SIZE }>::from_iter(
pubkeys_vec.clone(),
);
let pubkeys = Vector::<Vector<u8, { config::PUBKEY_SIZE }>, SYNC_COMMITTEE_SIZE>::from_iter(
pubkeys_vec.clone(),
);

let agg = Vector::<u8, { config::PUBKEY_SIZE }>::from_iter(sync_committee.aggregate_pubkey.0);

Expand Down Expand Up @@ -170,10 +171,13 @@ pub fn hash_tree_root<T: SimpleSerializeTrait>(
}
}

pub fn get_sync_committee_bits<SyncCommitteeBitsSize: Get<u32>>(
pub fn get_sync_committee_bits<
SyncCommitteeBitsSize: Get<u32>,
const SYNC_COMMITTEE_SIZE: usize,
>(
bits_hex: BoundedVec<u8, SyncCommitteeBitsSize>,
) -> Result<Vec<u8>, MerkleizationError> {
let bitv = Bitvector::<{ config::SYNC_COMMITTEE_SIZE }>::deserialize(&bits_hex).map_err(
let bitv = Bitvector::<SYNC_COMMITTEE_SIZE>::deserialize(&bits_hex).map_err(
//|_| MerkleizationError::InvalidInput
|e| -> MerkleizationError {
match e {
Expand Down
29 changes: 21 additions & 8 deletions parachain/pallets/ethereum-beacon-client/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::{fs::File, path::PathBuf};

pub mod mock_minimal {
use super::*;

use crate::config::minimal;
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;

Expand Down Expand Up @@ -69,7 +69,7 @@ pub mod mock_minimal {
}

parameter_types! {
pub const MaxSyncCommitteeSize: u32 = config::SYNC_COMMITTEE_SIZE as u32;
pub const MaxSyncCommitteeSize: u32 = minimal::SYNC_COMMITTEE_SIZE as u32;
pub const MaxProofBranchSize: u32 = 20;
pub const MaxExtraDataSize: u32 = config::MAX_EXTRA_DATA_BYTES as u32;
pub const MaxLogsBloomSize: u32 = config::MAX_LOGS_BLOOM_SIZE as u32;
Expand Down Expand Up @@ -110,11 +110,17 @@ pub mod mock_minimal {
type ForkVersions = ChainForkVersions;
type WeakSubjectivityPeriodSeconds = WeakSubjectivityPeriodSeconds;
type WeightInfo = ();

const SLOTS_PER_EPOCH: u64 = minimal::SLOTS_PER_EPOCH;
const EPOCHS_PER_SYNC_COMMITTEE_PERIOD: u64 = minimal::EPOCHS_PER_SYNC_COMMITTEE_PERIOD;
const SYNC_COMMITTEE_SIZE: usize = minimal::SYNC_COMMITTEE_SIZE;
const BLOCK_ROOT_AT_INDEX_PROOF_DEPTH: u64 = minimal::BLOCK_ROOT_AT_INDEX_PROOF_DEPTH;
}
}

pub mod mock_mainnet {
use super::*;
use crate::config::mainnet;

type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;
Expand Down Expand Up @@ -171,7 +177,7 @@ pub mod mock_mainnet {
}

parameter_types! {
pub const MaxSyncCommitteeSize: u32 = config::SYNC_COMMITTEE_SIZE as u32;
pub const MaxSyncCommitteeSize: u32 = mainnet::SYNC_COMMITTEE_SIZE as u32;
pub const MaxProofBranchSize: u32 = 20;
pub const MaxExtraDataSize: u32 = config::MAX_EXTRA_DATA_BYTES as u32;
pub const MaxLogsBloomSize: u32 = config::MAX_LOGS_BLOOM_SIZE as u32;
Expand Down Expand Up @@ -212,6 +218,11 @@ pub mod mock_mainnet {
type ForkVersions = ChainForkVersions;
type WeakSubjectivityPeriodSeconds = WeakSubjectivityPeriodSeconds;
type WeightInfo = ();

const SLOTS_PER_EPOCH: u64 = mainnet::SLOTS_PER_EPOCH;
const EPOCHS_PER_SYNC_COMMITTEE_PERIOD: u64 = mainnet::EPOCHS_PER_SYNC_COMMITTEE_PERIOD;
const SYNC_COMMITTEE_SIZE: usize = mainnet::SYNC_COMMITTEE_SIZE;
const BLOCK_ROOT_AT_INDEX_PROOF_DEPTH: u64 = mainnet::BLOCK_ROOT_AT_INDEX_PROOF_DEPTH;
}
}

Expand Down Expand Up @@ -276,11 +287,13 @@ fn header_update_from_file<T: crate::Config>(
serde_json::from_reader(File::open(&filepath).unwrap()).unwrap()
}

fn get_config_setting() -> String {
return match config::IS_MINIMAL {
true => "minimal".to_owned(),
false => "mainnet".to_owned(),
}
#[cfg(feature = "minimal")]
fn get_config_setting() -> &'static str {
"minimal"
}
#[cfg(not(feature = "minimal"))]
fn get_config_setting() -> &'static str {
"mainnet"
}

fn add_file_prefix(name: &str) -> String {
Expand Down
8 changes: 4 additions & 4 deletions parachain/pallets/ethereum-beacon-client/src/ssz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ pub struct SSZBeaconBlockHeader {
}

#[derive(Default, SimpleSerialize)]
pub struct SSZSyncCommittee {
pub pubkeys: Vector<Vector<u8, { config::PUBKEY_SIZE }>, { config::SYNC_COMMITTEE_SIZE }>,
pub struct SSZSyncCommittee<const SYNC_COMMITTEE_SIZE: usize> {
pub pubkeys: Vector<Vector<u8, { config::PUBKEY_SIZE }>, SYNC_COMMITTEE_SIZE>,
pub aggregate_pubkey: Vector<u8, { config::PUBKEY_SIZE }>,
}

#[derive(Default, Debug, SimpleSerialize, Clone)]
pub struct SSZSyncAggregate {
pub sync_committee_bits: Bitvector<{ config::SYNC_COMMITTEE_SIZE }>,
pub struct SSZSyncAggregate<const SYNC_COMMITTEE_SIZE: usize> {
pub sync_committee_bits: Bitvector<SYNC_COMMITTEE_SIZE>,
pub sync_committee_signature: Vector<u8, { config::SIGNATURE_SIZE }>,
}

Expand Down
Loading

0 comments on commit 80c2ad4

Please sign in to comment.