From b7867e304ebd523dc23b93c877e95a23bf18ac61 Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Wed, 13 Nov 2024 23:55:43 +0900 Subject: [PATCH] add `verify_delay_passed` Signed-off-by: Jun Kimura --- crates/ibc/src/client_state.rs | 65 +++++++++++++++++++++++++++++++--- crates/ibc/src/errors.rs | 14 ++++++++ 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/crates/ibc/src/client_state.rs b/crates/ibc/src/client_state.rs index abbd465..e5f016c 100644 --- a/crates/ibc/src/client_state.rs +++ b/crates/ibc/src/client_state.rs @@ -22,6 +22,7 @@ use ibc::core::ics02_client::client_state::{ClientState as Ics2ClientState, Upda use ibc::core::ics02_client::client_type::ClientType; use ibc::core::ics02_client::consensus_state::ConsensusState as Ics02ConsensusState; use ibc::core::ics02_client::error::ClientError; +use ibc::core::ics03_connection::connection::ConnectionEnd; use ibc::core::ics24_host::identifier::{ChainId, ClientId}; use ibc::core::ics24_host::path::ClientConsensusStatePath; use ibc::core::ics24_host::Path; @@ -578,7 +579,7 @@ impl Ics2ClientState for ClientState Ics2ClientState for ClientState Result<(), ClientError> { + verify_delay_passed(ctx, proof_height, connection_end)?; self.verify_membership( proof_height, connection_end.counterparty().prefix(), @@ -598,7 +600,7 @@ impl Ics2ClientState for ClientState Ics2ClientState for ClientState Result<(), ClientError> { + verify_delay_passed(ctx, proof_height, connection_end)?; self.verify_membership( proof_height, connection_end.counterparty().prefix(), @@ -618,7 +621,7 @@ impl Ics2ClientState for ClientState Ics2ClientState for ClientState Result<(), ClientError> { + verify_delay_passed(ctx, proof_height, connection_end)?; let mut seq_bytes = Vec::new(); u64::from(sequence) .encode(&mut seq_bytes) @@ -643,13 +647,14 @@ impl Ics2ClientState for ClientState Result<(), ClientError> { + verify_delay_passed(ctx, proof_height, connection_end)?; self.verify_non_membership( proof_height, connection_end.counterparty().prefix(), @@ -958,6 +963,58 @@ fn trim_left_zero(value: &[u8]) -> &[u8] { &value[pos..] } +// A copy from https://github.com/cosmos/ibc-rs/blob/eea4f0e7a1887f2f1cb18a550d08bb805a08240a/crates/ibc/src/clients/ics07_tendermint/client_state.rs#L1031 +fn verify_delay_passed( + ctx: &dyn ValidationContext, + height: Height, + connection_end: &ConnectionEnd, +) -> Result<(), ClientError> { + let current_timestamp = ctx.host_timestamp().map_err(|e| ClientError::Other { + description: e.to_string(), + })?; + let current_height = ctx.host_height().map_err(|e| ClientError::Other { + description: e.to_string(), + })?; + + let client_id = connection_end.client_id(); + let processed_time = + ctx.client_update_time(client_id, &height) + .map_err(|_| Error::ProcessedTimeNotFound { + client_id: client_id.clone(), + height, + })?; + let processed_height = ctx.client_update_height(client_id, &height).map_err(|_| { + Error::ProcessedHeightNotFound { + client_id: client_id.clone(), + height, + } + })?; + + let delay_period_time = connection_end.delay_period(); + let delay_period_height = ctx.block_delay(&delay_period_time); + + let earliest_time = + (processed_time + delay_period_time).map_err(Error::TimestampOverflowError)?; + if !(current_timestamp == earliest_time || current_timestamp.after(&earliest_time)) { + return Err(Error::NotEnoughTimeElapsed { + current_timestamp, + earliest_time, + } + .into()); + } + + let earliest_height = processed_height.add(delay_period_height); + if current_height < earliest_height { + return Err(Error::NotEnoughBlocksElapsed { + current_height, + earliest_height, + } + .into()); + } + + Ok(()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/ibc/src/errors.rs b/crates/ibc/src/errors.rs index 70f08ce..4b34a89 100644 --- a/crates/ibc/src/errors.rs +++ b/crates/ibc/src/errors.rs @@ -117,6 +117,20 @@ pub enum Error { CannotInitializeFrozenClient, /// unexpected client ID in misbehaviour: expected={0} got={1} UnexpectedClientIdInMisbehaviour(ClientId, ClientId), + /// Processed time for the client `{client_id}` at height `{height}` not found + ProcessedTimeNotFound { client_id: ClientId, height: Height }, + /// Processed height for the client `{client_id}` at height `{height}` not found + ProcessedHeightNotFound { client_id: ClientId, height: Height }, + /// not enough time elapsed, current timestamp `{current_timestamp}` is still less than earliest acceptable timestamp `{earliest_time}` + NotEnoughTimeElapsed { + current_timestamp: Timestamp, + earliest_time: Timestamp, + }, + /// not enough blocks elapsed, current height `{current_height}` is still less than earliest acceptable height `{earliest_height}` + NotEnoughBlocksElapsed { + current_height: Height, + earliest_height: Height, + }, } impl Error {