diff --git a/ibc/modules/src/core/ics02_client/handler/upgrade_client.rs b/ibc/modules/src/core/ics02_client/handler/upgrade_client.rs index 09a945b02..4d39d5b49 100644 --- a/ibc/modules/src/core/ics02_client/handler/upgrade_client.rs +++ b/ibc/modules/src/core/ics02_client/handler/upgrade_client.rs @@ -17,6 +17,7 @@ use crate::{ core::{ ics02_client::{ + client_consensus::ConsensusState, client_def::{ClientDef, ConsensusUpdateResult}, client_state::ClientState, context::ClientTypes, @@ -60,6 +61,29 @@ where return Err(Error::client_frozen(client_id)) } + // need to ensure that the client state is not expired as per + // https://github.com/cosmos/ibc-rs/blob/main/docs/architecture/adr-006-upgrade-client-implementation.md#decisions + let latest_consensus_state = + ctx.consensus_state(&client_id, client_state.latest_height()).map_err(|_| { + Error::consensus_state_not_found(client_id.clone(), client_state.latest_height()) + })?; + + tracing::debug!("latest consensus state: {:?}", latest_consensus_state); + + let now = ctx.host_timestamp(); + let last_update_timestamp = + ctx.client_update_time(&client_id, client_state.latest_height()).map_err(|_| { + Error::implementation_specific("Could not find update time for client".to_string()) + })?; + + let duration = now.duration_since(&last_update_timestamp).ok_or_else(|| { + Error::invalid_consensus_state_timestamp(latest_consensus_state.timestamp(), now) + })?; + + if client_state.expired(duration) { + return Err(Error::header_not_within_trust_period(last_update_timestamp, now)) + } + let upgrade_client_state = msg.client_state.clone(); if client_state.latest_height() >= upgrade_client_state.latest_height() {