diff --git a/cairo-contracts/packages/core/src/channel/components/handler.cairo b/cairo-contracts/packages/core/src/channel/components/handler.cairo index 2fbcbc7c..3658fc4a 100644 --- a/cairo-contracts/packages/core/src/channel/components/handler.cairo +++ b/cairo-contracts/packages/core/src/channel/components/handler.cairo @@ -174,15 +174,6 @@ pub mod ChannelHandlerComponent { self.read_packet_ack(@port_id, @channel_id, @sequence) } - fn is_packet_received( - self: @ComponentState, - port_id: PortId, - channel_id: ChannelId, - sequence: Sequence - ) -> bool { - self.packet_ack_exists(@port_id, @channel_id, @sequence) - } - fn unreceived_packet_sequences( self: @ComponentState, port_id: PortId, diff --git a/cairo-contracts/packages/core/src/channel/interface.cairo b/cairo-contracts/packages/core/src/channel/interface.cairo index 5c683a53..af08c48d 100644 --- a/cairo-contracts/packages/core/src/channel/interface.cairo +++ b/cairo-contracts/packages/core/src/channel/interface.cairo @@ -67,9 +67,6 @@ pub trait IChannelQuery { fn packet_acknowledgement( self: @TContractState, port_id: PortId, channel_id: ChannelId, sequence: Sequence ) -> Commitment; - fn is_packet_received( - self: @TContractState, port_id: PortId, channel_id: ChannelId, sequence: Sequence - ) -> bool; fn unreceived_packet_sequences( self: @TContractState, port_id: PortId, channel_id: ChannelId, sequences: Array ) -> Array; diff --git a/cairo-contracts/packages/core/src/commitment/types.cairo b/cairo-contracts/packages/core/src/commitment/types.cairo index c1b8efd4..4d40448d 100644 --- a/cairo-contracts/packages/core/src/commitment/types.cairo +++ b/cairo-contracts/packages/core/src/commitment/types.cairo @@ -52,7 +52,9 @@ pub fn compute_packet_commitment( json_packet_data: @ByteArray, timeout_height: Height, timeout_timestamp: Timestamp ) -> Commitment { let mut coll = U32CollectorImpl::init(); - coll.extend(timeout_timestamp); + // ibc-go uses nanosecs + // https://github.com/cosmos/ibc-go/blob/98d7e7550a23ecf8d96ce042ab11ef857b184f2a/proto/ibc/core/channel/v1/channel.proto#L179-L180 + coll.extend(timeout_timestamp.timestamp * 1_000_000_000); coll.extend(timeout_height); coll.extend_from_chunk(compute_sha256_byte_array(json_packet_data)); compute_sha256_u32_array(coll.value(), 0, 0).into() diff --git a/cairo-contracts/packages/core/src/tests/commitment.cairo b/cairo-contracts/packages/core/src/tests/commitment.cairo index d785731f..c7b3fc8b 100644 --- a/cairo-contracts/packages/core/src/tests/commitment.cairo +++ b/cairo-contracts/packages/core/src/tests/commitment.cairo @@ -52,7 +52,7 @@ fn test_array_u8_into_array_u32() { fn test_compute_packet_commitment() { let commitment = PACKET_COMMITMENT_ON_SN(ERC20()); let expected: [u32; 8] = [ - 3458244073, 1576048754, 4210798310, 1002247062, 2365181318, 2763927782, 545147151, 944653547 + 1561496803, 591083406, 1958596266, 2480824962, 846563094, 2634790765, 145282158, 2139799705 ]; assert_eq!(commitment, expected.into()); } diff --git a/light-client/Cargo.lock b/light-client/Cargo.lock index 62a78652..71c260d5 100644 --- a/light-client/Cargo.lock +++ b/light-client/Cargo.lock @@ -1135,12 +1135,13 @@ dependencies = [ [[package]] name = "ibc-client-cw" version = "0.56.0" -source = "git+https://github.com/informalsystems/cosmwasm-ibc.git?branch=luca_joss/add-cw-client-extension-trait#9160e505a664aaa430f9c3cdc40e115d6d364ceb" +source = "git+https://github.com/informalsystems/cosmwasm-ibc.git?branch=starknet/demo2#7d37df42469728747fde966d6e4789bc87404b42" dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus", "derive_more 1.0.0", + "ibc-client-tendermint", "ibc-client-wasm-types", "ibc-core", "prost", diff --git a/light-client/Cargo.toml b/light-client/Cargo.toml index f414819e..57e5427e 100644 --- a/light-client/Cargo.toml +++ b/light-client/Cargo.toml @@ -61,7 +61,7 @@ ibc-client-starknet = { path = "./ibc-client-starknet" } ibc-client-starknet-cw = { path = "./ibc-client-starknet-cw" } ibc-client-starknet-types = { path = "./ibc-client-starknet-types" } -ibc-client-cw = { git = "https://github.com/informalsystems/cosmwasm-ibc.git", branch = "luca_joss/add-cw-client-extension-trait" } +ibc-client-cw = { git = "https://github.com/informalsystems/cosmwasm-ibc.git", branch = "starknet/demo2" } ibc = { git = "https://github.com/cosmos/ibc-rs", branch = "main" } ibc-core = { git = "https://github.com/cosmos/ibc-rs", branch = "main" } diff --git a/light-client/ibc-client-starknet/src/client_state/cw.rs b/light-client/ibc-client-starknet/src/client_state/cw.rs new file mode 100644 index 00000000..a10d7c13 --- /dev/null +++ b/light-client/ibc-client-starknet/src/client_state/cw.rs @@ -0,0 +1,14 @@ +use ibc_client_cw::api::CwClientStateExecution; +use ibc_client_cw::context::client_ctx::CwClientExecution; + +use super::ClientState; +use crate::ConsensusState; + +impl<'a, E> CwClientStateExecution<'a, E> for ClientState +where + E: CwClientExecution<'a, ClientStateMut = ClientState, ConsensusStateRef = ConsensusState>, +{ + fn public_key(&self) -> Option> { + Some(self.0.pub_key.clone()) + } +} diff --git a/light-client/ibc-client-starknet/src/client_state/execution.rs b/light-client/ibc-client-starknet/src/client_state/execution.rs index c13c2aa4..a18cddb5 100644 --- a/light-client/ibc-client-starknet/src/client_state/execution.rs +++ b/light-client/ibc-client-starknet/src/client_state/execution.rs @@ -62,13 +62,11 @@ where let raw_header = signed_header.header; - let header_digest = ctx.generate_sha256_digest(&raw_header); + let header_digest = ctx.checksum(&raw_header); - let deps = ctx - .cosmwasm_execute_context() - .ok_or_else(|| ClientError::ClientSpecific { - description: "missing Deps from context".to_owned(), - })?; + let deps = ctx.deps_mut().ok_or_else(|| ClientError::ClientSpecific { + description: "missing Deps from context".to_owned(), + })?; match deps.api.secp256k1_verify( header_digest.as_slice(), diff --git a/light-client/ibc-client-starknet/src/client_state/mod.rs b/light-client/ibc-client-starknet/src/client_state/mod.rs index 0977bb7d..ead0506a 100644 --- a/light-client/ibc-client-starknet/src/client_state/mod.rs +++ b/light-client/ibc-client-starknet/src/client_state/mod.rs @@ -1,4 +1,5 @@ pub mod common; +pub mod cw; pub mod execution; pub mod validation; diff --git a/nix/ibc-starknet-cw.nix b/nix/ibc-starknet-cw.nix index 11647f3c..548bdf05 100644 --- a/nix/ibc-starknet-cw.nix +++ b/nix/ibc-starknet-cw.nix @@ -12,7 +12,7 @@ let outputHashes = { "hermes-cosmos-encoding-components-0.1.0" = "sha256-uxXpzxVc89DkAC4VqC/Au3cpBzUbxiSS2KiFKZ+rqdg="; "cgp-0.3.1" = "sha256-AOQ+WVQWPlF2ZfYYc5Eq3t7XAljd5P2qExWLYZWNnd8="; - "ibc-client-cw-0.56.0" = "sha256-EkLxuJfr3vf0busmSZD7DwOS9GfgfhT+sdopi1nNiCs="; + "ibc-client-cw-0.56.0" = "sha256-DA3AB8ejUrx4ksBtN/vaOznjpKE0+0F6vGA7JmWyHWA="; "ibc-0.56.0" = "sha256-7DPIqu/zs0szjmtJTfXI2eQ0HEkRyvGjArcMZsFWMT4="; }; }; diff --git a/relayer/Cargo.lock b/relayer/Cargo.lock index 188c74d3..2a7870d6 100644 --- a/relayer/Cargo.lock +++ b/relayer/Cargo.lock @@ -2598,6 +2598,7 @@ dependencies = [ "sha2 0.10.8", "starknet", "tendermint-rpc", + "tiny-bip39", "tokio", "toml", "tracing", @@ -2625,6 +2626,7 @@ dependencies = [ "ibc", "serde", "starknet", + "tiny-bip39", "url", ] diff --git a/relayer/Cargo.toml b/relayer/Cargo.toml index 16ce3b8f..d9070788 100644 --- a/relayer/Cargo.toml +++ b/relayer/Cargo.toml @@ -53,6 +53,7 @@ tracing-subscriber = { version = "0.3.18" } flate2 = { version = "1.0" } http = { version = "1.0.0" } futures = { version = "0.3.30", default-features = false } +tiny-bip39 = { version = "1.0.0" } ibc = { version = "0.56.0" } ibc-proto = { version = "0.51.1" } diff --git a/relayer/crates/starknet-chain-components/src/impls/mod.rs b/relayer/crates/starknet-chain-components/src/impls/mod.rs index 977616cc..acade873 100644 --- a/relayer/crates/starknet-chain-components/src/impls/mod.rs +++ b/relayer/crates/starknet-chain-components/src/impls/mod.rs @@ -9,6 +9,7 @@ pub mod messages; pub mod packet_fields; pub mod packet_filter; pub mod payload_builders; +pub mod proof_signer; pub mod provider; pub mod queries; pub mod send_message; diff --git a/relayer/crates/starknet-chain-components/src/impls/payload_builders/create_client.rs b/relayer/crates/starknet-chain-components/src/impls/payload_builders/create_client.rs index 27f858b7..9ec2e462 100644 --- a/relayer/crates/starknet-chain-components/src/impls/payload_builders/create_client.rs +++ b/relayer/crates/starknet-chain-components/src/impls/payload_builders/create_client.rs @@ -1,5 +1,6 @@ use cgp::prelude::CanRaiseAsyncError; use hermes_chain_components::traits::types::chain_id::HasChainId; +use hermes_cosmos_chain_components::types::key_types::secp256k1::Secp256k1KeyPair; use hermes_relayer_components::chain::traits::payload_builders::create_client::CreateClientPayloadBuilder; use hermes_relayer_components::chain::traits::queries::chain_status::CanQueryChainStatus; use hermes_relayer_components::chain::traits::types::create_client::{ @@ -10,6 +11,7 @@ use ibc::core::client::types::Height; use ibc::core::host::types::identifiers::ChainId; use ibc::primitives::Timestamp; +use crate::traits::proof_signer::HasStarknetProofSigner; use crate::types::consensus_state::{StarknetConsensusState, WasmStarknetConsensusState}; use crate::types::payloads::client::{ StarknetCreateClientPayload, StarknetCreateClientPayloadOptions, @@ -27,6 +29,7 @@ where > + HasCreateClientPayloadType + CanQueryChainStatus + HasChainId + + HasStarknetProofSigner + CanRaiseAsyncError<&'static str> + CanRaiseAsyncError, { @@ -53,6 +56,7 @@ where chain_id: chain.chain_id().clone(), client_state_wasm_code_hash: create_client_options.wasm_code_hash.into(), consensus_state, + proof_signer_pub_key: chain.proof_signer().public_key.serialize().to_vec(), }) } } diff --git a/relayer/crates/starknet-chain-components/src/impls/payload_builders/update_client.rs b/relayer/crates/starknet-chain-components/src/impls/payload_builders/update_client.rs index 03a28601..11fcb481 100644 --- a/relayer/crates/starknet-chain-components/src/impls/payload_builders/update_client.rs +++ b/relayer/crates/starknet-chain-components/src/impls/payload_builders/update_client.rs @@ -1,4 +1,9 @@ -use cgp::prelude::CanRaiseAsyncError; +use cgp::prelude::{Async, CanRaiseAsyncError}; +use hermes_cosmos_chain_components::types::key_types::secp256k1::Secp256k1KeyPair; +use hermes_encoding_components::traits::encode::CanEncode; +use hermes_encoding_components::traits::has_encoding::HasDefaultEncoding; +use hermes_encoding_components::types::AsBytes; +use hermes_protobuf_encoding_components::types::strategy::ViaProtobuf; use hermes_relayer_components::chain::traits::payload_builders::update_client::UpdateClientPayloadBuilder; use hermes_relayer_components::chain::traits::queries::chain_status::CanQueryChainStatus; use hermes_relayer_components::chain::traits::types::client_state::HasClientStateType; @@ -10,6 +15,7 @@ use ibc_client_starknet_types::header::StarknetHeader; use starknet::core::types::{BlockId, MaybePendingBlockWithTxHashes}; use starknet::providers::{Provider, ProviderError}; +use crate::traits::proof_signer::HasStarknetProofSigner; use crate::traits::provider::HasStarknetProvider; use crate::types::consensus_state::StarknetConsensusState; use crate::types::payloads::client::StarknetUpdateClientPayload; @@ -17,7 +23,7 @@ use crate::types::status::StarknetChainStatus; pub struct BuildStarknetUpdateClientPayload; -impl UpdateClientPayloadBuilder +impl UpdateClientPayloadBuilder for BuildStarknetUpdateClientPayload where Chain: HasHeightType @@ -26,7 +32,12 @@ where + CanQueryChainStatus + HasStarknetProvider + CanRaiseAsyncError<&'static str> - + CanRaiseAsyncError, + + HasDefaultEncoding + + HasStarknetProofSigner + + CanRaiseAsyncError + + CanRaiseAsyncError + + CanRaiseAsyncError, + Encoding: Async + CanEncode>, { async fn build_update_client_payload( chain: &Chain, @@ -63,6 +74,15 @@ where consensus_state, }; - Ok(StarknetUpdateClientPayload { header }) + let encoded_header = Chain::default_encoding() + .encode(&header) + .map_err(Chain::raise_error)?; + + let signature = chain + .proof_signer() + .sign(&encoded_header) + .map_err(Chain::raise_error)?; + + Ok(StarknetUpdateClientPayload { header, signature }) } } diff --git a/relayer/crates/starknet-chain-components/src/impls/proof_signer.rs b/relayer/crates/starknet-chain-components/src/impls/proof_signer.rs new file mode 100644 index 00000000..f2c6f2d8 --- /dev/null +++ b/relayer/crates/starknet-chain-components/src/impls/proof_signer.rs @@ -0,0 +1,28 @@ +use core::marker::PhantomData; + +use cgp::prelude::*; + +use crate::traits::proof_signer::{ + HasStarknetProofSignerType, ProvideStarknetProofSignerType, StarknetProofSignerGetter, +}; + +pub struct GetStarknetProofSignerField(pub PhantomData); + +impl ProvideStarknetProofSignerType for GetStarknetProofSignerField +where + Chain: Async + HasField, + Tag: Async, + Chain::Value: Async, +{ + type ProofSigner = Chain::Value; +} + +impl StarknetProofSignerGetter for GetStarknetProofSignerField +where + Chain: Async + HasStarknetProofSignerType + HasField, + Tag: Async, +{ + fn proof_signer(chain: &Chain) -> &Chain::ProofSigner { + chain.get_field(PhantomData) + } +} diff --git a/relayer/crates/starknet-chain-components/src/impls/queries/ack_commitment.rs b/relayer/crates/starknet-chain-components/src/impls/queries/ack_commitment.rs index d4f4906b..f9eaaf8a 100644 --- a/relayer/crates/starknet-chain-components/src/impls/queries/ack_commitment.rs +++ b/relayer/crates/starknet-chain-components/src/impls/queries/ack_commitment.rs @@ -3,6 +3,8 @@ use core::marker::PhantomData; use cgp::prelude::*; use hermes_cairo_encoding_components::strategy::ViaCairo; use hermes_cairo_encoding_components::types::as_felt::AsFelt; +use hermes_chain_components::traits::commitment_prefix::HasIbcCommitmentPrefix; +use hermes_chain_components::traits::queries::chain_status::CanQueryChainStatus; use hermes_chain_components::traits::queries::packet_acknowledgement::PacketAcknowledgementQuerier; use hermes_chain_components::traits::types::height::HasHeightType; use hermes_chain_components::traits::types::ibc::{ @@ -10,22 +12,27 @@ use hermes_chain_components::traits::types::ibc::{ }; use hermes_chain_components::traits::types::packets::ack::HasAcknowledgementType; use hermes_chain_components::traits::types::proof::HasCommitmentProofType; +use hermes_cosmos_chain_components::types::key_types::secp256k1::Secp256k1KeyPair; use hermes_encoding_components::traits::decode::CanDecode; use hermes_encoding_components::traits::encode::CanEncode; use hermes_encoding_components::traits::has_encoding::HasEncoding; use hermes_encoding_components::traits::types::encoded::HasEncodedType; use ibc::core::host::types::identifiers::{PortId as IbcPortId, Sequence as IbcSequence}; +use ibc::core::host::types::path::{AckPath, Path}; use starknet::core::types::Felt; use starknet::macros::selector; use crate::traits::contract::call::CanCallContract; +use crate::traits::proof_signer::HasStarknetProofSigner; use crate::traits::queries::address::CanQueryContractAddress; use crate::traits::types::blob::HasBlobType; use crate::traits::types::method::HasSelectorType; use crate::types::channel_id::ChannelId; use crate::types::commitment_proof::StarknetCommitmentProof; +use crate::types::membership_proof_signer::MembershipVerifierContainer; use crate::types::messages::ibc::channel::PortId as CairoPortId; use crate::types::messages::ibc::packet::Sequence; +use crate::types::status::StarknetChainStatus; pub struct QueryStarknetAckCommitment; @@ -33,6 +40,8 @@ impl PacketAcknowledgementQuerier + + CanQueryChainStatus + + HasIbcCommitmentPrefix> + HasChannelIdType + HasPortIdType + HasAcknowledgementType> @@ -42,6 +51,8 @@ where + CanQueryContractAddress + HasEncoding + CanCallContract + + HasStarknetProofSigner + + CanRaiseAsyncError + CanRaiseAsyncError, Counterparty: HasSequenceType, @@ -54,7 +65,7 @@ where channel_id: &ChannelId, port_id: &IbcPortId, sequence: &IbcSequence, - height: &u64, + _height: &u64, ) -> Result<(Vec, StarknetCommitmentProof), Chain::Error> { let encoding = chain.encoding(); @@ -80,12 +91,6 @@ where ) .await?; - // TODO(rano): how to get the proof? - let dummy_proof = StarknetCommitmentProof { - proof_height: *height, - proof_bytes: vec![0x1], - }; - let product![ack,] = encoding.decode(&output).map_err(Chain::raise_error)?; let ack_bytes = ack @@ -94,6 +99,29 @@ where .flat_map(|felt| felt.to_be_bytes()) .collect::>(); + let chain_status = chain.query_chain_status().await?; + + let unsigned_membership_proof_bytes = MembershipVerifierContainer { + state_root: chain_status.block_hash.to_bytes_be().to_vec(), + prefix: chain.ibc_commitment_prefix().clone(), + path: Path::Ack(AckPath::new(port_id, channel_id, *sequence)) + .to_string() + .into(), + value: Some(ack_bytes.clone()), + } + .canonical_bytes(); + + let signed_bytes = chain + .proof_signer() + .sign(&unsigned_membership_proof_bytes) + .map_err(Chain::raise_error)?; + + // TODO(rano): how to get the proof? + let dummy_proof = StarknetCommitmentProof { + proof_height: chain_status.height, + proof_bytes: signed_bytes, + }; + Ok((ack_bytes, dummy_proof)) } } diff --git a/relayer/crates/starknet-chain-components/src/impls/queries/channel_end.rs b/relayer/crates/starknet-chain-components/src/impls/queries/channel_end.rs index 203db1db..baeb26a7 100644 --- a/relayer/crates/starknet-chain-components/src/impls/queries/channel_end.rs +++ b/relayer/crates/starknet-chain-components/src/impls/queries/channel_end.rs @@ -3,7 +3,10 @@ use core::marker::PhantomData; use cgp::prelude::*; use hermes_cairo_encoding_components::strategy::ViaCairo; use hermes_cairo_encoding_components::types::as_felt::AsFelt; -use hermes_chain_components::traits::queries::chain_status::CanQueryChainHeight; +use hermes_chain_components::traits::commitment_prefix::HasIbcCommitmentPrefix; +use hermes_chain_components::traits::queries::chain_status::{ + CanQueryChainHeight, CanQueryChainStatus, +}; use hermes_chain_components::traits::queries::channel_end::{ ChannelEndQuerier, ChannelEndWithProofsQuerier, }; @@ -11,20 +14,26 @@ use hermes_chain_components::traits::types::channel::HasChannelEndType; use hermes_chain_components::traits::types::height::HasHeightType; use hermes_chain_components::traits::types::ibc::{HasChannelIdType, HasPortIdType}; use hermes_chain_components::traits::types::proof::HasCommitmentProofType; +use hermes_cosmos_chain_components::types::key_types::secp256k1::Secp256k1KeyPair; use hermes_encoding_components::traits::decode::CanDecode; use hermes_encoding_components::traits::encode::CanEncode; use hermes_encoding_components::traits::has_encoding::HasEncoding; use hermes_encoding_components::traits::types::encoded::HasEncodedType; +use ibc::core::host::types::path::{ChannelEndPath, Path}; +use ibc_proto::Protobuf; use starknet::core::types::Felt; use starknet::macros::selector; use crate::traits::contract::call::CanCallContract; +use crate::traits::proof_signer::HasStarknetProofSigner; use crate::traits::queries::address::CanQueryContractAddress; use crate::traits::types::blob::HasBlobType; use crate::traits::types::method::HasSelectorType; use crate::types::channel_id::{ChannelEnd, ChannelId}; use crate::types::commitment_proof::StarknetCommitmentProof; +use crate::types::membership_proof_signer::MembershipVerifierContainer; use crate::types::messages::ibc::channel::PortId; +use crate::types::status::StarknetChainStatus; pub struct QueryChannelEndFromStarknet; @@ -74,6 +83,8 @@ impl ChannelEndWithProofsQuerier + CanQueryChainHeight + + CanQueryChainStatus + + HasIbcCommitmentPrefix> + HasChannelIdType + HasPortIdType + HasChannelEndType @@ -83,6 +94,8 @@ where + CanQueryContractAddress + HasEncoding + CanCallContract + + HasStarknetProofSigner + + CanRaiseAsyncError + CanRaiseAsyncError, Encoding: CanEncode + CanDecode @@ -108,15 +121,30 @@ where .call_contract(&contract_address, &selector!("channel_end"), &calldata) .await?; - // TODO(rano): how to get the proof? + let channel_end = encoding.decode(&output).map_err(Chain::raise_error)?; + + let chain_status = chain.query_chain_status().await?; + + let unsigned_membership_proof_bytes = MembershipVerifierContainer { + state_root: chain_status.block_hash.to_bytes_be().to_vec(), + prefix: chain.ibc_commitment_prefix().clone(), + path: Path::ChannelEnd(ChannelEndPath::new(port_id, channel_id)) + .to_string() + .into(), + value: Some(channel_end.clone().encode_vec()), + } + .canonical_bytes(); + + let signed_bytes = chain + .proof_signer() + .sign(&unsigned_membership_proof_bytes) + .map_err(Chain::raise_error)?; + let dummy_proof = StarknetCommitmentProof { - proof_height: chain.query_chain_height().await?, - proof_bytes: vec![0x1], + proof_height: chain_status.height, + proof_bytes: signed_bytes, }; - Ok(( - encoding.decode(&output).map_err(Chain::raise_error)?, - dummy_proof, - )) + Ok((channel_end, dummy_proof)) } } diff --git a/relayer/crates/starknet-chain-components/src/impls/queries/client_state.rs b/relayer/crates/starknet-chain-components/src/impls/queries/client_state.rs index fc4e47cc..ae25a681 100644 --- a/relayer/crates/starknet-chain-components/src/impls/queries/client_state.rs +++ b/relayer/crates/starknet-chain-components/src/impls/queries/client_state.rs @@ -3,6 +3,8 @@ use core::marker::PhantomData; use cgp::prelude::*; use hermes_cairo_encoding_components::strategy::ViaCairo; use hermes_cairo_encoding_components::types::as_felt::AsFelt; +use hermes_chain_components::traits::commitment_prefix::HasIbcCommitmentPrefix; +use hermes_chain_components::traits::queries::chain_status::CanQueryChainStatus; use hermes_chain_components::traits::queries::client_state::{ CanQueryClientState, ClientStateQuerier, ClientStateWithProofsQuerier, }; @@ -10,20 +12,25 @@ use hermes_chain_components::traits::types::client_state::HasClientStateType; use hermes_chain_components::traits::types::height::HasHeightType; use hermes_chain_components::traits::types::ibc::HasClientIdType; use hermes_chain_components::traits::types::proof::HasCommitmentProofType; +use hermes_cosmos_chain_components::types::key_types::secp256k1::Secp256k1KeyPair; use hermes_encoding_components::traits::decode::CanDecode; use hermes_encoding_components::traits::encode::CanEncode; use hermes_encoding_components::traits::has_encoding::HasEncoding; use hermes_encoding_components::traits::types::encoded::HasEncodedType; +use ibc::core::host::types::path::{ClientStatePath, Path}; use starknet::core::types::Felt; use starknet::macros::selector; use crate::traits::contract::call::CanCallContract; +use crate::traits::proof_signer::HasStarknetProofSigner; use crate::traits::queries::address::CanQueryContractAddress; use crate::traits::types::blob::HasBlobType; use crate::traits::types::method::HasSelectorType; use crate::types::client_id::ClientId; use crate::types::commitment_proof::StarknetCommitmentProof; use crate::types::cosmos::client_state::CometClientState; +use crate::types::membership_proof_signer::MembershipVerifierContainer; +use crate::types::status::StarknetChainStatus; pub struct QueryCometClientState; @@ -84,12 +91,16 @@ where impl ClientStateWithProofsQuerier for QueryCometClientState where - Chain: HasClientIdType + Chain: HasClientIdType + HasHeightType + + CanQueryChainStatus + + HasIbcCommitmentPrefix> + HasCommitmentProofType + CanQueryClientState + + HasStarknetProofSigner + + CanRaiseAsyncError + HasAsyncErrorType, - Counterparty: HasClientStateType + HasHeightType, + Counterparty: HasClientStateType + HasHeightType, { async fn query_client_state_with_proofs( chain: &Chain, @@ -97,14 +108,37 @@ where client_id: &Chain::ClientId, query_height: &Chain::Height, ) -> Result<(Counterparty::ClientState, Chain::CommitmentProof), Chain::Error> { - // FIXME: properly fetch consensus state with proofs + // FIXME: properly fetch client state with proofs let client_state = chain .query_client_state(tag, client_id, query_height) .await?; + let chain_status = chain.query_chain_status().await?; + + // FIXME: CometClientState can't be encoded to protobuf + let protobuf_encoded_client_state = Vec::new(); + // let protobuf_encoded_client_state = Counterparty::default_encoding() + // .encode(&client_state) + // .map_err(Chain::raise_error)?; + + let unsigned_membership_proof_bytes = MembershipVerifierContainer { + state_root: chain_status.block_hash.to_bytes_be().to_vec(), + prefix: chain.ibc_commitment_prefix().clone(), + path: Path::ClientState(ClientStatePath::new(client_id.clone())) + .to_string() + .into(), + value: Some(protobuf_encoded_client_state), + } + .canonical_bytes(); + + let signed_bytes = chain + .proof_signer() + .sign(&unsigned_membership_proof_bytes) + .map_err(Chain::raise_error)?; + let proof = StarknetCommitmentProof { - proof_height: *query_height, - proof_bytes: Vec::new(), + proof_height: chain_status.height, + proof_bytes: signed_bytes, }; Ok((client_state, proof)) diff --git a/relayer/crates/starknet-chain-components/src/impls/queries/connection_end.rs b/relayer/crates/starknet-chain-components/src/impls/queries/connection_end.rs index f3b72411..1bafc08f 100644 --- a/relayer/crates/starknet-chain-components/src/impls/queries/connection_end.rs +++ b/relayer/crates/starknet-chain-components/src/impls/queries/connection_end.rs @@ -3,7 +3,8 @@ use core::marker::PhantomData; use cgp::prelude::*; use hermes_cairo_encoding_components::strategy::ViaCairo; use hermes_cairo_encoding_components::types::as_felt::AsFelt; -use hermes_chain_components::traits::queries::chain_status::CanQueryChainHeight; +use hermes_chain_components::traits::commitment_prefix::HasIbcCommitmentPrefix; +use hermes_chain_components::traits::queries::chain_status::CanQueryChainStatus; use hermes_chain_components::traits::queries::connection_end::{ ConnectionEndQuerier, ConnectionEndWithProofsQuerier, }; @@ -11,19 +12,25 @@ use hermes_chain_components::traits::types::connection::HasConnectionEndType; use hermes_chain_components::traits::types::height::HasHeightType; use hermes_chain_components::traits::types::ibc::HasConnectionIdType; use hermes_chain_components::traits::types::proof::HasCommitmentProofType; +use hermes_cosmos_chain_components::types::key_types::secp256k1::Secp256k1KeyPair; use hermes_encoding_components::traits::decode::CanDecode; use hermes_encoding_components::traits::encode::CanEncode; use hermes_encoding_components::traits::has_encoding::HasEncoding; use hermes_encoding_components::traits::types::encoded::HasEncodedType; +use ibc::core::host::types::path::{ConnectionPath, Path}; +use ibc_proto::Protobuf; use starknet::core::types::Felt; use starknet::macros::selector; use crate::traits::contract::call::CanCallContract; +use crate::traits::proof_signer::HasStarknetProofSigner; use crate::traits::queries::address::CanQueryContractAddress; use crate::traits::types::blob::HasBlobType; use crate::traits::types::method::HasSelectorType; use crate::types::commitment_proof::StarknetCommitmentProof; use crate::types::connection_id::{ConnectionEnd, ConnectionId}; +use crate::types::membership_proof_signer::MembershipVerifierContainer; +use crate::types::status::StarknetChainStatus; pub struct QueryConnectionEndFromStarknet; @@ -68,7 +75,8 @@ impl ConnectionEndWithProofsQuerier - + CanQueryChainHeight + + CanQueryChainStatus + + HasIbcCommitmentPrefix> + HasCommitmentProofType + HasConnectionIdType + HasConnectionEndType @@ -77,6 +85,8 @@ where + CanQueryContractAddress + HasEncoding + CanCallContract + + HasStarknetProofSigner + + CanRaiseAsyncError + CanRaiseAsyncError, Encoding: CanEncode + CanDecode @@ -99,15 +109,30 @@ where .call_contract(&contract_address, &selector!("connection_end"), &calldata) .await?; - // TODO(rano): how to get the proof? + let connection_end = encoding.decode(&output).map_err(Chain::raise_error)?; + + let chain_status = chain.query_chain_status().await?; + + let unsigned_membership_proof_bytes = MembershipVerifierContainer { + state_root: chain_status.block_hash.to_bytes_be().to_vec(), + prefix: chain.ibc_commitment_prefix().clone(), + path: Path::Connection(ConnectionPath::new(connection_id)) + .to_string() + .into(), + value: Some(connection_end.clone().encode_vec()), + } + .canonical_bytes(); + + let signed_bytes = chain + .proof_signer() + .sign(&unsigned_membership_proof_bytes) + .map_err(Chain::raise_error)?; + let dummy_proof = StarknetCommitmentProof { - proof_height: chain.query_chain_height().await?, - proof_bytes: vec![0x1], + proof_height: chain_status.height, + proof_bytes: signed_bytes, }; - Ok(( - encoding.decode(&output).map_err(Chain::raise_error)?, - dummy_proof, - )) + Ok((connection_end, dummy_proof)) } } 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 ca4b4641..dda2e17b 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 @@ -3,6 +3,8 @@ use core::marker::PhantomData; use cgp::prelude::*; use hermes_cairo_encoding_components::strategy::ViaCairo; use hermes_cairo_encoding_components::types::as_felt::AsFelt; +use hermes_chain_components::traits::commitment_prefix::HasIbcCommitmentPrefix; +use hermes_chain_components::traits::queries::chain_status::CanQueryChainStatus; use hermes_chain_components::traits::queries::consensus_state::{ CanQueryConsensusState, ConsensusStateQuerier, ConsensusStateWithProofsQuerier, }; @@ -10,14 +12,18 @@ use hermes_chain_components::traits::types::consensus_state::HasConsensusStateTy use hermes_chain_components::traits::types::height::{HasHeightFields, HasHeightType}; use hermes_chain_components::traits::types::ibc::HasClientIdType; use hermes_chain_components::traits::types::proof::HasCommitmentProofType; +use hermes_cosmos_chain_components::types::key_types::secp256k1::Secp256k1KeyPair; use hermes_encoding_components::traits::decode::CanDecode; use hermes_encoding_components::traits::encode::CanEncode; use hermes_encoding_components::traits::has_encoding::HasEncoding; use hermes_encoding_components::traits::types::encoded::HasEncodedType; +use ibc::core::client::types::Height as IbcHeight; +use ibc::core::host::types::path::{ClientConsensusStatePath, Path}; use starknet::core::types::Felt; use starknet::macros::selector; use crate::traits::contract::call::CanCallContract; +use crate::traits::proof_signer::HasStarknetProofSigner; use crate::traits::queries::address::CanQueryContractAddress; use crate::traits::types::blob::HasBlobType; use crate::traits::types::method::HasSelectorType; @@ -25,7 +31,8 @@ use crate::types::client_id::ClientId; use crate::types::commitment_proof::StarknetCommitmentProof; use crate::types::cosmos::consensus_state::CometConsensusState; use crate::types::cosmos::height::Height; - +use crate::types::membership_proof_signer::MembershipVerifierContainer; +use crate::types::status::StarknetChainStatus; #[derive(Debug)] pub struct ConsensusStateNotFound { pub client_id: ClientId, @@ -109,12 +116,17 @@ where impl ConsensusStateWithProofsQuerier for QueryCometConsensusState where - Chain: HasClientIdType + Chain: HasClientIdType + HasHeightType + + CanQueryChainStatus + + HasIbcCommitmentPrefix> + HasCommitmentProofType + CanQueryConsensusState + + HasStarknetProofSigner + + CanRaiseAsyncError + HasAsyncErrorType, - Counterparty: HasConsensusStateType + HasHeightType, + Counterparty: HasConsensusStateType + + HasHeightType, { async fn query_consensus_state_with_proofs( chain: &Chain, @@ -128,9 +140,36 @@ where .query_consensus_state(tag, client_id, consensus_height, query_height) .await?; + let chain_status = chain.query_chain_status().await?; + + // FIXME: CometConsensusState can't be encoded to protobuf + let protobuf_encoded_consensus_state = Vec::new(); + // let protobuf_encoded_consensus_state = Counterparty::default_encoding() + // .encode(&consensus_state) + // .map_err(Chain::raise_error)?; + + let unsigned_membership_proof_bytes = MembershipVerifierContainer { + state_root: chain_status.block_hash.to_bytes_be().to_vec(), + prefix: chain.ibc_commitment_prefix().clone(), + path: Path::ClientConsensusState(ClientConsensusStatePath::new( + client_id.clone(), + consensus_height.revision_number(), + consensus_height.revision_height(), + )) + .to_string() + .into(), + value: Some(protobuf_encoded_consensus_state), + } + .canonical_bytes(); + + let signed_bytes = chain + .proof_signer() + .sign(&unsigned_membership_proof_bytes) + .map_err(Chain::raise_error)?; + let proof = StarknetCommitmentProof { - proof_height: *query_height, - proof_bytes: Vec::new(), + proof_height: chain_status.height, + proof_bytes: signed_bytes, }; Ok((consensus_state, proof)) diff --git a/relayer/crates/starknet-chain-components/src/impls/queries/packet_commitment.rs b/relayer/crates/starknet-chain-components/src/impls/queries/packet_commitment.rs index 3df4e6d3..91568902 100644 --- a/relayer/crates/starknet-chain-components/src/impls/queries/packet_commitment.rs +++ b/relayer/crates/starknet-chain-components/src/impls/queries/packet_commitment.rs @@ -3,6 +3,8 @@ use core::marker::PhantomData; use cgp::prelude::*; use hermes_cairo_encoding_components::strategy::ViaCairo; use hermes_cairo_encoding_components::types::as_felt::AsFelt; +use hermes_chain_components::traits::commitment_prefix::HasIbcCommitmentPrefix; +use hermes_chain_components::traits::queries::chain_status::CanQueryChainStatus; use hermes_chain_components::traits::queries::packet_commitment::PacketCommitmentQuerier; use hermes_chain_components::traits::types::height::HasHeightType; use hermes_chain_components::traits::types::ibc::{ @@ -10,22 +12,27 @@ use hermes_chain_components::traits::types::ibc::{ }; use hermes_chain_components::traits::types::packets::receive::HasPacketCommitmentType; use hermes_chain_components::traits::types::proof::HasCommitmentProofType; +use hermes_cosmos_chain_components::types::key_types::secp256k1::Secp256k1KeyPair; use hermes_encoding_components::traits::decode::CanDecode; use hermes_encoding_components::traits::encode::CanEncode; use hermes_encoding_components::traits::has_encoding::HasEncoding; use hermes_encoding_components::traits::types::encoded::HasEncodedType; use ibc::core::host::types::identifiers::{PortId as IbcPortId, Sequence as IbcSequence}; +use ibc::core::host::types::path::{CommitmentPath, Path}; use starknet::core::types::Felt; use starknet::macros::selector; use crate::traits::contract::call::CanCallContract; +use crate::traits::proof_signer::HasStarknetProofSigner; use crate::traits::queries::address::CanQueryContractAddress; use crate::traits::types::blob::HasBlobType; use crate::traits::types::method::HasSelectorType; use crate::types::channel_id::ChannelId; use crate::types::commitment_proof::StarknetCommitmentProof; +use crate::types::membership_proof_signer::MembershipVerifierContainer; use crate::types::messages::ibc::channel::PortId as CairoPortId; use crate::types::messages::ibc::packet::Sequence; +use crate::types::status::StarknetChainStatus; pub struct QueryStarknetPacketCommitment; @@ -33,6 +40,8 @@ impl PacketCommitmentQuerier for QueryStarknetPacketCommitment where Chain: HasHeightType + + CanQueryChainStatus + + HasIbcCommitmentPrefix> + HasChannelIdType + HasPortIdType + HasSequenceType @@ -43,6 +52,8 @@ where + CanQueryContractAddress + HasEncoding + CanCallContract + + HasStarknetProofSigner + + CanRaiseAsyncError + CanRaiseAsyncError, Encoding: CanEncode + CanDecode @@ -53,7 +64,7 @@ where channel_id: &ChannelId, port_id: &IbcPortId, sequence: &IbcSequence, - height: &u64, + _height: &u64, ) -> Result<(Vec, StarknetCommitmentProof), Chain::Error> { let encoding = chain.encoding(); @@ -79,12 +90,6 @@ where ) .await?; - // TODO(rano): how to get the proof? - let dummy_proof = StarknetCommitmentProof { - proof_height: *height, - proof_bytes: vec![0x1], - }; - let product![commitment,] = encoding.decode(&output).map_err(Chain::raise_error)?; let commitment_bytes = commitment @@ -93,6 +98,28 @@ where .flat_map(|felt| felt.to_be_bytes()) .collect::>(); + let chain_status = chain.query_chain_status().await?; + + let unsigned_membership_proof_bytes = MembershipVerifierContainer { + state_root: chain_status.block_hash.to_bytes_be().to_vec(), + prefix: chain.ibc_commitment_prefix().clone(), + path: Path::Commitment(CommitmentPath::new(port_id, channel_id, *sequence)) + .to_string() + .into(), + value: Some(commitment_bytes.clone()), + } + .canonical_bytes(); + + let signed_bytes = chain + .proof_signer() + .sign(&unsigned_membership_proof_bytes) + .map_err(Chain::raise_error)?; + + let dummy_proof = StarknetCommitmentProof { + proof_height: chain_status.height, + proof_bytes: signed_bytes, + }; + Ok((commitment_bytes, dummy_proof)) } } diff --git a/relayer/crates/starknet-chain-components/src/impls/queries/packet_receipt.rs b/relayer/crates/starknet-chain-components/src/impls/queries/packet_receipt.rs index 826b796b..ac1c4a93 100644 --- a/relayer/crates/starknet-chain-components/src/impls/queries/packet_receipt.rs +++ b/relayer/crates/starknet-chain-components/src/impls/queries/packet_receipt.rs @@ -3,6 +3,8 @@ use core::marker::PhantomData; use cgp::prelude::*; use hermes_cairo_encoding_components::strategy::ViaCairo; use hermes_cairo_encoding_components::types::as_felt::AsFelt; +use hermes_chain_components::traits::commitment_prefix::HasIbcCommitmentPrefix; +use hermes_chain_components::traits::queries::chain_status::CanQueryChainStatus; use hermes_chain_components::traits::queries::packet_receipt::PacketReceiptQuerier; use hermes_chain_components::traits::types::height::HasHeightType; use hermes_chain_components::traits::types::ibc::{ @@ -10,22 +12,27 @@ use hermes_chain_components::traits::types::ibc::{ }; use hermes_chain_components::traits::types::packets::timeout::HasPacketReceiptType; use hermes_chain_components::traits::types::proof::HasCommitmentProofType; +use hermes_cosmos_chain_components::types::key_types::secp256k1::Secp256k1KeyPair; use hermes_encoding_components::traits::decode::CanDecode; use hermes_encoding_components::traits::encode::CanEncode; use hermes_encoding_components::traits::has_encoding::HasEncoding; use hermes_encoding_components::traits::types::encoded::HasEncodedType; use ibc::core::host::types::identifiers::{PortId as IbcPortId, Sequence as IbcSequence}; +use ibc::core::host::types::path::{Path, ReceiptPath}; use starknet::core::types::Felt; use starknet::macros::selector; use crate::traits::contract::call::CanCallContract; +use crate::traits::proof_signer::HasStarknetProofSigner; use crate::traits::queries::address::CanQueryContractAddress; use crate::traits::types::blob::HasBlobType; use crate::traits::types::method::HasSelectorType; use crate::types::channel_id::ChannelId; use crate::types::commitment_proof::StarknetCommitmentProof; +use crate::types::membership_proof_signer::MembershipVerifierContainer; use crate::types::messages::ibc::channel::PortId as CairoPortId; use crate::types::messages::ibc::packet::Sequence; +use crate::types::status::StarknetChainStatus; pub struct QueryStarknetPacketReceipt; @@ -33,6 +40,8 @@ impl PacketReceiptQuerier for QueryStarknetPacketReceipt where Chain: HasHeightType + + CanQueryChainStatus + + HasIbcCommitmentPrefix> + HasChannelIdType + HasPortIdType + HasPacketReceiptType> @@ -42,6 +51,9 @@ where + CanQueryContractAddress + HasEncoding + CanCallContract + + HasStarknetProofSigner + + CanRaiseAsyncError + + CanRaiseAsyncError<&'static str> + CanRaiseAsyncError, Counterparty: HasSequenceType, Encoding: CanEncode @@ -53,7 +65,7 @@ where channel_id: &ChannelId, port_id: &IbcPortId, sequence: &IbcSequence, - height: &u64, + _height: &u64, ) -> Result<(Vec, StarknetCommitmentProof), Chain::Error> { let encoding = chain.encoding(); @@ -75,24 +87,36 @@ where .call_contract(&contract_address, &selector!("packet_receipt"), &calldata) .await?; - // TODO(rano): how to get the proof? - let dummy_proof = StarknetCommitmentProof { - proof_height: *height, - proof_bytes: vec![0x1], - }; - let receipt_status = encoding.decode(&output).map_err(Chain::raise_error)?; - // TODO(rano): are these bytes correct? - let receipt_bytes = if receipt_status { - // 0x01 -> "AQ==" - br#"{"result":"AQ=="}"# - } else { - // 0x00 -> "AA==" - br#"{"result":"AA=="}"# + if receipt_status { + return Err(Chain::raise_error( + "Packet is received. No non-membership proof.", + )); + } + + let chain_status = chain.query_chain_status().await?; + + let unsigned_membership_proof_bytes = MembershipVerifierContainer { + state_root: chain_status.block_hash.to_bytes_be().to_vec(), + prefix: chain.ibc_commitment_prefix().clone(), + path: Path::Receipt(ReceiptPath::new(port_id, channel_id, *sequence)) + .to_string() + .into(), + value: None, } - .to_vec(); + .canonical_bytes(); + + let signed_bytes = chain + .proof_signer() + .sign(&unsigned_membership_proof_bytes) + .map_err(Chain::raise_error)?; + + let dummy_proof = StarknetCommitmentProof { + proof_height: chain_status.height, + proof_bytes: signed_bytes, + }; - Ok((receipt_bytes, dummy_proof)) + Ok((vec![], dummy_proof)) } } diff --git a/relayer/crates/starknet-chain-components/src/impls/queries/packet_received.rs b/relayer/crates/starknet-chain-components/src/impls/queries/packet_received.rs index 256d65a1..ac650f77 100644 --- a/relayer/crates/starknet-chain-components/src/impls/queries/packet_received.rs +++ b/relayer/crates/starknet-chain-components/src/impls/queries/packet_received.rs @@ -73,11 +73,7 @@ where .map_err(Chain::raise_error)?; let output = chain - .call_contract( - &contract_address, - &selector!("is_packet_received"), - &calldata, - ) + .call_contract(&contract_address, &selector!("packet_receipt"), &calldata) .await?; let is_received = encoding.decode(&output).map_err(Chain::raise_error)?; diff --git a/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/channel_message.rs b/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/channel_message.rs index 94eb22d0..158c549f 100644 --- a/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/channel_message.rs +++ b/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/channel_message.rs @@ -40,7 +40,6 @@ where + HasPortIdType + CanRaiseAsyncError + CanRaiseAsyncError - + CanRaiseAsyncError<&'static str> + CanRaiseAsyncError + CanRaiseAsyncError, Counterparty: HasChannelIdType @@ -118,15 +117,13 @@ where let update_height = CosmosHeight::new(0, counterparty_payload.update_height).map_err(Chain::raise_error)?; - let proof_try = counterparty_payload.proof_try.proof_bytes; - let message = CosmosChannelOpenAckMessage { port_id: port_id.to_string(), channel_id: channel_id.to_string(), counterparty_channel_id: counterparty_channel_id.to_string(), counterparty_version: counterparty_payload.channel_end.version.to_string(), update_height, - proof_try, + proof_try: counterparty_payload.proof_try.proof_bytes, }; Ok(message.to_cosmos_message()) diff --git a/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/connection_message.rs b/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/connection_message.rs index 1a5ab5e9..9243ee10 100644 --- a/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/connection_message.rs +++ b/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/connection_message.rs @@ -6,12 +6,14 @@ use hermes_chain_components::traits::message_builders::connection_handshake::{ ConnectionOpenAckMessageBuilder, ConnectionOpenConfirmMessageBuilder, ConnectionOpenInitMessageBuilder, ConnectionOpenTryMessageBuilder, }; +use hermes_chain_components::traits::queries::chain_status::CanQueryChainHeight; use hermes_chain_components::traits::types::client_state::HasClientStateType; use hermes_chain_components::traits::types::connection::{ HasConnectionEndType, HasConnectionOpenAckPayloadType, HasConnectionOpenConfirmPayloadType, HasConnectionOpenInitPayloadType, HasConnectionOpenTryPayloadType, HasInitConnectionOptionsType, }; +use hermes_chain_components::traits::types::consensus_state::HasConsensusStateType; use hermes_chain_components::traits::types::height::HasHeightType; use hermes_chain_components::traits::types::ibc::{HasClientIdType, HasConnectionIdType}; use hermes_chain_components::traits::types::message::HasMessageType; @@ -29,6 +31,7 @@ use hermes_cosmos_chain_components::types::messages::connection::open_try::Cosmo use ibc::core::client::types::error::ClientError; use ibc::core::client::types::Height as CosmosHeight; use ibc::core::connection::types::version::Version as CosmosConnectionVersion; +use ibc::core::connection::types::ConnectionEnd; use ibc::core::host::types::identifiers::{ ClientId as CosmosClientId, ConnectionId as CosmosConnectionId, }; @@ -38,6 +41,7 @@ use prost_types::Any; use crate::types::client_id::ClientId as StarknetClientId; use crate::types::commitment_proof::StarknetCommitmentProof; use crate::types::connection_id::ConnectionId as StarknetConnectionId; +use crate::types::consensus_state::WasmStarknetConsensusState; use crate::types::cosmos::client_state::CometClientState; pub struct BuildStarknetToCosmosConnectionHandshake; @@ -90,7 +94,8 @@ where > + HasClientIdType + HasConnectionIdType + HasHeightType - + HasConnectionEndType + + HasConsensusStateType + + HasConnectionEndType + HasCommitmentPrefixType> + HasCommitmentProofType, { @@ -109,10 +114,8 @@ where // TODO(rano): delay period let delay_period = Duration::from_secs(0); - // TODO(rano): apparently update height is set to zero let update_height = - CosmosHeight::new(0, core::cmp::max(1, counterparty_payload.update_height)) - .map_err(Chain::raise_error)?; + CosmosHeight::new(0, counterparty_payload.update_height).map_err(Chain::raise_error)?; let message = CosmosConnectionOpenTryMessage { client_id: client_id.to_string(), @@ -127,11 +130,10 @@ where delay_period, update_height, proof_init: counterparty_payload.proof_init.proof_bytes, - // TODO(rano): counterparty_payload has empty proofs? - // proof_client: counterparty_payload.proof_client.proof_bytes, - proof_client: vec![0x1], - // proof_consensus: counterparty_payload.proof_consensus.proof_bytes, - proof_consensus: vec![0x1], + // client and consensus proofs are passed but ignored + // cosmos/ibc-go#7129 + proof_client: counterparty_payload.proof_client.proof_bytes, + proof_consensus: counterparty_payload.proof_consensus.proof_bytes, proof_consensus_height: counterparty_payload.proof_consensus_height, }; @@ -179,11 +181,10 @@ where }, update_height, proof_try: counterparty_payload.proof_try.proof_bytes, - // TODO(rano): counterparty_payload has empty proofs? - // proof_client: counterparty_payload.proof_client.proof_bytes, - proof_client: vec![0x1], - // proof_consensus: counterparty_payload.proof_consensus.proof_bytes, - proof_consensus: vec![0x1], + // client and consensus proofs are passed but ignored + // cosmos/ibc-go#7129 + proof_client: counterparty_payload.proof_client.proof_bytes, + proof_consensus: counterparty_payload.proof_consensus.proof_bytes, proof_consensus_height: counterparty_payload.proof_consensus_height, }; @@ -195,6 +196,7 @@ impl ConnectionOpenConfirmMessageBuilder + + CanQueryChainHeight + HasConnectionIdType + CanRaiseAsyncError, Counterparty: HasConnectionOpenConfirmPayloadType< diff --git a/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/create_client_message.rs b/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/create_client_message.rs index 3a33e554..596b63ed 100644 --- a/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/create_client_message.rs +++ b/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/create_client_message.rs @@ -1,6 +1,5 @@ use cgp::prelude::*; use hermes_cosmos_chain_components::traits::message::{CosmosMessage, ToCosmosMessage}; -use hermes_cosmos_chain_components::types::key_types::secp256k1::Secp256k1KeyPair; use hermes_cosmos_chain_components::types::messages::client::create::CosmosCreateClientMessage; use hermes_encoding_components::traits::convert::CanConvert; use hermes_encoding_components::traits::has_encoding::HasDefaultEncoding; @@ -12,7 +11,6 @@ use hermes_relayer_components::chain::traits::types::create_client::{ HasCreateClientMessageOptionsType, HasCreateClientPayloadType, }; use hermes_relayer_components::chain::traits::types::message::HasMessageType; -use hermes_relayer_components::transaction::traits::default_signer::HasDefaultSigner; use ibc_client_starknet_types::StarknetClientState; use prost_types::Any; @@ -27,7 +25,6 @@ impl CreateClientMessageBuilder + HasCreateClientMessageOptionsType - + HasDefaultSigner + CanRaiseAsyncError, Counterparty: HasCreateClientPayloadType + HasClientStateType @@ -38,7 +35,7 @@ where + CanConvert, { async fn build_create_client_message( - chain: &Chain, + _chain: &Chain, _options: &Chain::CreateClientMessageOptions, payload: StarknetCreateClientPayload, ) -> Result { @@ -47,7 +44,7 @@ where let starknet_client_state = StarknetClientState { latest_height: payload.latest_height, chain_id: payload.chain_id, - pub_key: chain.get_default_signer().public_key.serialize().to_vec(), + pub_key: payload.proof_signer_pub_key, }; let client_state = WasmStarknetClientState { diff --git a/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/update_client_message.rs b/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/update_client_message.rs index ae69b1a0..dee1342a 100644 --- a/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/update_client_message.rs +++ b/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/update_client_message.rs @@ -1,6 +1,5 @@ use cgp::prelude::*; use hermes_cosmos_chain_components::traits::message::{CosmosMessage, ToCosmosMessage}; -use hermes_cosmos_chain_components::types::key_types::secp256k1::Secp256k1KeyPair; use hermes_cosmos_chain_components::types::messages::client::update::CosmosUpdateClientMessage; use hermes_encoding_components::traits::convert::CanConvert; use hermes_encoding_components::traits::encode::CanEncode; @@ -11,7 +10,6 @@ use hermes_relayer_components::chain::traits::message_builders::update_client::U use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes; use hermes_relayer_components::chain::traits::types::message::HasMessageType; use hermes_relayer_components::chain::traits::types::update_client::HasUpdateClientPayloadType; -use hermes_relayer_components::transaction::traits::default_signer::HasDefaultSigner; use ibc::core::host::types::identifiers::ClientId; use ibc_client_starknet_types::header::{SignedStarknetHeader, StarknetHeader}; use prost_types::Any; @@ -25,9 +23,7 @@ impl UpdateClientMessageBuilder + HasMessageType - + HasDefaultSigner - + CanRaiseAsyncError - + CanRaiseAsyncError, + + CanRaiseAsyncError, Counterparty: HasUpdateClientPayloadType + HasDefaultEncoding, Encoding: Async @@ -35,7 +31,7 @@ where + CanConvert, { async fn build_update_client_message( - chain: &Chain, + _chain: &Chain, client_id: &Chain::ClientId, payload: StarknetUpdateClientPayload, ) -> Result, Chain::Error> { @@ -45,13 +41,9 @@ where .encode(&payload.header) .map_err(Chain::raise_error)?; - let signer = chain.get_default_signer(); - - let signature = signer.sign(&encoded_header).map_err(Chain::raise_error)?; - let signed_header = SignedStarknetHeader { header: encoded_header.clone(), - signature, + signature: payload.signature, }; let signed_header_any: Any = encoding diff --git a/relayer/crates/starknet-chain-components/src/traits/mod.rs b/relayer/crates/starknet-chain-components/src/traits/mod.rs index 31896d3b..b2cd310b 100644 --- a/relayer/crates/starknet-chain-components/src/traits/mod.rs +++ b/relayer/crates/starknet-chain-components/src/traits/mod.rs @@ -2,6 +2,7 @@ pub mod account; pub mod client; pub mod contract; pub mod messages; +pub mod proof_signer; pub mod provider; pub mod queries; pub mod transfer; diff --git a/relayer/crates/starknet-chain-components/src/traits/proof_signer.rs b/relayer/crates/starknet-chain-components/src/traits/proof_signer.rs new file mode 100644 index 00000000..0b24f8b1 --- /dev/null +++ b/relayer/crates/starknet-chain-components/src/traits/proof_signer.rs @@ -0,0 +1,29 @@ +use cgp::prelude::*; + +#[cgp_component { + name: StarknetProofSignerTypeComponent, + provider: ProvideStarknetProofSignerType, + context: Chain, +}] +pub trait HasStarknetProofSignerType: Async { + type ProofSigner: Async; +} + +#[cgp_component { + name: StarknetProofSignerGetterComponent, + provider: StarknetProofSignerGetter, + context: Chain, +}] +pub trait HasStarknetProofSigner: HasStarknetProofSignerType { + fn proof_signer(&self) -> &Self::ProofSigner; +} + +pub trait CanRaiseProofSignerErrors: + HasStarknetProofSignerType + CanRaiseAsyncError<&'static str> +{ +} + +impl CanRaiseProofSignerErrors for Chain where + Chain: HasStarknetProofSignerType + CanRaiseAsyncError<&'static str> +{ +} diff --git a/relayer/crates/starknet-chain-components/src/types/membership_proof_signer.rs b/relayer/crates/starknet-chain-components/src/types/membership_proof_signer.rs new file mode 100644 index 00000000..9ef29d74 --- /dev/null +++ b/relayer/crates/starknet-chain-components/src/types/membership_proof_signer.rs @@ -0,0 +1,25 @@ +#[derive(Debug)] +pub struct MembershipVerifierContainer { + pub state_root: Vec, + pub prefix: Vec, + pub path: Vec, + pub value: Option>, +} + +impl MembershipVerifierContainer { + pub fn canonical_bytes(self) -> Vec { + let mut bytes = Vec::new(); + let encode_bytes = |mut data: Vec, output: &mut Vec| { + let len = data.len() as u64; + output.extend(len.to_be_bytes()); + output.append(&mut data); + }; + encode_bytes(self.state_root, &mut bytes); + encode_bytes(self.prefix, &mut bytes); + encode_bytes(self.path, &mut bytes); + if let Some(v) = self.value { + encode_bytes(v, &mut bytes); + } + bytes + } +} diff --git a/relayer/crates/starknet-chain-components/src/types/mod.rs b/relayer/crates/starknet-chain-components/src/types/mod.rs index 008bd5a2..9bd58008 100644 --- a/relayer/crates/starknet-chain-components/src/types/mod.rs +++ b/relayer/crates/starknet-chain-components/src/types/mod.rs @@ -8,6 +8,7 @@ pub mod consensus_state; pub mod cosmos; pub mod event; pub mod events; +pub mod membership_proof_signer; pub mod message_response; pub mod message_responses; pub mod messages; diff --git a/relayer/crates/starknet-chain-components/src/types/payloads/client.rs b/relayer/crates/starknet-chain-components/src/types/payloads/client.rs index c5ac4c7f..3bfd89c9 100644 --- a/relayer/crates/starknet-chain-components/src/types/payloads/client.rs +++ b/relayer/crates/starknet-chain-components/src/types/payloads/client.rs @@ -11,6 +11,9 @@ pub struct StarknetCreateClientPayload { pub chain_id: ChainId, pub client_state_wasm_code_hash: Vec, pub consensus_state: WasmStarknetConsensusState, + + // FIXME: only needed for demo2 + pub proof_signer_pub_key: Vec, } pub struct StarknetCreateClientPayloadOptions { @@ -19,4 +22,7 @@ pub struct StarknetCreateClientPayloadOptions { pub struct StarknetUpdateClientPayload { pub header: StarknetHeader, + + // FIXME: only needed for demo2 + pub signature: Vec, } diff --git a/relayer/crates/starknet-chain-context/src/contexts/chain.rs b/relayer/crates/starknet-chain-context/src/contexts/chain.rs index 06d81a7d..dc9aa8fc 100644 --- a/relayer/crates/starknet-chain-context/src/contexts/chain.rs +++ b/relayer/crates/starknet-chain-context/src/contexts/chain.rs @@ -14,6 +14,7 @@ use hermes_chain_type_components::traits::types::height::HasHeightType; use hermes_chain_type_components::traits::types::message_response::HasMessageResponseType; use hermes_cosmos_chain_components::components::delegate::DelegateCosmosChainComponents; use hermes_cosmos_chain_components::types::connection::CosmosInitConnectionOptions; +use hermes_cosmos_chain_components::types::key_types::secp256k1::Secp256k1KeyPair; use hermes_cosmos_relayer::contexts::chain::CosmosChain; use hermes_encoding_components::traits::has_encoding::{ DefaultEncodingGetter, EncodingGetter, HasDefaultEncoding, ProvideEncodingType, @@ -131,6 +132,7 @@ use hermes_starknet_chain_components::components::chain::{ }; use hermes_starknet_chain_components::components::starknet_to_cosmos::StarknetToCosmosComponents; use hermes_starknet_chain_components::impls::account::GetStarknetAccountField; +use hermes_starknet_chain_components::impls::proof_signer::GetStarknetProofSignerField; use hermes_starknet_chain_components::impls::provider::GetStarknetProviderField; use hermes_starknet_chain_components::impls::subscription::CanCreateStarknetEventSubscription; use hermes_starknet_chain_components::impls::types::events::StarknetCreateClientEvent; @@ -142,6 +144,9 @@ use hermes_starknet_chain_components::traits::contract::call::CanCallContract; use hermes_starknet_chain_components::traits::contract::declare::CanDeclareContract; use hermes_starknet_chain_components::traits::contract::deploy::CanDeployContract; use hermes_starknet_chain_components::traits::contract::invoke::CanInvokeContract; +use hermes_starknet_chain_components::traits::proof_signer::{ + HasStarknetProofSigner, StarknetProofSignerGetterComponent, StarknetProofSignerTypeComponent, +}; use hermes_starknet_chain_components::traits::provider::{ HasStarknetProvider, StarknetProviderGetterComponent, StarknetProviderTypeComponent, }; @@ -194,6 +199,8 @@ pub struct StarknetChain { pub ibc_core_contract_address: Option, pub event_encoding: StarknetEventEncoding, pub event_subscription: Option>>, + // FIXME: only needed for demo2 + pub proof_signer: Secp256k1KeyPair, } pub struct StarknetChainContextComponents; @@ -224,6 +231,11 @@ delegate_components! { StarknetAccountGetterComponent, ]: GetStarknetAccountField, + [ + StarknetProofSignerTypeComponent, + StarknetProofSignerGetterComponent, + ]: + GetStarknetProofSignerField, WalletTypeComponent: ProvideStarknetWalletType, } @@ -428,6 +440,7 @@ pub trait CanUseStarknetChain: + HasPacketDstPortId + CanAssertEventualAmount + CanBuildIbcTokenTransferMessage + + HasStarknetProofSigner // TODO(rano): need this to >::ibc_transfer_token // + CanIbcTransferToken { diff --git a/relayer/crates/starknet-integration-tests/Cargo.toml b/relayer/crates/starknet-integration-tests/Cargo.toml index 409fb60d..75f2578a 100644 --- a/relayer/crates/starknet-integration-tests/Cargo.toml +++ b/relayer/crates/starknet-integration-tests/Cargo.toml @@ -46,3 +46,4 @@ prost = { workspace = true } prost-types = { workspace = true } tracing = { workspace = true } flate2 = { workspace = true } +tiny-bip39 = { workspace = true } diff --git a/relayer/crates/starknet-integration-tests/src/contexts/bootstrap.rs b/relayer/crates/starknet-integration-tests/src/contexts/bootstrap.rs index d3593f07..d1908907 100644 --- a/relayer/crates/starknet-integration-tests/src/contexts/bootstrap.rs +++ b/relayer/crates/starknet-integration-tests/src/contexts/bootstrap.rs @@ -7,6 +7,7 @@ use cgp::core::error::{ErrorRaiserComponent, ErrorTypeComponent}; use cgp::core::field::WithField; use cgp::core::types::WithType; use cgp::prelude::*; +use hermes_cosmos_chain_components::types::key_types::secp256k1::Secp256k1KeyPair; use hermes_cosmos_test_components::bootstrap::components::cosmos_sdk::{ ChainGenesisConfigTypeComponent, ChainNodeConfigTypeComponent, }; @@ -139,6 +140,18 @@ impl ChainDriverBuilder for StarknetBootstrapComponents { ExecutionEncoding::New, ); + let proof_signer = Secp256k1KeyPair::from_mnemonic( + bip39::Mnemonic::from_entropy( + &relayer_wallet.signing_key.to_bytes_be(), + bip39::Language::English, + ) + .expect("valid mnemonic") + .phrase(), + &"m/84'/0'/0'/0/0".parse().expect("valid hdpath"), + "strk", + ) + .expect("valid key pair"); + let chain = StarknetChain { runtime: runtime.clone(), chain_id: chain_id.to_string().parse()?, @@ -148,6 +161,7 @@ impl ChainDriverBuilder for StarknetBootstrapComponents { ibc_core_contract_address: None, event_encoding: Default::default(), event_subscription: None, + proof_signer, }; let chain_driver = StarknetChainDriver { diff --git a/relayer/crates/starknet-integration-tests/src/tests/light_client.rs b/relayer/crates/starknet-integration-tests/src/tests/light_client.rs index 7a28fbd6..dc67bda9 100644 --- a/relayer/crates/starknet-integration-tests/src/tests/light_client.rs +++ b/relayer/crates/starknet-integration-tests/src/tests/light_client.rs @@ -13,20 +13,13 @@ use hermes_cosmos_chain_components::impls::connection::connection_handshake_mess use hermes_cosmos_chain_components::traits::message::ToCosmosMessage; use hermes_cosmos_chain_components::types::config::gas::dynamic_gas_config::DynamicGasConfig; use hermes_cosmos_chain_components::types::config::gas::eip_type::EipQueryType; -use hermes_cosmos_chain_components::types::events::channel::CosmosChannelOpenInitEvent; use hermes_cosmos_chain_components::types::events::connection::CosmosConnectionOpenInitEvent; -use hermes_cosmos_chain_components::types::messages::channel::open_ack::CosmosChannelOpenAckMessage; -use hermes_cosmos_chain_components::types::messages::channel::open_init::CosmosChannelOpenInitMessage; -use hermes_cosmos_chain_components::types::messages::connection::open_ack::CosmosConnectionOpenAckMessage; use hermes_cosmos_chain_components::types::messages::connection::open_init::CosmosConnectionOpenInitMessage; 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_relayer::contexts::encoding::CosmosEncoding; -use hermes_encoding_components::traits::convert::CanConvert; use hermes_encoding_components::traits::encode::CanEncode; use hermes_error::types::Error; -use hermes_relayer_components::chain::traits::payload_builders::create_client::CanBuildCreateClientPayload; use hermes_relayer_components::chain::traits::queries::chain_status::{ CanQueryChainHeight, CanQueryChainStatus, }; @@ -48,9 +41,7 @@ use hermes_starknet_chain_context::contexts::encoding::cairo::StarknetCairoEncod use hermes_starknet_relayer::contexts::starknet_to_cosmos_relay::StarknetToCosmosRelay; use hermes_test_components::bootstrap::traits::chain::CanBootstrapChain; use hermes_test_components::chain_driver::traits::types::chain::HasChain; -use ibc::core::channel::types::channel::State; use ibc::core::client::types::Height; -use ibc_proto::ibc::core::channel::v1::{Channel, Counterparty}; use sha2::{Digest, Sha256}; use starknet::accounts::Call; use starknet::macros::{selector, short_string}; @@ -235,8 +226,8 @@ fn test_starknet_light_client() -> Result<(), Error> { ); { - let client_state = - cosmos_chain.query_client_state( + let client_state = cosmos_chain + .query_client_state( PhantomData::, &cosmos_client_id, &cosmos_chain.query_chain_height().await?, @@ -245,8 +236,8 @@ fn test_starknet_light_client() -> Result<(), Error> { let client_height = client_state.client_state.latest_height.revision_height(); - let consensus_state = - cosmos_chain.query_consensus_state( + let consensus_state = cosmos_chain + .query_consensus_state( PhantomData::, &cosmos_client_id, &client_height, @@ -262,16 +253,16 @@ fn test_starknet_light_client() -> Result<(), Error> { } { - let client_state = - starknet_chain.query_client_state( + let client_state = starknet_chain + .query_client_state( PhantomData::, &starknet_client_id, &starknet_chain.query_chain_height().await?, ) .await?; - let consensus_state = - starknet_chain.query_consensus_state( + let consensus_state = starknet_chain + .query_consensus_state( PhantomData::, &starknet_client_id, &Height::new( @@ -284,8 +275,7 @@ fn test_starknet_light_client() -> Result<(), Error> { info!( "initial Cosmos consensus state height {} and root: {:?} on Starknet", - client_state.latest_height.revision_height, - consensus_state.root + client_state.latest_height.revision_height, consensus_state.root ); } @@ -304,8 +294,8 @@ fn test_starknet_light_client() -> Result<(), Error> { .send_target_update_client_messages(DestinationTarget, &starknet_status.height) .await?; - let consensus_state = - cosmos_chain.query_consensus_state( + let consensus_state = cosmos_chain + .query_consensus_state( PhantomData::, &cosmos_client_id, &starknet_status.height, @@ -322,7 +312,7 @@ fn test_starknet_light_client() -> Result<(), Error> { { runtime.sleep(Duration::from_secs(2)).await; - let cosmos_status= cosmos_chain.query_chain_status().await?; + let cosmos_status = cosmos_chain.query_chain_status().await?; info!( "updating Cosmos client to Starknet to height {}", @@ -335,8 +325,8 @@ fn test_starknet_light_client() -> Result<(), Error> { .send_target_update_client_messages(SourceTarget, &cosmos_status.height) .await?; - let consensus_state = - starknet_chain.query_consensus_state( + let consensus_state = starknet_chain + .query_consensus_state( PhantomData::, &starknet_client_id, &cosmos_status.height, @@ -344,17 +334,15 @@ fn test_starknet_light_client() -> Result<(), Error> { ) .await?; - // TODO(rano): add assert info!( "updated Cosmos client to Starknet to height {} and root: {:?}", - cosmos_status.height, - consensus_state.root + cosmos_status.height, consensus_state.root ); } - let cosmos_connection_id = { + let _cosmos_connection_id = { let open_init_message = CosmosConnectionOpenInitMessage { client_id: cosmos_client_id.to_string(), counterparty_client_id: starknet_client_id.to_string(), @@ -363,88 +351,23 @@ fn test_starknet_light_client() -> Result<(), Error> { delay_period: Duration::from_secs(0), }; - let events = cosmos_chain.send_message(open_init_message.to_cosmos_message()).await?; + let events = cosmos_chain + .send_message(open_init_message.to_cosmos_message()) + .await?; - let connection_id = cosmos_chain.try_extract_from_message_response(PhantomData::, &events) + let connection_id = cosmos_chain + .try_extract_from_message_response( + PhantomData::, + &events, + ) .unwrap() - .connection_id - ; + .connection_id; info!("initialized connection on Cosmos: {connection_id}"); connection_id }; - { - // Pretend that we have relayed ConnectionOpenTry to Starknet, and then send ConnectionOpenAck. - - let payload = >::build_create_client_payload(cosmos_chain, &Default::default(), - ).await?; - - let client_state = CosmosEncoding.convert(&payload.client_state)?; - - runtime.sleep(Duration::from_secs(1)).await; - - let open_ack_message = CosmosConnectionOpenAckMessage { - connection_id: cosmos_connection_id.to_string(), - counterparty_connection_id: cosmos_connection_id.to_string(), // TODO: stub - version: default_connection_version(), - client_state, - update_height: Height::new(0, 1).unwrap(), - proof_try: [0; 32].into(), // dummy proofs - proof_client: [0; 32].into(), - proof_consensus: [0; 32].into(), - proof_consensus_height: payload.client_state.latest_height, - }; - - cosmos_chain.send_message(open_ack_message.to_cosmos_message()).await?; - } - - let channel_id = { - let channel = Channel { - state: State::Init as i32, - ordering: 1, - counterparty: Some(Counterparty { - port_id: "11b7f9bfa43d3facae74efa5dfe0030df98273271278291d67c16a4e6cd5f7c".to_string(), // stub application contract on Starknet as port ID - channel_id: "".to_string(), - }), - connection_hops: vec![cosmos_connection_id.to_string()], - version: "ics20-1".into(), - upgrade_sequence: 0, - }; - - let open_init_message = CosmosChannelOpenInitMessage { - port_id: "transfer".into(), - channel, - }; - - let events = cosmos_chain.send_message(open_init_message.to_cosmos_message()).await?; - - let channel_id = cosmos_chain.try_extract_from_message_response(PhantomData::, &events) - .unwrap() - .channel_id - ; - - info!("initialized channel on Cosmos: {channel_id}"); - - channel_id - }; - - { - // Pretend that we have already done ChannelOpenTry on Starknet, and then continue with ChannelOpenAck - - let open_ack_message = CosmosChannelOpenAckMessage { - port_id: "transfer".into(), - channel_id: channel_id.to_string(), - counterparty_channel_id: "63c350000c404581a3385ec7b4324008b2965dd8fc5af768b87329d25e57cfa".into(), // stub channel contract on Starknet as channel ID - counterparty_version: "ics20-1".into(), - update_height: Height::new(0, 1).unwrap(), - proof_try: [0; 32].into(), // dummy proofs - }; - - cosmos_chain.send_message(open_ack_message.to_cosmos_message()).await?; - } - Ok(()) }) } diff --git a/relayer/crates/starknet-integration-tests/src/tests/mod.rs b/relayer/crates/starknet-integration-tests/src/tests/mod.rs index ae131565..d0a7f839 100644 --- a/relayer/crates/starknet-integration-tests/src/tests/mod.rs +++ b/relayer/crates/starknet-integration-tests/src/tests/mod.rs @@ -1,4 +1,5 @@ pub mod erc20; pub mod ics20; pub mod light_client; +pub mod packet_commitment; pub mod update_clients; diff --git a/relayer/crates/starknet-integration-tests/src/tests/packet_commitment.rs b/relayer/crates/starknet-integration-tests/src/tests/packet_commitment.rs new file mode 100644 index 00000000..551404a8 --- /dev/null +++ b/relayer/crates/starknet-integration-tests/src/tests/packet_commitment.rs @@ -0,0 +1,37 @@ +use ibc::core::channel::types::commitment::compute_packet_commitment; +use ibc::core::channel::types::timeout::{TimeoutHeight, TimeoutTimestamp}; +use ibc::core::client::types::Height; +use ibc::primitives::Timestamp; + +#[test] +fn test_cairo_packet_commitment() { + // https://github.com/informalsystems/ibc-starknet/blob/7967c8045ed6b4453030e01d0df12c47c2d77b37/cairo-contracts/packages/apps/src/transfer/types.cairo#L307 + // https://github.com/informalsystems/ibc-starknet/blob/7967c8045ed6b4453030e01d0df12c47c2d77b37/cairo-contracts/packages/core/src/tests/commitment.cairo#L52-L58 + + let timeout_height = TimeoutHeight::At(Height::new(0, 1000).expect("valid height")); + let timeout_timestamp = TimeoutTimestamp::At(Timestamp::from_nanoseconds(1000 * 1_000_000_000)); + + let packet_json_data: &str = + "{\"denom\":\"2087021424722619777119509474943472645767659996348769578120564519014510906823\",\"amount\":\"100\",\"sender\":\"1431520594\",\"receiver\":\"cosmos1wxeyh7zgn4tctjzs0vtqpc6p5cxq5t2muzl7ng\",\"memo\":\"\"}"; + + let expected: Vec = [ + 1561496803, 591083406, 1958596266, 2480824962, 846563094, 2634790765, 145282158, 2139799705, + ] + .to_vec(); + + let actual = compute_packet_commitment( + packet_json_data.as_ref(), + &timeout_height, + &timeout_timestamp, + ) + .into_vec() + .chunks(4) + .map(|chunk| { + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(chunk); + u32::from_be_bytes(bytes) + }) + .collect::>(); + + assert_eq!(expected, actual); +} diff --git a/relayer/crates/starknet-relayer/Cargo.toml b/relayer/crates/starknet-relayer/Cargo.toml index 863a024e..a969749d 100644 --- a/relayer/crates/starknet-relayer/Cargo.toml +++ b/relayer/crates/starknet-relayer/Cargo.toml @@ -30,3 +30,5 @@ eyre = { workspace = true } serde = { workspace = true } url = { workspace = true } futures = { workspace = true } + +tiny-bip39 = { workspace = true } diff --git a/relayer/crates/starknet-relayer/src/contexts/builder.rs b/relayer/crates/starknet-relayer/src/contexts/builder.rs index 9b2098cc..6c12c2e9 100644 --- a/relayer/crates/starknet-relayer/src/contexts/builder.rs +++ b/relayer/crates/starknet-relayer/src/contexts/builder.rs @@ -8,6 +8,7 @@ use cgp::core::field::{Index, WithField}; use cgp::core::types::WithType; use cgp::prelude::*; use eyre::eyre; +use hermes_cosmos_chain_components::types::key_types::secp256k1::Secp256k1KeyPair; use hermes_cosmos_relayer::contexts::build::CosmosBuilder; use hermes_cosmos_relayer::contexts::chain::CosmosChain; use hermes_error::impls::ProvideHermesError; @@ -191,6 +192,22 @@ impl StarknetBuilder { ExecutionEncoding::New, ); + let proof_signer = Secp256k1KeyPair::from_mnemonic( + bip39::Mnemonic::from_entropy( + &self + .starknet_chain_config + .relayer_wallet + .signing_key + .to_bytes_be(), + bip39::Language::English, + ) + .expect("valid mnemonic") + .phrase(), + &"m/84'/0'/0'/0/0".parse().expect("valid hdpath"), + "strk", + ) + .expect("valid key pair"); + let context = StarknetChain { runtime: self.runtime.clone(), chain_id, @@ -200,6 +217,7 @@ impl StarknetBuilder { ibc_core_contract_address: None, event_encoding: Default::default(), event_subscription: None, + proof_signer, }; Ok(context) diff --git a/tools/Cargo.lock b/tools/Cargo.lock index 879a23f3..5b1092e0 100644 --- a/tools/Cargo.lock +++ b/tools/Cargo.lock @@ -2480,6 +2480,7 @@ dependencies = [ "sha2 0.10.8", "starknet", "tendermint-rpc", + "tiny-bip39", "tokio", "toml", "tracing", @@ -2507,6 +2508,7 @@ dependencies = [ "ibc", "serde", "starknet", + "tiny-bip39", "url", ]