Skip to content

Commit 486c044

Browse files
Snowbridge Beacon header age check and add linear fee multiplier to ensure safety margins (paritytech#3791)
This is a cherry-pick from master of paritytech#3727 and paritytech#3790 Expected patches for (1.7.0): snowbridge-pallet-ethereum-client snowbridge-pallet-inbound-queue snowbridge-pallet-outbound-queue snowbridge-outbound-queue-runtime-api snowbridge-pallet-system snowbridge-core
1 parent 44c6148 commit 486c044

File tree

2 files changed

+71
-1
lines changed
  • bridges/snowbridge/parachain/pallets/ethereum-client/src

2 files changed

+71
-1
lines changed

bridges/snowbridge/parachain/pallets/ethereum-client/src/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ pub mod pallet {
130130
InvalidExecutionHeaderProof,
131131
InvalidAncestryMerkleProof,
132132
InvalidBlockRootsRootMerkleProof,
133+
/// The gap between the finalized headers is larger than the sync committee period,
134+
/// rendering execution headers unprovable using ancestry proofs (blocks root size is
135+
/// the same as the sync committee period slots).
136+
InvalidFinalizedHeaderGap,
133137
HeaderNotFinalized,
134138
BlockBodyHashTreeRootFailed,
135139
HeaderHashTreeRootFailed,
@@ -398,6 +402,17 @@ pub mod pallet {
398402
Error::<T>::IrrelevantUpdate
399403
);
400404

405+
// Verify the finalized header gap between the current finalized header and new imported
406+
// header is not larger than the sync committee period, otherwise we cannot do
407+
// ancestry proofs for execution headers in the gap.
408+
ensure!(
409+
latest_finalized_state
410+
.slot
411+
.saturating_add(config::SLOTS_PER_HISTORICAL_ROOT as u64) >=
412+
update.finalized_header.slot,
413+
Error::<T>::InvalidFinalizedHeaderGap
414+
);
415+
401416
// Verify that the `finality_branch`, if present, confirms `finalized_header` to match
402417
// the finalized checkpoint root saved in the state of `attested_header`.
403418
let finalized_block_root: H256 = update

bridges/snowbridge/parachain/pallets/ethereum-client/src/tests.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::mock::{
1515

1616
pub use crate::mock::*;
1717

18-
use crate::config::{EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH};
18+
use crate::config::{EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT};
1919
use frame_support::{assert_err, assert_noop, assert_ok};
2020
use hex_literal::hex;
2121
use primitives::{
@@ -884,6 +884,61 @@ fn submit_execution_header_not_finalized() {
884884
});
885885
}
886886

887+
/// Check that a gap of more than 8192 slots between finalized headers is not allowed.
888+
#[test]
889+
fn submit_finalized_header_update_with_too_large_gap() {
890+
let checkpoint = Box::new(load_checkpoint_update_fixture());
891+
let update = Box::new(load_sync_committee_update_fixture());
892+
let mut next_update = Box::new(load_next_sync_committee_update_fixture());
893+
894+
// Adds 8193 slots, so that the next update is still in the next sync committee, but the
895+
// gap between the finalized headers is more than 8192 slots.
896+
let slot_with_large_gap = checkpoint.header.slot + SLOTS_PER_HISTORICAL_ROOT as u64 + 1;
897+
898+
next_update.finalized_header.slot = slot_with_large_gap;
899+
// Adding some slots to the attested header and signature slot since they need to be ahead
900+
// of the finalized header.
901+
next_update.attested_header.slot = slot_with_large_gap + 33;
902+
next_update.signature_slot = slot_with_large_gap + 43;
903+
904+
new_tester().execute_with(|| {
905+
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
906+
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()));
907+
assert!(<NextSyncCommittee<Test>>::exists());
908+
assert_err!(
909+
EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone()),
910+
Error::<Test>::InvalidFinalizedHeaderGap
911+
);
912+
});
913+
}
914+
915+
/// Check that a gap of 8192 slots between finalized headers is allowed.
916+
#[test]
917+
fn submit_finalized_header_update_with_gap_at_limit() {
918+
let checkpoint = Box::new(load_checkpoint_update_fixture());
919+
let update = Box::new(load_sync_committee_update_fixture());
920+
let mut next_update = Box::new(load_next_sync_committee_update_fixture());
921+
922+
next_update.finalized_header.slot = checkpoint.header.slot + SLOTS_PER_HISTORICAL_ROOT as u64;
923+
// Adding some slots to the attested header and signature slot since they need to be ahead
924+
// of the finalized header.
925+
next_update.attested_header.slot =
926+
checkpoint.header.slot + SLOTS_PER_HISTORICAL_ROOT as u64 + 33;
927+
next_update.signature_slot = checkpoint.header.slot + SLOTS_PER_HISTORICAL_ROOT as u64 + 43;
928+
929+
new_tester().execute_with(|| {
930+
assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint));
931+
assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()));
932+
assert!(<NextSyncCommittee<Test>>::exists());
933+
assert_err!(
934+
EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone()),
935+
// The test should pass the InvalidFinalizedHeaderGap check, and will fail at the
936+
// next check, the merkle proof, because we changed the next_update slots.
937+
Error::<Test>::InvalidHeaderMerkleProof
938+
);
939+
});
940+
}
941+
887942
/* IMPLS */
888943

889944
#[test]

0 commit comments

Comments
 (0)