From 5bac4ee5ba3a37b072e27593c5dfb0530f46cfa9 Mon Sep 17 00:00:00 2001 From: Ron Date: Thu, 14 Mar 2024 14:54:14 +0800 Subject: [PATCH] Sync execution update on demand (#123) * Sync execution update on demand * Fix updating LatestExecutionState * Revert change unrelated * Remove unused * Remove execution header from update & Remove LatestExecutionState --- .../ethereum-client/fixtures/src/lib.rs | 2 +- .../pallets/ethereum-client/src/lib.rs | 57 +------- .../pallets/ethereum-client/src/tests.rs | 132 +----------------- .../primitives/beacon/src/updates.rs | 15 +- .../bridge-hub-rococo/src/tests/snowbridge.rs | 2 - .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 2 +- 6 files changed, 12 insertions(+), 198 deletions(-) diff --git a/bridges/snowbridge/pallets/ethereum-client/fixtures/src/lib.rs b/bridges/snowbridge/pallets/ethereum-client/fixtures/src/lib.rs index facaffb8149c..d487ae1712c6 100644 --- a/bridges/snowbridge/pallets/ethereum-client/fixtures/src/lib.rs +++ b/bridges/snowbridge/pallets/ethereum-client/fixtures/src/lib.rs @@ -1165,7 +1165,7 @@ pub fn make_finalized_header_update() -> Box { hex!("ecea7e1d3152d8130e83afdfe34b4de4ba2b69a33c9471991096daf454de9cf5").into(), hex!("b2bf1758e50b2bfff29169fbc70fdb884b2b05bb615dbc53567574da6f4f1ae2").into(), hex!("cd87069daf70975779126d6af833b7d636c75ca4d5e750ebcad0e76408a5e5bf").into(), - ] + ], }) } diff --git a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs index a54d4a05ac58..173942e0be43 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs @@ -40,8 +40,8 @@ use frame_support::{ use frame_system::ensure_signed; use primitives::{ fast_aggregate_verify, verify_merkle_branch, verify_receipt_proof, BeaconHeader, BlsError, - CompactBeaconState, CompactExecutionHeader, ExecutionHeaderState, ForkData, ForkVersion, - ForkVersions, PublicKeyPrepared, SigningData, + CompactBeaconState, CompactExecutionHeader, ForkData, ForkVersion, ForkVersions, + PublicKeyPrepared, SigningData, }; use snowbridge_core::{BasicOperatingMode, RingBufferMap}; use sp_core::H256; @@ -187,12 +187,6 @@ pub mod pallet { pub(super) type NextSyncCommittee = StorageValue<_, SyncCommitteePrepared, ValueQuery>; - /// Latest imported execution header - #[pallet::storage] - #[pallet::getter(fn latest_execution_state)] - pub(super) type LatestExecutionState = - StorageValue<_, ExecutionHeaderState, ValueQuery>; - /// Execution Headers #[pallet::storage] pub type ExecutionHeaders = @@ -321,7 +315,6 @@ pub mod pallet { >::set(sync_committee_prepared); >::kill(); InitialCheckpointRoot::::set(header_root); - >::kill(); Self::store_validators_root(update.validators_root); Self::store_finalized_header(header_root, update.header, update.block_roots_root)?; @@ -330,32 +323,11 @@ pub mod pallet { } pub(crate) fn process_update(update: &Update) -> DispatchResult { - Self::cross_check_execution_state()?; Self::verify_update(update)?; Self::apply_update(update)?; Ok(()) } - /// Cross check to make sure that execution header import does not fall too far behind - /// finalised beacon header import. If that happens just return an error and pause - /// processing until execution header processing has caught up. - pub(crate) fn cross_check_execution_state() -> DispatchResult { - let latest_finalized_state = - FinalizedBeaconState::::get(LatestFinalizedBlockRoot::::get()) - .ok_or(Error::::NotBootstrapped)?; - let latest_execution_state = Self::latest_execution_state(); - // The execution header import should be at least within the slot range of a sync - // committee period. - let max_latency = config::EPOCHS_PER_SYNC_COMMITTEE_PERIOD * config::SLOTS_PER_EPOCH; - ensure!( - latest_execution_state.beacon_slot == 0 || - latest_finalized_state.slot < - latest_execution_state.beacon_slot + max_latency as u64, - Error::::ExecutionHeaderTooFarBehind - ); - Ok(()) - } - /// References and strictly follows /// Verifies that provided next sync committee is valid through a series of checks /// (including checking that a sync committee period isn't skipped and that the header is @@ -548,15 +520,6 @@ pub mod pallet { Error::::HeaderNotFinalized ); - // Checks that we don't skip execution headers, they need to be imported sequentially. - let latest_execution_state: ExecutionHeaderState = Self::latest_execution_state(); - ensure!( - latest_execution_state.block_number == 0 || - update.execution_header.block_number() == - latest_execution_state.block_number + 1, - Error::::ExecutionHeaderSkippedBlock - ); - // Gets the hash tree root of the execution header, in preparation for the execution // header proof (used to check that the execution header is rooted in the beacon // header body. @@ -605,8 +568,6 @@ pub mod pallet { Self::store_execution_header( update.execution_header.block_hash(), update.execution_header.clone().into(), - update.header.slot, - block_root, ); Ok(()) @@ -692,12 +653,7 @@ pub mod pallet { /// Stores the provided execution header in pallet storage. The header is stored /// in a ring buffer map, with the block hash as map key. The last imported execution /// header is also kept in storage, for the relayer to check import progress. - pub fn store_execution_header( - block_hash: H256, - header: CompactExecutionHeader, - beacon_slot: u64, - beacon_block_root: H256, - ) { + pub fn store_execution_header(block_hash: H256, header: CompactExecutionHeader) { let block_number = header.block_number; >::insert(block_hash, header); @@ -709,13 +665,6 @@ pub mod pallet { block_number ); - LatestExecutionState::::mutate(|s| { - s.beacon_block_root = beacon_block_root; - s.beacon_slot = beacon_slot; - s.block_hash = block_hash; - s.block_number = block_number; - }); - Self::deposit_event(Event::ExecutionHeaderImported { block_hash, block_number }); } diff --git a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs index 50b6a25c3428..aa2a0e099a88 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs @@ -3,7 +3,7 @@ use crate::{ functions::compute_period, pallet::ExecutionHeaders, sync_committee_sum, verify_merkle_branch, BeaconHeader, CompactBeaconState, Error, ExecutionHeaderBuffer, FinalizedBeaconState, - LatestExecutionState, LatestFinalizedBlockRoot, NextSyncCommittee, SyncCommitteePrepared, + LatestFinalizedBlockRoot, NextSyncCommittee, SyncCommitteePrepared, }; use crate::mock::{ @@ -18,10 +18,7 @@ pub use crate::mock::*; use crate::config::{EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH}; use frame_support::{assert_err, assert_noop, assert_ok}; use hex_literal::hex; -use primitives::{ - CompactExecutionHeader, ExecutionHeaderState, Fork, ForkVersions, NextSyncCommitteeUpdate, - VersionedExecutionPayloadHeader, -}; +use primitives::{CompactExecutionHeader, Fork, ForkVersions, NextSyncCommitteeUpdate}; use rand::{thread_rng, Rng}; use snowbridge_core::{ inbound::{VerificationError, Verifier}, @@ -220,15 +217,10 @@ pub fn execution_header_pruning() { let mut stored_hashes = vec![]; - for i in 0..execution_header_prune_threshold { + for _ in 0..execution_header_prune_threshold { let mut hash = H256::default(); thread_rng().try_fill(&mut hash.0[..]).unwrap(); - EthereumBeaconClient::store_execution_header( - hash, - CompactExecutionHeader::default(), - i as u64, - hash, - ); + EthereumBeaconClient::store_execution_header(hash, CompactExecutionHeader::default()); stored_hashes.push(hash); } @@ -236,15 +228,10 @@ pub fn execution_header_pruning() { assert_eq!({ ExecutionHeaders::::iter().count() }, stored_hashes.len()); // Let's push extra entries so that some of the previous entries are deleted. - for i in 0..to_be_deleted { + for _ in 0..to_be_deleted { let mut hash = H256::default(); thread_rng().try_fill(&mut hash.0[..]).unwrap(); - EthereumBeaconClient::store_execution_header( - hash, - CompactExecutionHeader::default(), - (i + execution_header_prune_threshold) as u64, - hash, - ); + EthereumBeaconClient::store_execution_header(hash, CompactExecutionHeader::default()); stored_hashes.push(hash); } @@ -348,34 +335,6 @@ fn find_present_keys() { }); } -#[test] -fn cross_check_execution_state() { - new_tester().execute_with(|| { - let header_root: H256 = TEST_HASH.into(); - >::insert( - header_root, - CompactBeaconState { - // set slot to period 5 - slot: ((EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH) * 5) as u64, - block_roots_root: Default::default(), - }, - ); - LatestFinalizedBlockRoot::::set(header_root); - >::set(ExecutionHeaderState { - beacon_block_root: Default::default(), - // set slot to period 2 - beacon_slot: ((EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH) * 2) as u64, - block_hash: Default::default(), - block_number: 0, - }); - - assert_err!( - EthereumBeaconClient::cross_check_execution_state(), - Error::::ExecutionHeaderTooFarBehind - ); - }); -} - /* SYNC PROCESS TESTS */ #[test] @@ -608,40 +567,6 @@ fn submit_update_with_skipped_sync_committee_period() { }); } -#[test] -fn submit_update_execution_headers_too_far_behind() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let execution_header_update = Box::new(load_execution_header_update_fixture()); - let next_update = Box::new(load_next_sync_committee_update_fixture()); - - new_tester().execute_with(|| { - let far_ahead_finalized_header_slot = finalized_header_update.finalized_header.slot + - (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH * 2) as u64; - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - assert_ok!(EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update - )); - - let header_root: H256 = TEST_HASH.into(); - >::insert( - header_root, - CompactBeaconState { - slot: far_ahead_finalized_header_slot, - block_roots_root: Default::default(), - }, - ); - LatestFinalizedBlockRoot::::set(header_root); - - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update), - Error::::ExecutionHeaderTooFarBehind - ); - }); -} - #[test] fn submit_irrelevant_update() { let checkpoint = Box::new(load_checkpoint_update_fixture()); @@ -764,51 +689,6 @@ fn submit_execution_header_update_invalid_execution_header_proof() { }); } -#[test] -fn submit_execution_header_update_that_skips_block() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let execution_header_update = Box::new(load_execution_header_update_fixture()); - let mut skipped_block_execution_header_update = - Box::new(load_execution_header_update_fixture()); - let mut skipped_execution_header = - skipped_block_execution_header_update.execution_header.clone(); - - skipped_execution_header = match skipped_execution_header { - VersionedExecutionPayloadHeader::Capella(execution_payload_header) => { - let mut mut_execution_payload_header = execution_payload_header.clone(); - mut_execution_payload_header.block_number = execution_payload_header.block_number + 2; - VersionedExecutionPayloadHeader::Capella(mut_execution_payload_header) - }, - VersionedExecutionPayloadHeader::Deneb(execution_payload_header) => { - let mut mut_execution_payload_header = execution_payload_header.clone(); - mut_execution_payload_header.block_number = execution_payload_header.block_number + 2; - VersionedExecutionPayloadHeader::Deneb(mut_execution_payload_header) - }, - }; - - skipped_block_execution_header_update.execution_header = skipped_execution_header; - - new_tester().execute_with(|| { - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - assert_ok!(EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update.clone() - )); - assert!(>::contains_key( - execution_header_update.execution_header.block_hash() - )); - assert_err!( - EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - skipped_block_execution_header_update - ), - Error::::ExecutionHeaderSkippedBlock - ); - }); -} - #[test] fn submit_execution_header_update_that_is_also_finalized_header_which_is_not_stored() { let checkpoint = Box::new(load_checkpoint_update_fixture()); diff --git a/bridges/snowbridge/primitives/beacon/src/updates.rs b/bridges/snowbridge/primitives/beacon/src/updates.rs index 1ecd32c6d7b7..442d7565768f 100644 --- a/bridges/snowbridge/primitives/beacon/src/updates.rs +++ b/bridges/snowbridge/primitives/beacon/src/updates.rs @@ -23,26 +23,13 @@ pub struct CheckpointUpdate { pub block_roots_branch: Vec, } -impl Default for CheckpointUpdate { - fn default() -> Self { - CheckpointUpdate { - header: Default::default(), - current_sync_committee: Default::default(), - current_sync_committee_branch: Default::default(), - validators_root: Default::default(), - block_roots_root: Default::default(), - block_roots_branch: Default::default(), - } - } -} - #[derive( Default, Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo, )] #[cfg_attr( feature = "std", derive(serde::Deserialize), - serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = "")) + serde(bound(serialize = ""), bound(deserialize = "")) )] pub struct Update { /// A recent header attesting to the finalized header, using its `state_root`. diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs index ab329fbd242b..61df39b310de 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -58,8 +58,6 @@ pub fn send_inbound_message(fixture: InboundQueueFixture) -> DispatchResult { EthereumBeaconClient::store_execution_header( fixture.message.proof.block_hash, fixture.execution_header, - 0, - H256::default(), ); EthereumInboundQueue::submit( diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 926f5ae3477a..daeff8f24ec4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -518,7 +518,7 @@ pub mod benchmark_helpers { impl BenchmarkHelper for Runtime { fn initialize_storage(block_hash: H256, header: CompactExecutionHeader) { - EthereumBeaconClient::store_execution_header(block_hash, header, 0, H256::default()) + EthereumBeaconClient::store_execution_header(block_hash, header) } }