From 2497fd197c5f7da334256e208e56122aff4faf1c Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 7 Nov 2024 14:53:32 +0100 Subject: [PATCH] Implement and test update client methods on relay context (#107) * Implement CanQueryConsensusStateHeight for StarknetChain * Implement CanSendTargetUpdateClientMessage to Starknet * Use relay.send_target_update_client_messages in test * Test full relaying of UpdateClient on both sides * Wire up CosmosToStarknetRelay * Update branch * Use back main branch --- light-client/Cargo.lock | 8 +- relayer/Cargo.lock | 54 ++-- .../src/components/chain.rs | 6 + .../src/impls/queries/consensus_state.rs | 31 +- .../update_client_payload.rs | 9 + .../src/contexts/chain.rs | 6 +- .../starknet-chain-context/src/impls/error.rs | 7 + .../src/tests/ibc_client.rs | 172 ----------- .../src/tests/mod.rs | 2 +- .../src/tests/update_clients.rs | 278 ++++++++++++++++++ .../src/contexts/cosmos_to_starknet_relay.rs | 99 +++++++ .../src/contexts/starknet_to_cosmos_relay.rs | 10 +- 12 files changed, 461 insertions(+), 221 deletions(-) delete mode 100644 relayer/crates/starknet-integration-tests/src/tests/ibc_client.rs create mode 100644 relayer/crates/starknet-integration-tests/src/tests/update_clients.rs diff --git a/light-client/Cargo.lock b/light-client/Cargo.lock index 4ac216c6..54b10a72 100644 --- a/light-client/Cargo.lock +++ b/light-client/Cargo.lock @@ -1004,7 +1004,7 @@ checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" [[package]] name = "hermes-cosmos-encoding-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "hermes-encoding-components", @@ -1018,7 +1018,7 @@ dependencies = [ [[package]] name = "hermes-encoding-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", ] @@ -1026,7 +1026,7 @@ dependencies = [ [[package]] name = "hermes-protobuf-encoding-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "hermes-encoding-components", @@ -1841,7 +1841,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.11.0", "proc-macro2", "quote", "syn 2.0.82", diff --git a/relayer/Cargo.lock b/relayer/Cargo.lock index 9e0042ca..a5c2cc93 100644 --- a/relayer/Cargo.lock +++ b/relayer/Cargo.lock @@ -1757,7 +1757,7 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermes-any-counterparty" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "cgp-error-eyre", @@ -1774,7 +1774,7 @@ dependencies = [ [[package]] name = "hermes-async-runtime-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "async-trait", "cgp", @@ -1797,7 +1797,7 @@ dependencies = [ [[package]] name = "hermes-chain-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "hermes-chain-type-components", @@ -1808,7 +1808,7 @@ dependencies = [ [[package]] name = "hermes-chain-type-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", ] @@ -1816,7 +1816,7 @@ dependencies = [ [[package]] name = "hermes-cosmos-chain-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "bech32 0.9.1", "cgp", @@ -1850,7 +1850,7 @@ dependencies = [ [[package]] name = "hermes-cosmos-encoding-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "hermes-encoding-components", @@ -1864,7 +1864,7 @@ dependencies = [ [[package]] name = "hermes-cosmos-integration-tests" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "eyre", @@ -1898,7 +1898,7 @@ dependencies = [ [[package]] name = "hermes-cosmos-relayer" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "eyre", @@ -1945,7 +1945,7 @@ dependencies = [ [[package]] name = "hermes-cosmos-test-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "hdpath", @@ -1970,7 +1970,7 @@ dependencies = [ [[package]] name = "hermes-cosmos-wasm-relayer" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "eyre", @@ -2022,7 +2022,7 @@ dependencies = [ [[package]] name = "hermes-encoding-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", ] @@ -2030,7 +2030,7 @@ dependencies = [ [[package]] name = "hermes-error" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "eyre", @@ -2040,7 +2040,7 @@ dependencies = [ [[package]] name = "hermes-ibc-test-suite" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "hermes-logging-components", @@ -2051,7 +2051,7 @@ dependencies = [ [[package]] name = "hermes-logger" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "hermes-logging-components", @@ -2063,7 +2063,7 @@ dependencies = [ [[package]] name = "hermes-logging-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", ] @@ -2071,7 +2071,7 @@ dependencies = [ [[package]] name = "hermes-protobuf-encoding-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "hermes-encoding-components", @@ -2082,7 +2082,7 @@ dependencies = [ [[package]] name = "hermes-relayer-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "hermes-chain-components", @@ -2095,7 +2095,7 @@ dependencies = [ [[package]] name = "hermes-relayer-components-extra" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "hermes-chain-type-components", @@ -2107,7 +2107,7 @@ dependencies = [ [[package]] name = "hermes-runtime" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "hermes-async-runtime-components", @@ -2119,7 +2119,7 @@ dependencies = [ [[package]] name = "hermes-runtime-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", ] @@ -2257,7 +2257,7 @@ dependencies = [ [[package]] name = "hermes-test-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "hermes-chain-type-components", @@ -2269,7 +2269,7 @@ dependencies = [ [[package]] name = "hermes-tokio-runtime-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "futures", @@ -2283,7 +2283,7 @@ dependencies = [ [[package]] name = "hermes-tracing-logging-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "hermes-logging-components", @@ -2295,7 +2295,7 @@ dependencies = [ [[package]] name = "hermes-wasm-client-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "cgp-error-eyre", @@ -2315,7 +2315,7 @@ dependencies = [ [[package]] name = "hermes-wasm-encoding-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "hermes-cosmos-encoding-components", @@ -2329,7 +2329,7 @@ dependencies = [ [[package]] name = "hermes-wasm-test-components" version = "0.1.0" -source = "git+https://github.com/informalsystems/hermes-sdk.git#d095d409ef1be6aa813ccf05ddef7555a6a025c1" +source = "git+https://github.com/informalsystems/hermes-sdk.git#acb0ad36cbc63c2509a2eb438f7f2298626201d0" dependencies = [ "cgp", "cgp-error-eyre", @@ -4248,7 +4248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", - "itertools 0.13.0", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.87", diff --git a/relayer/crates/starknet-chain-components/src/components/chain.rs b/relayer/crates/starknet-chain-components/src/components/chain.rs index 364049b8..475c0369 100644 --- a/relayer/crates/starknet-chain-components/src/components/chain.rs +++ b/relayer/crates/starknet-chain-components/src/components/chain.rs @@ -1,6 +1,8 @@ use cgp::core::component::WithProvider; use cgp::core::types::impls::UseDelegatedType; use cgp::prelude::*; +use hermes_chain_components::impls::queries::consensus_state_height::QueryConsensusStateHeightsAndFindHeightBefore; +use hermes_chain_components::impls::queries::consensus_state_heights::QueryLatestConsensusStateHeightAsHeights; pub use hermes_cosmos_chain_components::components::client::*; use hermes_cosmos_chain_components::impls::packet::packet_fields::CosmosPacketFieldReader; use hermes_cosmos_chain_components::impls::types::chain::ProvideCosmosChainTypes; @@ -198,6 +200,10 @@ define_components! { QueryCometClientState, ConsensusStateQuerierComponent: QueryCometConsensusState, + ConsensusStateHeightQuerierComponent: + QueryConsensusStateHeightsAndFindHeightBefore, + ConsensusStateHeightsQuerierComponent: + QueryLatestConsensusStateHeightAsHeights, ContractAddressQuerierComponent: GetContractAddressFromField, } diff --git a/relayer/crates/starknet-chain-components/src/impls/queries/consensus_state.rs b/relayer/crates/starknet-chain-components/src/impls/queries/consensus_state.rs index 560d458d..6fc32d02 100644 --- a/relayer/crates/starknet-chain-components/src/impls/queries/consensus_state.rs +++ b/relayer/crates/starknet-chain-components/src/impls/queries/consensus_state.rs @@ -22,6 +22,12 @@ use crate::types::client_id::ClientId; use crate::types::cosmos::consensus_state::CometConsensusState; use crate::types::cosmos::height::Height; +#[derive(Debug)] +pub struct ConsensusStateNotFound { + pub client_id: ClientId, + pub height: Height, +} + pub struct QueryCometConsensusState; impl ConsensusStateQuerier @@ -34,6 +40,7 @@ where + HasBlobType> + HasEncoding + CanQueryContractAddress + + CanRaiseError + CanRaiseError, Counterparty: HasConsensusStateType + HasHeightFields, @@ -45,7 +52,7 @@ where async fn query_consensus_state( chain: &Chain, _tag: PhantomData, - client_id: &Chain::ClientId, + client_id: &ClientId, consensus_height: &Counterparty::Height, _query_height: &Chain::Height, // TODO: figure whether we can perform height specific queries on Starknet ) -> Result { @@ -53,14 +60,13 @@ where let contract_address = chain.query_contract_address(PhantomData).await?; + let height = Height { + revision_number: Counterparty::revision_number(consensus_height), + revision_height: Counterparty::revision_height(consensus_height), + }; + let calldata = encoding - .encode(&( - client_id.sequence, - Height { - revision_number: Counterparty::revision_number(consensus_height), - revision_height: Counterparty::revision_height(consensus_height), - }, - )) + .encode(&(client_id.sequence, height.clone())) .map_err(Chain::raise_error)?; let output = chain @@ -74,6 +80,15 @@ where .decode(&raw_consensus_state) .map_err(Chain::raise_error)?; + // FIXME: Temporary workaround, as the current Cairo contract returns + // default value when the entry is not found. + if consensus_state.root.is_empty() { + return Err(Chain::raise_error(ConsensusStateNotFound { + client_id: client_id.clone(), + height, + })); + } + Ok(consensus_state) } } diff --git a/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/update_client_payload.rs b/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/update_client_payload.rs index eea7556d..2703c23c 100644 --- a/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/update_client_payload.rs +++ b/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/update_client_payload.rs @@ -19,6 +19,14 @@ use crate::types::cosmos::update::CometUpdateHeader; pub struct BuildUpdateCometClientPayload; +/* + Stub implementation of UpdateClient payload builder from Cosmos to Starknet. + We basically build a `CosmosCreateClientPayload`, and then use the state root + of the consensus state to build a dummy update header. + + TODO: refactor Cosmos UpdateClient header so that they are more easily + be converted into the Cairo encoding for the Starknet Comet contract. +*/ impl UpdateClientPayloadBuilder for BuildUpdateCometClientPayload where @@ -33,6 +41,7 @@ where async fn build_update_client_payload( chain: &Chain, trusted_height: &CosmosHeight, + // Ignore the target height for the dummy implementation _target_height: &CosmosHeight, _client_state: Chain::ClientState, ) -> Result { diff --git a/relayer/crates/starknet-chain-context/src/contexts/chain.rs b/relayer/crates/starknet-chain-context/src/contexts/chain.rs index 8ec6303c..bb9746f1 100644 --- a/relayer/crates/starknet-chain-context/src/contexts/chain.rs +++ b/relayer/crates/starknet-chain-context/src/contexts/chain.rs @@ -24,7 +24,9 @@ use hermes_relayer_components::chain::traits::payload_builders::update_client::C use hermes_relayer_components::chain::traits::queries::chain_status::CanQueryChainStatus; use hermes_relayer_components::chain::traits::queries::client_state::CanQueryClientState; use hermes_relayer_components::chain::traits::queries::consensus_state::CanQueryConsensusState; -use hermes_relayer_components::chain::traits::queries::consensus_state_height::CanQueryConsensusStateHeight; +use hermes_relayer_components::chain::traits::queries::consensus_state_height::{ + CanQueryConsensusStateHeight, CanQueryConsensusStateHeights, +}; use hermes_relayer_components::chain::traits::send_message::CanSendMessages; use hermes_relayer_components::chain::traits::types::chain_id::ChainIdGetter; use hermes_relayer_components::chain::traits::types::client_state::{ @@ -214,6 +216,8 @@ pub trait CanUseStarknetChain: + CanBuildUpdateClientMessage + CanQueryClientState + CanQueryConsensusState + + CanQueryConsensusStateHeights + + CanQueryConsensusStateHeight + CanQueryContractAddress where CosmosChain: HasClientStateType diff --git a/relayer/crates/starknet-chain-context/src/impls/error.rs b/relayer/crates/starknet-chain-context/src/impls/error.rs index 2b1d927c..09a3f3c9 100644 --- a/relayer/crates/starknet-chain-context/src/impls/error.rs +++ b/relayer/crates/starknet-chain-context/src/impls/error.rs @@ -11,6 +11,7 @@ use hermes_cairo_encoding_components::impls::encode_mut::bool::DecodeBoolError; use hermes_cairo_encoding_components::impls::encode_mut::end::NonEmptyBuffer; use hermes_cairo_encoding_components::impls::encode_mut::felt::UnexpectedEndOfBuffer; use hermes_cairo_encoding_components::impls::encode_mut::variant::VariantIndexOutOfBound; +use hermes_chain_type_components::traits::types::height::HasHeightType; use hermes_error::handlers::debug::DebugError; use hermes_error::handlers::display::DisplayError; use hermes_error::handlers::identity::ReturnError; @@ -24,13 +25,16 @@ use hermes_protobuf_encoding_components::impls::encode_mut::chunk::{ InvalidWireType, UnsupportedWireType, }; use hermes_protobuf_encoding_components::impls::encode_mut::proto_field::decode_required::RequiredFieldTagNotFound; +use hermes_relayer_components::chain::impls::queries::consensus_state_height::NoConsensusStateAtLessThanHeight; use hermes_relayer_components::chain::traits::send_message::EmptyMessageResponse; +use hermes_relayer_components::chain::traits::types::ibc::HasClientIdType; use hermes_relayer_components::transaction::impls::poll_tx_response::TxNoResponseError; use hermes_relayer_components::transaction::traits::types::tx_hash::HasTransactionHashType; use hermes_runtime::types::error::TokioRuntimeError; use hermes_starknet_chain_components::impls::error::account::RaiseAccountError; use hermes_starknet_chain_components::impls::error::provider::RaiseProviderError; use hermes_starknet_chain_components::impls::error::starknet::RaiseStarknetError; +use hermes_starknet_chain_components::impls::queries::consensus_state::ConsensusStateNotFound; use hermes_starknet_chain_components::impls::queries::contract_address::ContractAddressNotFound; use hermes_starknet_chain_components::impls::send_message::UnexpectedTransactionTraceType; use hermes_starknet_chain_components::types::event::UnknownEvent; @@ -86,8 +90,11 @@ delegate_components! { RequiredFieldTagNotFound, ContractAddressNotFound, EmptyMessageResponse, + ConsensusStateNotFound, <'a> UnknownEvent<'a>, <'a, Chain: HasTransactionHashType> TxNoResponseError<'a, Chain>, + <'a, Chain: HasClientIdType, Counterparty: HasHeightType> + NoConsensusStateAtLessThanHeight<'a, Chain, Counterparty>, ]: DebugError, [ diff --git a/relayer/crates/starknet-integration-tests/src/tests/ibc_client.rs b/relayer/crates/starknet-integration-tests/src/tests/ibc_client.rs deleted file mode 100644 index 01510649..00000000 --- a/relayer/crates/starknet-integration-tests/src/tests/ibc_client.rs +++ /dev/null @@ -1,172 +0,0 @@ -use core::marker::PhantomData; -use core::time::Duration; -use std::env::var; -use std::path::PathBuf; -use std::sync::Arc; -use std::time::SystemTime; - -use hermes_chain_components::traits::message_builders::update_client::CanBuildUpdateClientMessage; -use hermes_chain_components::traits::payload_builders::update_client::CanBuildUpdateClientPayload; -use hermes_chain_components::traits::queries::chain_status::CanQueryChainHeight; -use hermes_chain_components::traits::queries::client_state::CanQueryClientStateWithLatestHeight; -use hermes_chain_components::traits::queries::consensus_state::CanQueryConsensusStateWithLatestHeight; -use hermes_chain_components::traits::send_message::CanSendMessages; -use hermes_cosmos_integration_tests::init::init_test_runtime; -use hermes_cosmos_relayer::contexts::build::CosmosBuilder; -use hermes_cosmos_relayer::contexts::chain::CosmosChain; -use hermes_cosmos_wasm_relayer::context::cosmos_bootstrap::CosmosWithWasmClientBootstrap; -use hermes_error::types::Error; -use hermes_relayer_components::relay::traits::client_creator::CanCreateClient; -use hermes_relayer_components::relay::traits::target::SourceTarget; -use hermes_runtime_components::traits::fs::read_file::CanReadFileAsString; -use hermes_runtime_components::traits::sleep::CanSleep; -use hermes_starknet_chain_components::traits::contract::declare::CanDeclareContract; -use hermes_starknet_chain_components::traits::contract::deploy::CanDeployContract; -use hermes_starknet_chain_context::contexts::chain::StarknetChain; -use hermes_starknet_relayer::contexts::starknet_to_cosmos_relay::StarknetToCosmosRelay; -use hermes_test_components::bootstrap::traits::chain::CanBootstrapChain; -use ibc_relayer::chain::cosmos::client::Settings; -use ibc_relayer::config::types::TrustThreshold; -use ibc_relayer_types::Height as CosmosHeight; - -use crate::contexts::bootstrap::StarknetBootstrap; - -#[test] -fn test_starknet_comet_client_contract() -> Result<(), Error> { - let runtime = init_test_runtime(); - - runtime.runtime.clone().block_on(async move { - let starknet_chain_command_path = std::env::var("STARKNET_BIN") - .unwrap_or("starknet-devnet".into()) - .into(); - - let wasm_client_code_path = PathBuf::from( - var("STARKNET_WASM_CLIENT_PATH").expect("Wasm blob for Starknet light client is required"), - ); - - let timestamp = SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH)? - .as_secs(); - - let starknet_bootstrap = StarknetBootstrap { - runtime: runtime.clone(), - chain_command_path: starknet_chain_command_path, - chain_store_dir: format!("./test-data/{timestamp}/starknet").into(), - }; - - let wasm_client_byte_code = tokio::fs::read(&wasm_client_code_path).await?; - - let cosmos_builder = Arc::new(CosmosBuilder::new_with_default(runtime.clone())); - - let cosmos_bootstrap = Arc::new(CosmosWithWasmClientBootstrap { - runtime: runtime.clone(), - builder: cosmos_builder, - should_randomize_identifiers: true, - chain_store_dir: format!("./test-data/{timestamp}/cosmos").into(), - chain_command_path: "simd".into(), - account_prefix: "cosmos".into(), - staking_denom: "stake".into(), - transfer_denom: "coin".into(), - wasm_client_byte_code, - governance_proposal_authority: "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn".into(), // TODO: don't hard code this - }); - - let mut starknet_chain_driver = starknet_bootstrap.bootstrap_chain("starknet").await?; - - let starknet_chain = &mut starknet_chain_driver.chain; - - let cosmos_chain_driver = cosmos_bootstrap.bootstrap_chain("cosmos").await?; - - let cosmos_chain = &cosmos_chain_driver.chain; - - let comet_client_class_hash = { - let contract_path = std::env::var("COMET_CLIENT_CONTRACT")?; - - let contract_str = runtime.read_file_as_string(&contract_path.into()).await?; - - let contract = serde_json::from_str(&contract_str)?; - - let class_hash = starknet_chain.declare_contract(&contract).await?; - - println!("declared class: {:?}", class_hash); - - class_hash - }; - - let comet_client_address = starknet_chain - .deploy_contract(&comet_client_class_hash, false, &Vec::new()) - .await?; - - println!( - "deployed Comet client contract to address: {:?}", - comet_client_address - ); - - starknet_chain.ibc_client_contract_address = Some(comet_client_address); - - let create_client_settings = Settings { - max_clock_drift: Duration::from_secs(40), - trusting_period: Some(Duration::from_secs(60 * 60)), - trust_threshold: TrustThreshold::ONE_THIRD, - }; - - let client_id = StarknetToCosmosRelay::create_client( - SourceTarget, - starknet_chain, - cosmos_chain, - &create_client_settings, - &(), - ).await?; - - println!("created client on Starknet: {:?}", client_id); - - runtime.sleep(Duration::from_secs(1)).await; - - let update_header = { - let target_height = cosmos_chain.query_chain_height().await?; - - let client_state = starknet_chain.query_client_state_with_latest_height( - PhantomData::, &client_id - ) - .await?; - - let trusted_height = CosmosHeight::new( - client_state.latest_height.revision_number, - client_state.latest_height.revision_height, - )?; - - >::build_update_client_payload(cosmos_chain, &trusted_height, &target_height, client_state).await? - }; - - { - let message = >::build_update_client_message( - starknet_chain, &client_id, update_header.clone()).await?; - - let events = starknet_chain.send_messages(message).await?; - - println!("update client events: {:?}", events); - } - - { - let client_state = starknet_chain.query_client_state_with_latest_height( - PhantomData::, &client_id - ) - .await?; - - println!("queried client state: {client_state:?}"); - } - - { - let consensus_state = starknet_chain.query_consensus_state_with_latest_height( - PhantomData::, - &client_id, - &CosmosHeight::new(update_header.target_height.revision_number, update_header.target_height.revision_height)?, - ) - .await?; - - println!("queried consensus state: {consensus_state:?}"); - } - - Ok(()) - }) -} diff --git a/relayer/crates/starknet-integration-tests/src/tests/mod.rs b/relayer/crates/starknet-integration-tests/src/tests/mod.rs index 255a6f7a..ae131565 100644 --- a/relayer/crates/starknet-integration-tests/src/tests/mod.rs +++ b/relayer/crates/starknet-integration-tests/src/tests/mod.rs @@ -1,4 +1,4 @@ pub mod erc20; -pub mod ibc_client; pub mod ics20; pub mod light_client; +pub mod update_clients; diff --git a/relayer/crates/starknet-integration-tests/src/tests/update_clients.rs b/relayer/crates/starknet-integration-tests/src/tests/update_clients.rs new file mode 100644 index 00000000..55eb683a --- /dev/null +++ b/relayer/crates/starknet-integration-tests/src/tests/update_clients.rs @@ -0,0 +1,278 @@ +use core::marker::PhantomData; +use core::time::Duration; +use std::env::var; +use std::path::PathBuf; +use std::sync::Arc; +use std::time::SystemTime; + +use hermes_chain_components::traits::queries::chain_status::CanQueryChainHeight; +use hermes_chain_components::traits::queries::client_state::CanQueryClientStateWithLatestHeight; +use hermes_chain_components::traits::queries::consensus_state::CanQueryConsensusStateWithLatestHeight; +use hermes_cosmos_integration_tests::init::init_test_runtime; +use hermes_cosmos_relayer::contexts::build::CosmosBuilder; +use hermes_cosmos_relayer::contexts::chain::CosmosChain; +use hermes_cosmos_wasm_relayer::context::cosmos_bootstrap::CosmosWithWasmClientBootstrap; +use hermes_error::types::Error; +use hermes_relayer_components::relay::traits::client_creator::CanCreateClient; +use hermes_relayer_components::relay::traits::target::{DestinationTarget, SourceTarget}; +use hermes_relayer_components::relay::traits::update_client_message_builder::CanSendTargetUpdateClientMessage; +use hermes_runtime_components::traits::fs::read_file::CanReadFileAsString; +use hermes_runtime_components::traits::sleep::CanSleep; +use hermes_starknet_chain_components::traits::contract::declare::CanDeclareContract; +use hermes_starknet_chain_components::traits::contract::deploy::CanDeployContract; +use hermes_starknet_chain_components::types::payloads::client::StarknetCreateClientPayloadOptions; +use hermes_starknet_chain_context::contexts::chain::StarknetChain; +use hermes_starknet_relayer::contexts::starknet_to_cosmos_relay::StarknetToCosmosRelay; +use hermes_test_components::bootstrap::traits::chain::CanBootstrapChain; +use ibc_relayer::chain::cosmos::client::Settings; +use ibc_relayer::config::types::TrustThreshold; +use ibc_relayer_types::Height as CosmosHeight; +use sha2::{Digest, Sha256}; + +use crate::contexts::bootstrap::StarknetBootstrap; + +#[test] +fn test_relay_update_clients() -> Result<(), Error> { + let runtime = init_test_runtime(); + + runtime.runtime.clone().block_on(async move { + let starknet_chain_command_path = std::env::var("STARKNET_BIN") + .unwrap_or("starknet-devnet".into()) + .into(); + + let wasm_client_code_path = PathBuf::from( + var("STARKNET_WASM_CLIENT_PATH") + .expect("Wasm blob for Starknet light client is required"), + ); + + let timestamp = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH)? + .as_secs(); + + let starknet_bootstrap = StarknetBootstrap { + runtime: runtime.clone(), + chain_command_path: starknet_chain_command_path, + chain_store_dir: format!("./test-data/{timestamp}/starknet").into(), + }; + + let wasm_client_byte_code = tokio::fs::read(&wasm_client_code_path).await?; + + let wasm_code_hash: [u8; 32] = { + let mut hasher = Sha256::new(); + hasher.update(&wasm_client_byte_code); + hasher.finalize().into() + }; + + let cosmos_builder = Arc::new(CosmosBuilder::new_with_default(runtime.clone())); + + let cosmos_bootstrap = Arc::new(CosmosWithWasmClientBootstrap { + runtime: runtime.clone(), + builder: cosmos_builder, + should_randomize_identifiers: true, + chain_store_dir: format!("./test-data/{timestamp}/cosmos").into(), + chain_command_path: "simd".into(), + account_prefix: "cosmos".into(), + staking_denom: "stake".into(), + transfer_denom: "coin".into(), + wasm_client_byte_code, + governance_proposal_authority: "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn".into(), // TODO: don't hard code this + }); + + let mut starknet_chain_driver = starknet_bootstrap.bootstrap_chain("starknet").await?; + + let starknet_chain = &mut starknet_chain_driver.chain; + + let cosmos_chain_driver = cosmos_bootstrap.bootstrap_chain("cosmos").await?; + + let cosmos_chain = &cosmos_chain_driver.chain; + + let comet_client_class_hash = { + let contract_path = std::env::var("COMET_CLIENT_CONTRACT")?; + + let contract_str = runtime.read_file_as_string(&contract_path.into()).await?; + + let contract = serde_json::from_str(&contract_str)?; + + let class_hash = starknet_chain.declare_contract(&contract).await?; + + println!("declared class: {:?}", class_hash); + + class_hash + }; + + let comet_client_address = starknet_chain + .deploy_contract(&comet_client_class_hash, false, &Vec::new()) + .await?; + + println!( + "deployed Comet client contract to address: {:?}", + comet_client_address + ); + + starknet_chain.ibc_client_contract_address = Some(comet_client_address); + + let create_client_settings = Settings { + max_clock_drift: Duration::from_secs(40), + trusting_period: Some(Duration::from_secs(60 * 60)), + trust_threshold: TrustThreshold::ONE_THIRD, + }; + + let starknet_client_id = StarknetToCosmosRelay::create_client( + SourceTarget, + starknet_chain, + cosmos_chain, + &create_client_settings, + &(), + ) + .await?; + + println!("created client on Starknet: {:?}", starknet_client_id); + + let cosmos_client_id = StarknetToCosmosRelay::create_client( + DestinationTarget, + cosmos_chain, + starknet_chain, + &StarknetCreateClientPayloadOptions { wasm_code_hash }, + &(), + ) + .await?; + + println!("created client on Cosmos: {:?}", cosmos_client_id); + + let starknet_to_cosmos_relay = StarknetToCosmosRelay { + runtime: runtime.clone(), + src_chain: starknet_chain.clone(), + dst_chain: cosmos_chain.clone(), + src_client_id: starknet_client_id.clone(), + dst_client_id: cosmos_client_id.clone(), + }; + + { + println!("test relaying UpdateClient from Cosmos to Starknet"); + + { + let client_state = starknet_chain + .query_client_state_with_latest_height( + PhantomData::, + &starknet_client_id, + ) + .await?; + + println!("Cosmos client state on Starknet: {client_state:?}"); + + let consensus_state = starknet_chain + .query_consensus_state_with_latest_height( + PhantomData::, + &starknet_client_id, + &CosmosHeight::new( + client_state.latest_height.revision_number, + client_state.latest_height.revision_height, + )?, + ) + .await?; + + println!("Cosmos consensus state on Starknet: {consensus_state:?}"); + } + + runtime.sleep(Duration::from_secs(1)).await; + + let target_height = cosmos_chain.query_chain_height().await?; + + println!( + "updating Cosmos client on Starknet to height {}", + target_height + ); + + starknet_to_cosmos_relay + .send_target_update_client_messages(SourceTarget, &target_height) + .await?; + + println!("sent update client message from Cosmos to Starknet"); + + { + let client_state = starknet_chain + .query_client_state_with_latest_height( + PhantomData::, + &starknet_client_id, + ) + .await?; + + println!("Cosmos client state on Starknet after UpdateClient: {client_state:?}"); + + let consensus_state = starknet_chain + .query_consensus_state_with_latest_height( + PhantomData::, + &starknet_client_id, + &CosmosHeight::new( + client_state.latest_height.revision_number, + client_state.latest_height.revision_height, + )?, + ) + .await?; + + println!( + "Cosmos consensus state on Starknet after UpdateClient: {consensus_state:?}" + ); + } + } + + { + println!("test relaying UpdateClient from Cosmos to Starknet"); + + { + let client_state = cosmos_chain + .query_client_state_with_latest_height( + PhantomData::, + &cosmos_client_id, + ) + .await?; + + println!("Starknet client state on Cosmos: {client_state:?}"); + + let consensus_state = cosmos_chain + .query_consensus_state_with_latest_height( + PhantomData::, + &cosmos_client_id, + &client_state.client_state.latest_height.revision_height(), + ) + .await?; + + println!("Starknet consensus state on Cosmos: {consensus_state:?}"); + } + + let target_height = starknet_chain.query_chain_height().await?; + + println!( + "updating Starknet client on Cosmos to height {}", + target_height + ); + + starknet_to_cosmos_relay + .send_target_update_client_messages(DestinationTarget, &target_height) + .await?; + + { + let client_state = cosmos_chain + .query_client_state_with_latest_height( + PhantomData::, + &cosmos_client_id, + ) + .await?; + + println!("Starknet client state on Cosmos after update: {client_state:?}"); + + let consensus_state = cosmos_chain + .query_consensus_state_with_latest_height( + PhantomData::, + &cosmos_client_id, + &client_state.client_state.latest_height.revision_height(), + ) + .await?; + + println!("Starknet consensus state on Cosmos after update: {consensus_state:?}"); + } + } + + Ok(()) + }) +} diff --git a/relayer/crates/starknet-relayer/src/contexts/cosmos_to_starknet_relay.rs b/relayer/crates/starknet-relayer/src/contexts/cosmos_to_starknet_relay.rs index 482f821f..c8002a0a 100644 --- a/relayer/crates/starknet-relayer/src/contexts/cosmos_to_starknet_relay.rs +++ b/relayer/crates/starknet-relayer/src/contexts/cosmos_to_starknet_relay.rs @@ -1,9 +1,108 @@ +use cgp::core::component::UseDelegate; +use cgp::core::error::{ErrorRaiserComponent, ErrorTypeComponent}; use cgp::prelude::*; use hermes_cosmos_relayer::contexts::chain::CosmosChain; +use hermes_error::impls::ProvideHermesError; +use hermes_logger::ProvideHermesLogger; +use hermes_logging_components::traits::has_logger::{ + GlobalLoggerGetterComponent, LoggerGetterComponent, LoggerTypeComponent, +}; +use hermes_relayer_components::components::default::relay::*; +use hermes_relayer_components::error::impls::retry::ReturnMaxRetry; +use hermes_relayer_components::error::traits::retry::MaxErrorRetryGetterComponent; +use hermes_relayer_components::relay::traits::chains::{ + CanRaiseRelayChainErrors, HasRelayChains, ProvideRelayChains, +}; +use hermes_relayer_components::relay::traits::client_creator::CanCreateClient; +use hermes_relayer_components::relay::traits::target::{DestinationTarget, SourceTarget}; +use hermes_relayer_components::relay::traits::update_client_message_builder::{ + CanBuildTargetUpdateClientMessage, CanSendTargetUpdateClientMessage, +}; +use hermes_runtime::types::runtime::HermesRuntime; +use hermes_runtime_components::traits::runtime::{ + ProvideDefaultRuntimeField, RuntimeGetterComponent, RuntimeTypeComponent, +}; +use hermes_starknet_chain_components::types::client_id::ClientId as StarknetClientId; use hermes_starknet_chain_context::contexts::chain::StarknetChain; +use ibc_relayer_types::core::ics24_host::identifier::ClientId as CosmosClientId; + +use crate::impls::error::HandleStarknetRelayError; #[derive(Clone, HasField)] pub struct CosmosToStarknetRelay { + pub runtime: HermesRuntime, pub src_chain: CosmosChain, pub dst_chain: StarknetChain, + pub src_client_id: CosmosClientId, + pub dst_client_id: StarknetClientId, +} + +pub struct CosmosToStarknetRelayComponents; + +impl HasComponents for CosmosToStarknetRelay { + type Components = CosmosToStarknetRelayComponents; +} + +with_default_relay_components! { + delegate_components! { + CosmosToStarknetRelayComponents { + @DefaultRelayComponents: DefaultRelayComponents, + } + } +} + +delegate_components! { + CosmosToStarknetRelayComponents { + ErrorTypeComponent: ProvideHermesError, + ErrorRaiserComponent: UseDelegate, + [ + RuntimeTypeComponent, + RuntimeGetterComponent, + ]: + ProvideDefaultRuntimeField, + [ + LoggerTypeComponent, + LoggerGetterComponent, + GlobalLoggerGetterComponent, + ]: + ProvideHermesLogger, + MaxErrorRetryGetterComponent: + ReturnMaxRetry<3>, + } +} + +impl ProvideRelayChains for CosmosToStarknetRelayComponents { + type SrcChain = CosmosChain; + + type DstChain = StarknetChain; + + fn src_chain(relay: &CosmosToStarknetRelay) -> &CosmosChain { + &relay.src_chain + } + + fn dst_chain(relay: &CosmosToStarknetRelay) -> &StarknetChain { + &relay.dst_chain + } + + fn src_client_id(relay: &CosmosToStarknetRelay) -> &CosmosClientId { + &relay.src_client_id + } + + fn dst_client_id(relay: &CosmosToStarknetRelay) -> &StarknetClientId { + &relay.dst_client_id + } +} + +pub trait CanUseCosmosToStarknetRelay: + HasRelayChains + + CanCreateClient + + CanCreateClient + + CanRaiseRelayChainErrors + + CanBuildTargetUpdateClientMessage + + CanBuildTargetUpdateClientMessage + + CanSendTargetUpdateClientMessage + + CanSendTargetUpdateClientMessage +{ } + +impl CanUseCosmosToStarknetRelay for CosmosToStarknetRelay {} diff --git a/relayer/crates/starknet-relayer/src/contexts/starknet_to_cosmos_relay.rs b/relayer/crates/starknet-relayer/src/contexts/starknet_to_cosmos_relay.rs index 1e907cb9..4f49a984 100644 --- a/relayer/crates/starknet-relayer/src/contexts/starknet_to_cosmos_relay.rs +++ b/relayer/crates/starknet-relayer/src/contexts/starknet_to_cosmos_relay.rs @@ -97,18 +97,12 @@ pub trait CanUseStarknetToCosmosRelay: HasRelayChains + CanCreateClient + CanCreateClient - // + CanSendTargetUpdateClientMessage + CanRaiseRelayChainErrors + + CanBuildTargetUpdateClientMessage + CanBuildTargetUpdateClientMessage + + CanSendTargetUpdateClientMessage + CanSendTargetUpdateClientMessage { } impl CanUseStarknetToCosmosRelay for StarknetToCosmosRelay {} - -// pub trait CanBuildUpdateClientMessage: -// TargetUpdateClientMessageBuilder -// { -// } - -// impl CanBuildUpdateClientMessage for BuildUpdateClientMessages {}