Skip to content

Commit

Permalink
add tests for apply_updates
Browse files Browse the repository at this point in the history
Signed-off-by: Jun Kimura <[email protected]>
  • Loading branch information
bluele committed Nov 11, 2024
1 parent 071109a commit 2205179
Show file tree
Hide file tree
Showing 2 changed files with 304 additions and 3 deletions.
2 changes: 1 addition & 1 deletion crates/ibc/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub enum Error {
Vec<String>,
),
/// consensus update doesn't have next sync committee: store_period={0} update_period={1}
NoNextSyncCommitteeInConsensusUpdate(u64, u64),
NoNextSyncCommitteeInConsensusUpdate(U64, U64),
/// invalid current sync committee keys: expected={0:?} actual={1:?}
InvalidCurrentSyncCommitteeKeys(PublicKey, PublicKey),
/// invalid next sync committee keys: expected={0:?} actual={1:?}
Expand Down
305 changes: 303 additions & 2 deletions crates/ibc/src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ pub fn apply_updates<const SYNC_COMMITTEE_SIZE: usize, C: ChainContext>(
} else {
// Relayers must submit an update that contains the next sync committee if the update period is `store_period + 1`.
return Err(Error::NoNextSyncCommitteeInConsensusUpdate(
store_period.into(),
update_finalized_period.into(),
store_period,
update_finalized_period,
));
}
} else {
Expand All @@ -77,3 +77,304 @@ pub fn apply_updates<const SYNC_COMMITTEE_SIZE: usize, C: ChainContext>(
new_consensus_state.validate()?;
Ok((new_client_state, new_consensus_state))
}

#[cfg(test)]
mod tests {
use super::*;
use core::time::Duration;
use ethereum_consensus::beacon::Version;
use ethereum_consensus::compute::compute_timestamp_at_slot;
use ethereum_consensus::context::ChainContext;
use ethereum_consensus::fork::altair::ALTAIR_FORK_SPEC;
use ethereum_consensus::fork::bellatrix::BELLATRIX_FORK_SPEC;
use ethereum_consensus::fork::capella::CAPELLA_FORK_SPEC;
use ethereum_consensus::fork::deneb::DENEB_FORK_SPEC;
use ethereum_consensus::fork::{ForkParameter, ForkParameters};
use ethereum_consensus::preset::minimal::PRESET;
use ethereum_consensus::types::Address;
use ethereum_consensus::{config, types::U64};
use ethereum_light_client_verifier::updates::ConsensusUpdate;
use ethereum_light_client_verifier::{
consensus::test_utils::{gen_light_client_update_with_params, MockSyncCommitteeManager},
context::{Fraction, LightClientContext},
updates::ConsensusUpdateInfo as EthConsensusUpdateInfo,
};
use hex_literal::hex;
use ibc::core::ics23_commitment::commitment::CommitmentRoot;
use std::time::SystemTime;

#[test]
pub fn test_apply_updates() {
let scm = MockSyncCommitteeManager::<32>::new(1, 6);
let ctx = LightClientContext::new_with_config(
config::minimal::get_config(),
Default::default(),
Default::default(),
Fraction::new(2, 3),
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs()
.into(),
);

let slots_per_period = ctx.slots_per_epoch() * ctx.epochs_per_sync_committee_period();
let base_store_period = 3u64;
let base_store_slot = U64(base_store_period) * slots_per_period;
let base_finalized_epoch = base_store_slot / ctx.slots_per_epoch() + 1;
let base_attested_slot = (base_finalized_epoch + 2) * ctx.slots_per_epoch();
let base_signature_slot = base_attested_slot + 1;

let current_sync_committee = scm.get_committee(base_store_period);
let dummy_execution_state_root = [1u8; 32].into();
let dummy_execution_block_number = 1;

let client_state =
ClientState::<{ ethereum_consensus::preset::minimal::PRESET.SYNC_COMMITTEE_SIZE }> {
genesis_validators_root: keccak256("genesis_validators_root"),
min_sync_committee_participants: 1.into(),
genesis_time: 1.into(),
fork_parameters: ForkParameters::new(
Version([0, 0, 0, 1]),
vec![
ForkParameter::new(Version([1, 0, 0, 1]), U64(0), ALTAIR_FORK_SPEC),
ForkParameter::new(Version([2, 0, 0, 1]), U64(0), BELLATRIX_FORK_SPEC),
ForkParameter::new(Version([3, 0, 0, 1]), U64(0), CAPELLA_FORK_SPEC),
ForkParameter::new(Version([4, 0, 0, 1]), U64(0), DENEB_FORK_SPEC),
],
)
.unwrap(),
seconds_per_slot: PRESET.SECONDS_PER_SLOT,
slots_per_epoch: PRESET.SLOTS_PER_EPOCH,
epochs_per_sync_committee_period: PRESET.EPOCHS_PER_SYNC_COMMITTEE_PERIOD,
ibc_address: Address(hex!("ff77D90D6aA12db33d3Ba50A34fB25401f6e4c4F")),
ibc_commitments_slot: keccak256("ibc_commitments_slot"),
trust_level: Fraction::new(2, 3),
trusting_period: Duration::from_secs(60 * 60 * 27),
max_clock_drift: Duration::from_secs(60),
latest_execution_block_number: 1.into(),
frozen_height: None,
consensus_verifier: Default::default(),
execution_verifier: Default::default(),
};

let consensus_state = ConsensusState {
slot: base_store_slot,
storage_root: CommitmentRoot::from_bytes(keccak256("storage_root").as_bytes()),
timestamp: Timestamp::from_nanoseconds(
compute_timestamp_at_slot(&ctx, base_store_slot).0 * 1_000_000_000,
)
.unwrap(),
current_sync_committee: scm
.get_committee(base_store_period)
.to_committee()
.aggregate_pubkey,
next_sync_committee: scm
.get_committee(base_store_period + 1)
.to_committee()
.aggregate_pubkey,
};

{
// store_period == finalized_period == attested_period == signature_period
let update = to_consensus_update_info(gen_light_client_update_with_params::<32, _>(
&ctx,
base_signature_slot,
base_attested_slot,
base_finalized_epoch,
dummy_execution_state_root,
dummy_execution_block_number.into(),
current_sync_committee,
scm.get_committee(base_store_period + 1),
true,
32,
));
let new_block_number = 2.into();
let res = apply_updates(
&ctx,
&client_state,
&consensus_state,
update.clone(),
new_block_number,
H256::from_slice(&[1u8; 32]),
Timestamp::from_nanoseconds(
compute_timestamp_at_slot(&ctx, update.finalized_header.0.slot).0
* 1_000_000_000,
)
.unwrap(),
);
assert!(res.is_ok(), "{:?}", res);
let (new_client_state, new_consensus_state) = res.unwrap();
assert_eq!(
new_client_state.latest_execution_block_number,
new_block_number
);
assert_eq!(new_consensus_state.slot, update.finalized_header.0.slot);
// sync committee info should be the same as the current consensus state
assert_eq!(
new_consensus_state.current_sync_committee,
scm.get_committee(base_store_period)
.to_committee()
.aggregate_pubkey
);
assert_eq!(
new_consensus_state.next_sync_committee,
scm.get_committee(base_store_period + 1)
.to_committee()
.aggregate_pubkey
);
}
{
// store_period + 1 == finalized_period == attested_period == signature_period
let update = to_consensus_update_info(gen_light_client_update_with_params::<32, _>(
&ctx,
base_signature_slot + slots_per_period,
base_attested_slot + slots_per_period,
base_finalized_epoch + ctx.epochs_per_sync_committee_period(),
dummy_execution_state_root,
dummy_execution_block_number.into(),
current_sync_committee,
scm.get_committee(base_store_period + 2),
true,
32,
));
let new_block_number = 2.into();
let res = apply_updates(
&ctx,
&client_state,
&consensus_state,
update.clone(),
new_block_number,
H256::from_slice(&[1u8; 32]),
Timestamp::from_nanoseconds(
compute_timestamp_at_slot(&ctx, update.finalized_header.0.slot).0
* 1_000_000_000,
)
.unwrap(),
);
assert!(res.is_ok(), "{:?}", res);
let (new_client_state, new_consensus_state) = res.unwrap();
assert_eq!(
new_client_state.latest_execution_block_number,
new_block_number
);
assert_eq!(new_consensus_state.slot, update.finalized_header.0.slot);
// sync committee info should be the same as the current consensus state
assert_eq!(
new_consensus_state.current_sync_committee,
scm.get_committee(base_store_period + 1)
.to_committee()
.aggregate_pubkey
);
assert_eq!(
new_consensus_state.next_sync_committee,
scm.get_committee(base_store_period + 2)
.to_committee()
.aggregate_pubkey
);
}
{
// store_period + 1 == finalized_period == attested_period == signature_period
// but the update has no next sync committee
let update = to_consensus_update_info(gen_light_client_update_with_params::<32, _>(
&ctx,
base_signature_slot + slots_per_period,
base_attested_slot + slots_per_period,
base_finalized_epoch + ctx.epochs_per_sync_committee_period(),
dummy_execution_state_root,
dummy_execution_block_number.into(),
current_sync_committee,
scm.get_committee(base_store_period + 2),
false,
32,
));
let new_block_number = 2.into();
let res = apply_updates(
&ctx,
&client_state,
&consensus_state,
update.clone(),
new_block_number,
H256::from_slice(&[1u8; 32]),
Timestamp::from_nanoseconds(
compute_timestamp_at_slot(&ctx, update.finalized_header.0.slot).0
* 1_000_000_000,
)
.unwrap(),
);
assert!(res.is_err(), "{:?}", res);
if let Err(Error::NoNextSyncCommitteeInConsensusUpdate(store_period, update_period)) =
res
{
assert_eq!(store_period.0, base_store_period);
assert_eq!(update_period.0, base_store_period + 1);
} else {
panic!("unexpected error: {:?}", res);
}
}
{
// finalized_period - 1 == store_period == attested_period == signature_period
let update = to_consensus_update_info(gen_light_client_update_with_params::<32, _>(
&ctx,
base_signature_slot,
base_attested_slot,
base_finalized_epoch - ctx.epochs_per_sync_committee_period(),
dummy_execution_state_root,
dummy_execution_block_number.into(),
current_sync_committee,
scm.get_committee(base_store_period),
true,
32,
));
let new_block_number = 2.into();
let res = apply_updates(
&ctx,
&client_state,
&consensus_state,
update.clone(),
new_block_number,
H256::from_slice(&[1u8; 32]),
Timestamp::from_nanoseconds(
compute_timestamp_at_slot(&ctx, update.finalized_header.0.slot).0
* 1_000_000_000,
)
.unwrap(),
);
if let Err(Error::StoreNotSupportedFinalizedPeriod(store_period, update_period)) = res {
assert_eq!(store_period.0, base_store_period);
assert_eq!(
update_period,
compute_sync_committee_period_at_slot(
&ctx,
update.finalized_beacon_header().slot
)
);
} else {
panic!("unexpected error: {:?}", res);
}
}
}

fn keccak256(s: &str) -> H256 {
use tiny_keccak::{Hasher, Keccak};
let mut hasher = Keccak::v256();
let mut output = [0u8; 32];
hasher.update(s.as_bytes());
hasher.finalize(&mut output);
H256::from_slice(&output)
}

fn to_consensus_update_info<const SYNC_COMMITTEE_SIZE: usize>(
consensus_update: EthConsensusUpdateInfo<SYNC_COMMITTEE_SIZE>,
) -> ConsensusUpdateInfo<SYNC_COMMITTEE_SIZE> {
ConsensusUpdateInfo {
attested_header: consensus_update.light_client_update.attested_header,
next_sync_committee: consensus_update.light_client_update.next_sync_committee,
finalized_header: consensus_update.light_client_update.finalized_header,
sync_aggregate: consensus_update.light_client_update.sync_aggregate,
signature_slot: consensus_update.light_client_update.signature_slot,
finalized_execution_root: consensus_update.finalized_execution_root,
finalized_execution_branch: consensus_update.finalized_execution_branch,
}
}
}

0 comments on commit 2205179

Please sign in to comment.