diff --git a/.changelog/unreleased/bug-fixes/1061-ease-frozen-height-check-ics07-try-from.md b/.changelog/unreleased/bug-fixes/1061-ease-frozen-height-check-ics07-try-from.md index 40e230d61..d3aa5cacc 100644 --- a/.changelog/unreleased/bug-fixes/1061-ease-frozen-height-check-ics07-try-from.md +++ b/.changelog/unreleased/bug-fixes/1061-ease-frozen-height-check-ics07-try-from.md @@ -1,3 +1,5 @@ - [ibc-client-tendermint-types] Ease frozen Height check in the tendermint - `ClientState` protobuf deserialization - ([\#1061](https://github.com/cosmos/ibc-rs/issues/1061)) + `ClientState` protobuf deserialization, and consequently include frozen client + check for client creation path. + ([\#1061](https://github.com/cosmos/ibc-rs/issues/1061)), + ([\#1063](https://github.com/cosmos/ibc-rs/pull/1063)) diff --git a/ibc-core/ics02-client/src/handler/create_client.rs b/ibc-core/ics02-client/src/handler/create_client.rs index d0e1d4d0a..e0a47e05b 100644 --- a/ibc-core/ics02-client/src/handler/create_client.rs +++ b/ibc-core/ics02-client/src/handler/create_client.rs @@ -1,6 +1,8 @@ //! Protocol logic specific to processing ICS2 messages of type `MsgCreateClient`. -use ibc_core_client_context::client_state::{ClientStateCommon, ClientStateExecution}; +use ibc_core_client_context::client_state::{ + ClientStateCommon, ClientStateExecution, ClientStateValidation, +}; use ibc_core_client_types::error::ClientError; use ibc_core_client_types::events::CreateClient; use ibc_core_client_types::msgs::MsgCreateClient; @@ -26,10 +28,19 @@ where let client_state = ctx.decode_client_state(client_state)?; - client_state.verify_consensus_state(consensus_state)?; - let client_id = client_state.client_type().build_client_id(id_counter); + let status = client_state.status(ctx.get_client_validation_context(), &client_id)?; + + if status.is_frozen() { + return Err(ClientError::ClientFrozen { + description: "the client is frozen".to_string(), + } + .into()); + }; + + client_state.verify_consensus_state(consensus_state)?; + if ctx.client_state(&client_id).is_ok() { return Err(ClientError::ClientStateAlreadyExists { client_id }.into()); }; diff --git a/ibc-testkit/tests/core/ics02_client/create_client.rs b/ibc-testkit/tests/core/ics02_client/create_client.rs index 91d465d6b..3540aefb6 100644 --- a/ibc-testkit/tests/core/ics02_client/create_client.rs +++ b/ibc-testkit/tests/core/ics02_client/create_client.rs @@ -2,9 +2,11 @@ use ibc::clients::tendermint::types::{ client_type as tm_client_type, ConsensusState as TmConsensusState, }; use ibc::core::client::context::client_state::ClientStateCommon; +use ibc::core::client::types::error::ClientError; use ibc::core::client::types::msgs::{ClientMsg, MsgCreateClient}; use ibc::core::client::types::Height; use ibc::core::entrypoint::{execute, validate}; +use ibc::core::handler::types::error::ContextError; use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::ValidationContext; use ibc_testkit::fixtures::clients::tendermint::{ @@ -86,3 +88,34 @@ fn test_tm_create_client_ok() { assert_eq!(expected_client_state.client_type(), client_type); assert_eq!(ctx.client_state(&client_id).unwrap(), expected_client_state); } + +#[test] +fn test_invalid_frozen_tm_client_creation() { + let signer = dummy_account_id(); + + let ctx = MockContext::default(); + + let router = MockRouter::new_with_transfer(); + + let tm_header = dummy_tendermint_header(); + + let tm_client_state = dummy_tm_client_state_from_header(tm_header.clone()) + .inner() + .clone() + .with_frozen_height(Height::min(0)); + + let msg = MsgCreateClient::new( + tm_client_state.into(), + TmConsensusState::from(tm_header).into(), + signer, + ); + + let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg.clone())); + + let res = validate(&ctx, &router, msg_envelope.clone()); + + assert!(matches!( + res, + Err(ContextError::ClientError(ClientError::ClientFrozen { .. })) + )) +}