Skip to content

Commit

Permalink
move header's timestamp validation into header::validate()
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 ffe5a51 commit cd4fc7f
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 26 deletions.
4 changes: 3 additions & 1 deletion crates/ibc/src/client_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,10 @@ impl<const SYNC_COMMITTEE_SIZE: usize> Ics2ClientState for ClientState<SYNC_COMM
client_id: ClientId,
header: Any,
) -> Result<UpdatedState, ClientError> {
let cc = self.build_context(ctx);
let header = Header::<SYNC_COMMITTEE_SIZE>::try_from(header)?;
header.validate(&cc)?;

let trusted_sync_committee = header.trusted_sync_committee;
let consensus_state = match maybe_consensus_state(
ctx,
Expand All @@ -338,7 +341,6 @@ impl<const SYNC_COMMITTEE_SIZE: usize> Ics2ClientState for ClientState<SYNC_COMM
let account_update = header.account_update;
let header_timestamp = header.timestamp;

let cc = self.build_context(ctx);
self.consensus_verifier
.validate_updates(
&cc,
Expand Down
27 changes: 26 additions & 1 deletion crates/ibc/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ use crate::types::{
ConsensusUpdateInfo, ExecutionUpdateInfo, TrustedSyncCommittee,
};
use bytes::Buf;
use ethereum_consensus::compute::compute_timestamp_at_slot;
use ethereum_consensus::context::ChainContext;
use ethereum_ibc_proto::ibc::lightclients::ethereum::v1::Header as RawHeader;
use ethereum_light_client_verifier::updates::ConsensusUpdate;
use ibc::core::ics02_client::error::ClientError;
use ibc::core::ics02_client::header::Header as Ics02Header;
use ibc::timestamp::Timestamp;
Expand Down Expand Up @@ -72,6 +75,22 @@ pub fn decode_header<const SYNC_COMMITTEE_SIZE: usize, B: Buf>(
RawHeader::decode(buf).map_err(Error::Decode)?.try_into()
}

impl<const SYNC_COMMITTEE_SIZE: usize> Header<SYNC_COMMITTEE_SIZE> {
pub fn validate<C: ChainContext>(&self, ctx: &C) -> Result<(), Error> {
self.trusted_sync_committee.sync_committee.validate()?;
let header_timestamp = self.timestamp.into_tm_time().unwrap().unix_timestamp() as u64;
let timestamp =
compute_timestamp_at_slot(ctx, self.consensus_update.finalized_beacon_header().slot);
if header_timestamp != timestamp.0 {
return Err(Error::UnexpectedTimestamp(
timestamp.into(),
header_timestamp,
));
}
Ok(())
}
}

impl<const SYNC_COMMITTEE_SIZE: usize> Ics02Header for Header<SYNC_COMMITTEE_SIZE> {
fn height(&self) -> ibc::Height {
ibc::Height::new(0, self.execution_update.block_number.into()).unwrap()
Expand Down Expand Up @@ -220,8 +239,14 @@ mod tests {
consensus_update: update.clone(),
execution_update: ExecutionUpdateInfo::default(),
account_update: AccountUpdateInfo::default(),
timestamp: Timestamp::from_nanoseconds(1730729158 * 1_000_000_000).unwrap(),
timestamp: Timestamp::from_nanoseconds(
compute_timestamp_at_slot(&ctx, update.finalized_beacon_header().slot).0
* 1_000_000_000,
)
.unwrap(),
};
let res = header.validate(&ctx);
assert!(res.is_ok(), "header validation failed: {:?}", res);
let any = IBCAny::from(header.clone());
let decoded = Header::<32>::try_from(any).unwrap();
assert_eq!(header, decoded);
Expand Down
28 changes: 4 additions & 24 deletions crates/ibc/src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ use crate::{
types::ConsensusUpdateInfo,
};
use ethereum_consensus::{
beacon::Slot,
compute::{compute_sync_committee_period_at_slot, compute_timestamp_at_slot},
compute::compute_sync_committee_period_at_slot,
context::ChainContext,
types::{H256, U64},
};
Expand All @@ -23,20 +22,11 @@ pub fn apply_updates<const SYNC_COMMITTEE_SIZE: usize, C: ChainContext>(
consensus_update: ConsensusUpdateInfo<SYNC_COMMITTEE_SIZE>,
block_number: U64,
account_storage_root: H256,
timestamp: Timestamp,
header_timestamp: Timestamp,
) -> Result<(ClientState<SYNC_COMMITTEE_SIZE>, ConsensusState), Error> {
let store_period = consensus_state.current_period(ctx);
let update_finalized_slot = consensus_update.finalized_header.0.slot;
let update_finalized_period = compute_sync_committee_period_at_slot(ctx, update_finalized_slot);
let timestamp = timestamp.into_tm_time().unwrap().unix_timestamp() as u64;
let finalized_header_timestamp: u64 =
compute_timestamp_at_slot(ctx, update_finalized_slot).into();
if finalized_header_timestamp != timestamp {
return Err(Error::UnexpectedTimestamp(
finalized_header_timestamp,
timestamp,
));
}

// Let `store_period` be the period of the current sync committe of the consensus state, then the state transition is the following:
// - If `store_period == update_finalized_period`, then the new consensus state will have the same sync committee info as the current consensus state.
Expand All @@ -47,7 +37,7 @@ pub fn apply_updates<const SYNC_COMMITTEE_SIZE: usize, C: ChainContext>(
ConsensusState {
slot: update_finalized_slot,
storage_root: account_storage_root.0.to_vec().into(),
timestamp: wrap_compute_timestamp_at_slot(ctx, update_finalized_slot)?,
timestamp: header_timestamp,
current_sync_committee: consensus_state.current_sync_committee.clone(),
next_sync_committee: consensus_state.next_sync_committee.clone(),
}
Expand All @@ -59,7 +49,7 @@ pub fn apply_updates<const SYNC_COMMITTEE_SIZE: usize, C: ChainContext>(
ConsensusState {
slot: update_finalized_slot,
storage_root: account_storage_root.0.to_vec().into(),
timestamp: wrap_compute_timestamp_at_slot(ctx, update_finalized_slot)?,
timestamp: header_timestamp,
current_sync_committee: consensus_state.next_sync_committee.clone(),
next_sync_committee: update_next_sync_committee.aggregate_pubkey,
}
Expand Down Expand Up @@ -87,13 +77,3 @@ pub fn apply_updates<const SYNC_COMMITTEE_SIZE: usize, C: ChainContext>(
new_consensus_state.validate()?;
Ok((new_client_state, new_consensus_state))
}

fn wrap_compute_timestamp_at_slot<C: ChainContext>(
ctx: &C,
slot: Slot,
) -> Result<Timestamp, Error> {
// NOTE: The return value of `compute_timestamp_at_slot`'s unit is seconds,
// so we need to convert it to nanoseconds.
let timestamp = compute_timestamp_at_slot(ctx, slot);
Ok(Timestamp::from_nanoseconds(timestamp.0 * 1_000_000_000)?)
}

0 comments on commit cd4fc7f

Please sign in to comment.