Skip to content
This repository has been archived by the owner on Oct 22, 2024. It is now read-only.

Commit

Permalink
Clara/sno 367 check for extended gap between header imports (parityte…
Browse files Browse the repository at this point in the history
…ch#742)

* Starts working on weak subjectivity period check

* Adds weak subjectivity check.

* fmt

* Adds WeakSubjectivityPeriod config to snowblink and snowbridge runtime.

* Fix tests.

* Fix tab.

* Converts weak subjectivity check to system time instead of block time. Adds bridge blocked flag.

* Fix tests and fmt

* Tiny update

* Reverts some of the logic to make way for long range attack governance handling.

* Refactors finalized header state into a single storage item. Use config for weak subjectivity period check.

* fmt and fix benchmarks, tests

* Fix tests

Co-authored-by: claravanstaden <Cats 4 life!>
  • Loading branch information
claravanstaden authored Jan 18, 2023
1 parent 3df6afc commit 5cb7c31
Show file tree
Hide file tree
Showing 15 changed files with 198 additions and 71 deletions.
1 change: 1 addition & 0 deletions parachain/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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 @@ -38,6 +38,7 @@ sp-keyring = { git = "https://github.com/paritytech/substrate.git", branch = "po
snowbridge-testutils = { path = "../../primitives/testutils" }
serde_json = "1.0.68"
hex-literal = { version = "0.3.4" }
pallet-timestamp = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.30", default-features = false }

[features]
default = ["std"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ pub fn initial_sync<SyncCommitteeSize: Get<u32>, ProofSize: Get<u32>>(
hex!("b132c9711ec41fb5b14de2c9d06da61cd09f57da54ca5556e70824e4787a1e84").into()
].try_into().expect("too many branch proof items"),
validators_root: hex!("043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb").into()
}
};
}

pub fn sync_committee_update<
Expand Down Expand Up @@ -3634,5 +3634,5 @@ pub fn block_update<
sync_committee_signature: hex!("802cbd03fec8b80a253aa8327cb66fe04684495742a0ef68bae487055f5bd71f00b082b1a1e10a7405e0a518bf06886817bad957aece07f119c66212422b5ce9d09c7c2eebf98a4f04a6bbec1a1fff31568380af32e26fcebc6cb2fbd423ca45").to_vec().try_into().expect("signature too long"),
},
signature_slot: 4485186
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ benchmarks! {

let block_update = data::block_update();

LatestFinalizedHeaderSlot::<T>::set(block_update.block.slot);
LatestFinalizedHeaderState::<T>::set(FinalizedHeaderState{
beacon_block_root: H256::default(),
beacon_slot: block_update.block.slot,
import_time: 0,
});
}: _(RawOrigin::Signed(caller.clone()), block_update.clone())
verify {
let block_hash: H256 = block_update.block.body.execution_payload.block_hash;
Expand Down
76 changes: 65 additions & 11 deletions parachain/pallets/ethereum-beacon-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ mod benchmarking;
pub use weights::WeightInfo;

use crate::merkleization::get_sync_committee_bits;
use frame_support::{dispatch::DispatchResult, log, transactional};
use frame_support::{dispatch::DispatchResult, log, traits::UnixTime, transactional};
use frame_system::ensure_signed;
use snowbridge_beacon_primitives::{
BeaconHeader, BlockUpdate, Domain, ExecutionHeader, ExecutionHeaderState,
BeaconHeader, BlockUpdate, Domain, ExecutionHeader, ExecutionHeaderState, FinalizedHeaderState,
FinalizedHeaderUpdate, ForkData, ForkVersion, InitialSync, PublicKey, Root, SigningData,
SyncCommittee, SyncCommitteePeriodUpdate,
};
Expand Down Expand Up @@ -82,6 +82,7 @@ pub mod pallet {
#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type TimeProvider: UnixTime;
#[pallet::constant]
type MaxSyncCommitteeSize: Get<u32>;
#[pallet::constant]
Expand Down Expand Up @@ -111,6 +112,7 @@ pub mod pallet {
#[pallet::constant]
type ForkVersions: Get<ForkVersions>;
type WeightInfo: WeightInfo;
type WeakSubjectivityPeriodSeconds: Get<u32>;
}

#[pallet::event]
Expand Down Expand Up @@ -146,6 +148,7 @@ pub mod pallet {
SigningRootHashTreeRootFailed,
ForkDataHashTreeRootFailed,
ExecutionHeaderNotLatest,
BridgeBlocked,
}

#[pallet::hooks]
Expand All @@ -169,10 +172,8 @@ pub mod pallet {
pub(super) type ValidatorsRoot<T: Config> = StorageValue<_, H256, ValueQuery>;

#[pallet::storage]
pub(super) type LatestFinalizedHeaderHash<T: Config> = StorageValue<_, H256, ValueQuery>;

#[pallet::storage]
pub(super) type LatestFinalizedHeaderSlot<T: Config> = StorageValue<_, u64, ValueQuery>;
pub(super) type LatestFinalizedHeaderState<T: Config> =
StorageValue<_, FinalizedHeaderState, ValueQuery>;

#[pallet::storage]
pub(super) type LatestExecutionHeaderState<T: Config> =
Expand All @@ -181,6 +182,9 @@ pub mod pallet {
#[pallet::storage]
pub(super) type LatestSyncCommitteePeriod<T: Config> = StorageValue<_, u64, ValueQuery>;

#[pallet::storage]
pub(super) type Blocked<T: Config> = StorageValue<_, bool, ValueQuery>;

#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
pub initial_sync: Option<InitialSyncOf<T>>,
Expand Down Expand Up @@ -218,6 +222,8 @@ pub mod pallet {
) -> DispatchResult {
let _sender = ensure_signed(origin)?;

Self::check_bridge_blocked_state()?;

let sync_committee_period = sync_committee_period_update.sync_committee_period;
log::info!(
target: "ethereum-beacon-client",
Expand Down Expand Up @@ -253,6 +259,8 @@ pub mod pallet {
) -> DispatchResult {
let _sender = ensure_signed(origin)?;

Self::check_bridge_blocked_state()?;

let slot = finalized_header_update.finalized_header.slot;

log::info!(
Expand Down Expand Up @@ -287,6 +295,8 @@ pub mod pallet {
) -> DispatchResult {
let _sender = ensure_signed(origin)?;

Self::check_bridge_blocked_state()?;

let slot = update.block.slot;
let block_hash = update.block.body.execution_payload.block_hash;

Expand Down Expand Up @@ -314,6 +324,18 @@ pub mod pallet {

Ok(())
}

#[pallet::weight(1000)]
#[transactional]
pub fn unblock_bridge(origin: OriginFor<T>) -> DispatchResult {
let _sender = ensure_root(origin)?;

<Blocked<T>>::set(false);

log::info!(target: "ethereum-beacon-client","💫 syncing bridge from governance provided checkpoint.");

Ok(())
}
}

impl<T: Config> Pallet<T> {
Expand Down Expand Up @@ -387,6 +409,25 @@ pub mod pallet {
}

fn process_finalized_header(update: FinalizedHeaderUpdateOf<T>) -> DispatchResult {
let last_finalized_header = <LatestFinalizedHeaderState<T>>::get();
let import_time = last_finalized_header.import_time;
let weak_subjectivity_period_check =
import_time + T::WeakSubjectivityPeriodSeconds::get() as u64;
let time: u64 = T::TimeProvider::now().as_secs();

log::info!(
target: "ethereum-beacon-client",
"💫 Checking weak subjectivity period. Current time is :{:?} Weak subjectvitity period check: {:?}.",
time,
weak_subjectivity_period_check
);

if time > weak_subjectivity_period_check {
log::info!(target: "ethereum-beacon-client","💫 Weak subjectivity period exceeded, blocking bridge.",);
<Blocked<T>>::set(true);
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)?;
Expand Down Expand Up @@ -423,7 +464,8 @@ pub mod pallet {
}

fn process_header(update: BlockUpdateOf<T>) -> DispatchResult {
let latest_finalized_header_slot = <LatestFinalizedHeaderSlot<T>>::get();
let last_finalized_header = <LatestFinalizedHeaderState<T>>::get();
let latest_finalized_header_slot = last_finalized_header.beacon_slot;
let block_slot = update.block.slot;
if block_slot > latest_finalized_header_slot {
return Err(Error::<T>::HeaderNotFinalized.into())
Expand All @@ -447,7 +489,7 @@ pub mod pallet {
let beacon_block_root: H256 =
merkleization::hash_tree_root_beacon_header(header.clone())
.map_err(|_| Error::<T>::HeaderHashTreeRootFailed)?
.into();
.into(); // TODO check denylist headers

let validators_root = <ValidatorsRoot<T>>::get();
let sync_committee_bits =
Expand Down Expand Up @@ -501,6 +543,14 @@ pub mod pallet {
Ok(())
}

fn check_bridge_blocked_state() -> DispatchResult {
if <Blocked<T>>::get() {
return Err(Error::<T>::BridgeBlocked.into())
}

Ok(())
}

pub(super) fn verify_signed_header(
sync_committee_bits: Vec<u8>,
sync_committee_signature: BoundedVec<u8, T::MaxSignatureSize>,
Expand Down Expand Up @@ -679,16 +729,20 @@ pub mod pallet {
slot
);

let latest_finalized_header_slot = <LatestFinalizedHeaderSlot<T>>::get();
let mut last_finalized_header = <LatestFinalizedHeaderState<T>>::get();
let latest_finalized_header_slot = last_finalized_header.beacon_slot;

if slot > latest_finalized_header_slot {
log::trace!(
target: "ethereum-beacon-client",
"💫 Updated latest finalized slot to {}.",
slot
);
<LatestFinalizedHeaderSlot<T>>::set(slot);
<LatestFinalizedHeaderHash<T>>::set(block_root);
last_finalized_header.import_time = T::TimeProvider::now().as_secs();
last_finalized_header.beacon_block_root = block_root;
last_finalized_header.beacon_slot = slot;

<LatestFinalizedHeaderState<T>>::set(last_finalized_header);
}

Self::deposit_event(Event::BeaconHeaderImported { block_hash: block_root, slot });
Expand Down
77 changes: 50 additions & 27 deletions parachain/pallets/ethereum-beacon-client/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::*;
use crate as ethereum_beacon_client;
use frame_support::parameter_types;
use frame_system as system;
use pallet_timestamp;
use snowbridge_beacon_primitives::{AttesterSlashing, BeaconHeader, Body, Fork, ForkVersions};
use sp_core::H256;
use sp_runtime::{
Expand All @@ -23,6 +24,7 @@ pub mod mock_minimal {
UncheckedExtrinsic = UncheckedExtrinsic,
{
System: frame_system::{Pallet, Call, Storage, Event<T>},
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
EthereumBeaconClient: ethereum_beacon_client::{Pallet, Call, Config<T>, Storage, Event<T>},
}
);
Expand Down Expand Up @@ -59,6 +61,13 @@ pub mod mock_minimal {
type MaxConsumers = frame_support::traits::ConstU32<16>;
}

impl pallet_timestamp::Config for Test {
type Moment = u64;
type OnTimestampSet = ();
type MinimumPeriod = ();
type WeightInfo = ();
}

parameter_types! {
pub const MaxSyncCommitteeSize: u32 = config::SYNC_COMMITTEE_SIZE as u32;
pub const MaxProofBranchSize: u32 = 6;
Expand All @@ -73,6 +82,7 @@ pub mod mock_minimal {
pub const MaxVoluntaryExitSize: u32 = config::MAX_VOLUNTARY_EXITS as u32;
pub const MaxAttestationSize: u32 = config::MAX_ATTESTATIONS as u32;
pub const MaxValidatorsPerCommittee: u32 = config::MAX_VALIDATORS_PER_COMMITTEE as u32;
pub const WeakSubjectivityPeriodSeconds: u32 = 97200;
pub const ChainForkVersions: ForkVersions = ForkVersions{
genesis: Fork {
version: [0, 0, 0, 1], // 0x00000001
Expand All @@ -90,6 +100,7 @@ pub mod mock_minimal {
}

impl ethereum_beacon_client::Config for Test {
type TimeProvider = pallet_timestamp::Pallet<Test>;
type RuntimeEvent = RuntimeEvent;
type MaxSyncCommitteeSize = MaxSyncCommitteeSize;
type MaxProofBranchSize = MaxProofBranchSize;
Expand All @@ -105,6 +116,7 @@ pub mod mock_minimal {
type MaxAttestationSize = MaxAttestationSize;
type MaxValidatorsPerCommittee = MaxValidatorsPerCommittee;
type ForkVersions = ChainForkVersions;
type WeakSubjectivityPeriodSeconds = WeakSubjectivityPeriodSeconds;
type WeightInfo = ();
}
}
Expand All @@ -122,6 +134,7 @@ pub mod mock_mainnet {
UncheckedExtrinsic = UncheckedExtrinsic,
{
System: frame_system::{Pallet, Call, Storage, Event<T>},
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
EthereumBeaconClient: ethereum_beacon_client::{Pallet, Call, Config<T>, Storage, Event<T>},
}
);
Expand Down Expand Up @@ -158,38 +171,47 @@ pub mod mock_mainnet {
type MaxConsumers = frame_support::traits::ConstU32<16>;
}

impl pallet_timestamp::Config for Test {
type Moment = u64;
type OnTimestampSet = ();
type MinimumPeriod = ();
type WeightInfo = ();
}

parameter_types! {
pub const MaxSyncCommitteeSize: u32 = config::SYNC_COMMITTEE_SIZE as u32;
pub const MaxProofBranchSize: u32 = 6;
pub const MaxExtraDataSize: u32 = config::MAX_EXTRA_DATA_BYTES as u32;
pub const MaxLogsBloomSize: u32 = config::MAX_LOGS_BLOOM_SIZE as u32;
pub const MaxFeeRecipientSize: u32 = config::MAX_FEE_RECIPIENT_SIZE as u32;
pub const MaxDepositDataSize: u32 = config::MAX_DEPOSITS as u32;
pub const MaxPublicKeySize: u32 = config::PUBKEY_SIZE as u32;
pub const MaxSignatureSize: u32 = config::SIGNATURE_SIZE as u32;
pub const MaxProposerSlashingSize: u32 = config::MAX_PROPOSER_SLASHINGS as u32;
pub const MaxAttesterSlashingSize: u32 = config::MAX_ATTESTER_SLASHINGS as u32;
pub const MaxVoluntaryExitSize: u32 = config::MAX_VOLUNTARY_EXITS as u32;
pub const MaxAttestationSize: u32 = config::MAX_ATTESTATIONS as u32;
pub const MaxValidatorsPerCommittee: u32 = config::MAX_VALIDATORS_PER_COMMITTEE as u32;
pub const ChainForkVersions: ForkVersions = ForkVersions{
genesis: Fork {
version: [0, 0, 16, 32], // 0x00001020
epoch: 0,
},
altair: Fork {
version: [1, 0, 16, 32], // 0x01001020
epoch: 36660,
},
bellatrix: Fork {
version: [2, 0, 16, 32], // 0x02001020
epoch: 112260,
},
};
pub const MaxSyncCommitteeSize: u32 = config::SYNC_COMMITTEE_SIZE as u32;
pub const MaxProofBranchSize: u32 = 6;
pub const MaxExtraDataSize: u32 = config::MAX_EXTRA_DATA_BYTES as u32;
pub const MaxLogsBloomSize: u32 = config::MAX_LOGS_BLOOM_SIZE as u32;
pub const MaxFeeRecipientSize: u32 = config::MAX_FEE_RECIPIENT_SIZE as u32;
pub const MaxDepositDataSize: u32 = config::MAX_DEPOSITS as u32;
pub const MaxPublicKeySize: u32 = config::PUBKEY_SIZE as u32;
pub const MaxSignatureSize: u32 = config::SIGNATURE_SIZE as u32;
pub const MaxProposerSlashingSize: u32 = config::MAX_PROPOSER_SLASHINGS as u32;
pub const MaxAttesterSlashingSize: u32 = config::MAX_ATTESTER_SLASHINGS as u32;
pub const MaxVoluntaryExitSize: u32 = config::MAX_VOLUNTARY_EXITS as u32;
pub const MaxAttestationSize: u32 = config::MAX_ATTESTATIONS as u32;
pub const MaxValidatorsPerCommittee: u32 = config::MAX_VALIDATORS_PER_COMMITTEE as u32;
pub const WeakSubjectivityPeriodSeconds: u32 = 97200;
pub const ChainForkVersions: ForkVersions = ForkVersions{
genesis: Fork {
version: [0, 0, 16, 32], // 0x00001020
epoch: 0,
},
altair: Fork {
version: [1, 0, 16, 32], // 0x01001020
epoch: 36660,
},
bellatrix: Fork {
version: [2, 0, 16, 32], // 0x02001020
epoch: 112260,
},
};
}

impl ethereum_beacon_client::Config for Test {
type RuntimeEvent = RuntimeEvent;
type TimeProvider = pallet_timestamp::Pallet<Test>;
type MaxSyncCommitteeSize = MaxSyncCommitteeSize;
type MaxProofBranchSize = MaxProofBranchSize;
type MaxExtraDataSize = MaxExtraDataSize;
Expand All @@ -204,6 +226,7 @@ pub mod mock_mainnet {
type MaxAttestationSize = MaxAttestationSize;
type MaxValidatorsPerCommittee = MaxValidatorsPerCommittee;
type ForkVersions = ChainForkVersions;
type WeakSubjectivityPeriodSeconds = WeakSubjectivityPeriodSeconds;
type WeightInfo = ();
}
}
Expand Down
Loading

0 comments on commit 5cb7c31

Please sign in to comment.