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

[stable2407] Backport #5671 #5822

Closed
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
42 changes: 42 additions & 0 deletions bridges/snowbridge/pallets/ethereum-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ pub mod pallet {
#[pallet::storage]
pub type NextSyncCommittee<T: Config> = StorageValue<_, SyncCommitteePrepared, ValueQuery>;

/// The last period where the next sync committee was updated for free.
#[pallet::storage]
pub type LatestSyncCommitteeUpdatePeriod<T: Config> = StorageValue<_, u64, ValueQuery>;

/// The current operating mode of the pallet.
#[pallet::storage]
#[pallet::getter(fn operating_mode)]
Expand Down Expand Up @@ -437,6 +441,13 @@ pub mod pallet {
let latest_finalized_state =
FinalizedBeaconState::<T>::get(LatestFinalizedBlockRoot::<T>::get())
.ok_or(Error::<T>::NotBootstrapped)?;

let pays_fee = Self::check_refundable(update, latest_finalized_state.slot);
let actual_weight = match update.next_sync_committee_update {
None => T::WeightInfo::submit(),
Some(_) => T::WeightInfo::submit_with_sync_committee(),
};

if let Some(next_sync_committee_update) = &update.next_sync_committee_update {
let store_period = compute_period(latest_finalized_state.slot);
let update_finalized_period = compute_period(update.finalized_header.slot);
Expand All @@ -460,6 +471,7 @@ pub mod pallet {
"💫 SyncCommitteeUpdated at period {}.",
update_finalized_period
);
<LatestSyncCommitteeUpdatePeriod<T>>::set(update_finalized_period);
Self::deposit_event(Event::SyncCommitteeUpdated {
period: update_finalized_period,
});
Expand Down Expand Up @@ -640,5 +652,35 @@ pub mod pallet {
let signing_root = Self::compute_signing_root(header, domain)?;
Ok(signing_root)
}
<<<<<<< HEAD
=======

/// Updates are free if the update is successful and the interval between the latest
/// finalized header in storage and the newly imported header is large enough. All
/// successful sync committee updates are free.
pub(super) fn check_refundable(update: &Update, latest_slot: u64) -> Pays {
// If the sync committee was successfully updated, the update may be free.
let update_period = compute_period(update.finalized_header.slot);
let latest_free_update_period = LatestSyncCommitteeUpdatePeriod::<T>::get();
// If the next sync committee is not known and this update sets it, the update is free.
// If the sync committee update is in a period that we have not received an update for,
// the update is free.
let refundable =
!<NextSyncCommittee<T>>::exists() || update_period > latest_free_update_period;
if update.next_sync_committee_update.is_some() && refundable {
return Pays::No;
}

// If the latest finalized header is larger than the minimum slot interval, the header
// import transaction is free.
if update.finalized_header.slot >=
latest_slot.saturating_add(T::FreeHeadersInterval::get() as u64)
{
return Pays::No;
}

Pays::Yes
}
>>>>>>> 1790e42 (Fix border condition in Snowbridge free consensus Updates (#5671))
}
}
27 changes: 27 additions & 0 deletions bridges/snowbridge/pallets/ethereum-client/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,33 @@ pub fn load_next_finalized_header_update_fixture() -> snowbridge_beacon_primitiv
load_fixture("next-finalized-header-update.json".to_string()).unwrap()
}

pub fn load_sync_committee_update_period_0() -> Box<
snowbridge_beacon_primitives::Update<
{ config::SYNC_COMMITTEE_SIZE },
{ config::SYNC_COMMITTEE_BITS_SIZE },
>,
> {
Box::new(load_fixture("sync-committee-update-period-0.json".to_string()).unwrap())
}

pub fn load_sync_committee_update_period_0_older_fixture() -> Box<
snowbridge_beacon_primitives::Update<
{ config::SYNC_COMMITTEE_SIZE },
{ config::SYNC_COMMITTEE_BITS_SIZE },
>,
> {
Box::new(load_fixture("sync-committee-update-period-0-older.json".to_string()).unwrap())
}

pub fn load_sync_committee_update_period_0_newer_fixture() -> Box<
snowbridge_beacon_primitives::Update<
{ config::SYNC_COMMITTEE_SIZE },
{ config::SYNC_COMMITTEE_BITS_SIZE },
>,
> {
Box::new(load_fixture("sync-committee-update-period-0-newer.json".to_string()).unwrap())
}

pub fn get_message_verification_payload() -> (Log, Proof) {
let inbound_fixture = snowbridge_pallet_ethereum_client_fixtures::make_inbound_fixture();
(inbound_fixture.message.event_log, inbound_fixture.message.proof)
Expand Down
94 changes: 94 additions & 0 deletions bridges/snowbridge/pallets/ethereum-client/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
pub use crate::mock::*;
use crate::{
<<<<<<< HEAD
functions::compute_period, sync_committee_sum, verify_merkle_branch, BeaconHeader,
CompactBeaconState, Error, FinalizedBeaconState, LatestFinalizedBlockRoot, NextSyncCommittee,
SyncCommitteePrepared,
Expand All @@ -16,6 +18,20 @@ pub use crate::mock::*;

use crate::config::{EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT};
use frame_support::{assert_err, assert_noop, assert_ok};
=======
config::{EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT},
functions::compute_period,
mock::{
get_message_verification_payload, load_checkpoint_update_fixture,
load_finalized_header_update_fixture, load_next_finalized_header_update_fixture,
load_next_sync_committee_update_fixture, load_sync_committee_update_fixture,
},
sync_committee_sum, verify_merkle_branch, BeaconHeader, CompactBeaconState, Error,
FinalizedBeaconState, LatestFinalizedBlockRoot, LatestSyncCommitteeUpdatePeriod,
NextSyncCommittee, SyncCommitteePrepared,
};
use frame_support::{assert_err, assert_noop, assert_ok, pallet_prelude::Pays};
>>>>>>> 1790e42 (Fix border condition in Snowbridge free consensus Updates (#5671))
use hex_literal::hex;
use snowbridge_beacon_primitives::{
types::deneb, Fork, ForkVersions, NextSyncCommitteeUpdate, VersionedExecutionPayloadHeader,
Expand Down Expand Up @@ -340,7 +356,13 @@ fn submit_update_in_current_period() {

new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
<<<<<<< HEAD
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()));
=======
let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone());
assert_ok!(result);
assert_eq!(result.unwrap().pays_fee, Pays::No);
>>>>>>> 1790e42 (Fix border condition in Snowbridge free consensus Updates (#5671))
let block_root: H256 = update.finalized_header.hash_tree_root().unwrap();
assert!(<FinalizedBeaconState<Test>>::contains_key(block_root));
});
Expand Down Expand Up @@ -645,6 +667,78 @@ fn submit_finalized_header_update_with_gap_at_limit() {
// next check, the merkle proof, because we changed the next_update slots.
Error::<Test>::InvalidHeaderMerkleProof
);
<<<<<<< HEAD
=======
assert_eq!(second_result.unwrap_err().post_info.pays_fee, Pays::Yes);
});
}

#[test]
fn duplicate_sync_committee_updates_are_not_free() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let sync_committee_update = Box::new(load_sync_committee_update_fixture());

new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
let result =
EthereumBeaconClient::submit(RuntimeOrigin::signed(1), sync_committee_update.clone());
assert_ok!(result);
assert_eq!(result.unwrap().pays_fee, Pays::No);

// Check that if the same update is submitted, the update is not free.
let second_result =
EthereumBeaconClient::submit(RuntimeOrigin::signed(1), sync_committee_update);
assert_ok!(second_result);
assert_eq!(second_result.unwrap().pays_fee, Pays::Yes);
});
}

#[test]
fn sync_committee_update_for_sync_committee_already_imported_are_not_free() {
let checkpoint = Box::new(load_checkpoint_update_fixture());
let sync_committee_update = Box::new(load_sync_committee_update_fixture()); // slot 129
let second_sync_committee_update = load_sync_committee_update_period_0(); // slot 128
let third_sync_committee_update = load_sync_committee_update_period_0_newer_fixture(); // slot 224
let fourth_sync_committee_update = load_sync_committee_update_period_0_older_fixture(); // slot 96
let fith_sync_committee_update = Box::new(load_next_sync_committee_update_fixture()); // slot 8259

new_tester().execute_with(|| {
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
assert_eq!(<LatestSyncCommitteeUpdatePeriod<Test>>::get(), 0);

// Check that setting the next sync committee for period 0 is free (it is not set yet).
let result =
EthereumBeaconClient::submit(RuntimeOrigin::signed(1), sync_committee_update.clone());
assert_ok!(result);
assert_eq!(result.unwrap().pays_fee, Pays::No);
assert_eq!(<LatestSyncCommitteeUpdatePeriod<Test>>::get(), 0);

// Check that setting the next sync committee for period 0 again is not free.
let second_result =
EthereumBeaconClient::submit(RuntimeOrigin::signed(1), second_sync_committee_update);
assert_eq!(second_result.unwrap().pays_fee, Pays::Yes);
assert_eq!(<LatestSyncCommitteeUpdatePeriod<Test>>::get(), 0);

// Check that setting an update with a sync committee that has already been set, but with a
// newer finalized header, is free.
let third_result =
EthereumBeaconClient::submit(RuntimeOrigin::signed(1), third_sync_committee_update);
assert_eq!(third_result.unwrap().pays_fee, Pays::No);
assert_eq!(<LatestSyncCommitteeUpdatePeriod<Test>>::get(), 0);

// Check that setting the next sync committee for period 0 again with an earlier slot is not
// free.
let fourth_result =
EthereumBeaconClient::submit(RuntimeOrigin::signed(1), fourth_sync_committee_update);
assert_err!(fourth_result, Error::<Test>::IrrelevantUpdate);
assert_eq!(fourth_result.unwrap_err().post_info.pays_fee, Pays::Yes);

// Check that setting the next sync committee for period 1 is free.
let fith_result =
EthereumBeaconClient::submit(RuntimeOrigin::signed(1), fith_sync_committee_update);
assert_eq!(fith_result.unwrap().pays_fee, Pays::No);
assert_eq!(<LatestSyncCommitteeUpdatePeriod<Test>>::get(), 1);
>>>>>>> 1790e42 (Fix border condition in Snowbridge free consensus Updates (#5671))
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"header": {
"slot": 864,
"slot": 64,
"proposer_index": 4,
"parent_root": "0x614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614",
"state_root": "0x5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a",
"body_root": "0x0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e"
"parent_root": "0x88e5b7e0dd468b334caf9281e0665184d2d712d7ffe632123ea07631b714920c",
"state_root": "0x82771f834d4d896f4969abdaf45f28f49a7437ecfca7bf2f7db7bfac5ca7224f",
"body_root": "0x8b36f34ceba40a29c9c6fa6266564c7df30ea75fecf1a85e6ec1cb4aabf4dc68"
},
"current_sync_committee": {
"pubkeys": [
Expand Down Expand Up @@ -525,18 +525,18 @@
},
"current_sync_committee_branch": [
"0x3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59",
"0xa9e90f89e7f90fd5d79a6bbcaf40ba5cfc05ab1b561ac51c84867c32248d5b1e",
"0xbd1a76b03e02402bb24a627de1980a80ab17691980271f597b844b89b497ef75",
"0x07bbcd27c7cad089023db046eda17e8209842b7d97add8b873519e84fe6480e7",
"0x94c11eeee4cb6192bf40810f23486d8c75dfbc2b6f28d988d6f74435ede243b0"
"0x058baa5628d6156e55ab99da54244be4a071978528f2eb3b19a4f4d7ab36f870",
"0x5f89984c1068b616e99589e161d2bb73b92c68b3422ef309ace434894b4503ae",
"0x4f1c230cf2bbe39502171956421fbe4f1c0a71a9691944019047b84584b371d5",
"0xbf8d5f6021db16e9b50e639e5c489eb8dc06449bf4ed17045cb949cb89a58a04"
],
"validators_root": "0x270d43e74ce340de4bca2b1936beca0f4f5408d9e78aec4850920baf659d5b69",
"block_roots_root": "0xb9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10",
"block_roots_root": "0x2c453665ba6fc024116daf5246126e36085c61257cfbcce69d0bdcf89c766dc0",
"block_roots_branch": [
"0x733422bd810895dab74cbbe07c69dd440cbb51f573181ad4dddac30fcdd0f41f",
"0x9b9eca73ab01d14549c325ba1b4610bb20bf1f8ec2dbd649f9d8cc7f3cea75fa",
"0xbcc666ad0ad9f9725cbd682bc95589d35b1b53b2a615f1e6e8dd5e086336becf",
"0x3069b547a08f703a1715016e926cbd64e71f93f64fb68d98d8c8f1ab745c46e5",
"0xc2de7e1097239404e17b263cfa0473533cc41e903cb03440d633bc5c27314cb4"
"0xbd04f51e43f63b0be48034920e8f5976111b7717225abccedbc6bcb327b95d00",
"0x758319a3bad11ee10fde1036551d982583c0392f284de5cc429b67fbd74c25d5",
"0xb42179d040c2bec20fa0a2750baf225b8097b5c9e4e22af9250cc773f4259427",
"0x5340ad5877c72dca689ca04bc8fedb78d67a4801d99887937edd8ccd29f87e82",
"0x9f03be8e70f74fc6b51e6ed03c96aabb544b5c50e5cdb8c0ab5001d1249d55f0"
]
}
}
Loading
Loading