diff --git a/light-client/Cargo.lock b/light-client/Cargo.lock index 8e106fce3..17de297ae 100644 --- a/light-client/Cargo.lock +++ b/light-client/Cargo.lock @@ -1139,8 +1139,7 @@ dependencies = [ [[package]] name = "ibc-client-cw" version = "0.56.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9620ac23289491d842beeacd4512feb3e1610ba031bbceec9cffe46e07fb8c" +source = "git+https://github.com/informalsystems/cosmwasm-ibc.git?branch=luca_joss/add-cw-client-extension-trait#9160e505a664aaa430f9c3cdc40e115d6d364ceb" dependencies = [ "cosmwasm-schema", "cosmwasm-std", @@ -1160,6 +1159,7 @@ dependencies = [ "hermes-cosmos-encoding-components", "hermes-encoding-components", "hermes-protobuf-encoding-components", + "ibc-client-cw", "ibc-client-starknet-types", "ibc-core", "prost", diff --git a/light-client/Cargo.toml b/light-client/Cargo.toml index bcba8d965..ebf27c703 100644 --- a/light-client/Cargo.toml +++ b/light-client/Cargo.toml @@ -61,6 +61,8 @@ 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" } + cgp = { git = "https://github.com/contextgeneric/cgp.git" } cgp-core = { git = "https://github.com/contextgeneric/cgp.git" } cgp-extra = { git = "https://github.com/contextgeneric/cgp.git" } diff --git a/light-client/ibc-client-starknet-types/src/client_state.rs b/light-client/ibc-client-starknet-types/src/client_state.rs index 1502c0f51..daafe1a4e 100644 --- a/light-client/ibc-client-starknet-types/src/client_state.rs +++ b/light-client/ibc-client-starknet-types/src/client_state.rs @@ -9,4 +9,5 @@ pub const STARKNET_CLIENT_STATE_TYPE_URL: &str = "/StarknetClientState"; pub struct StarknetClientState { pub latest_height: Height, pub chain_id: ChainId, + pub pub_key: Vec, } diff --git a/light-client/ibc-client-starknet-types/src/encoding/components.rs b/light-client/ibc-client-starknet-types/src/encoding/components.rs index f6f95e4e6..1fdcc2964 100644 --- a/light-client/ibc-client-starknet-types/src/encoding/components.rs +++ b/light-client/ibc-client-starknet-types/src/encoding/components.rs @@ -22,7 +22,9 @@ use ibc_core::primitives::Timestamp; use crate::encoding::impls::client_state::EncodeStarknetClientState; use crate::encoding::impls::consensus_state::EncodeStarknetConsensusState; use crate::encoding::impls::header::{EncodeSignedStarknetHeader, EncodeStarknetHeader}; -use crate::header::{SignedStarknetHeader, StarknetHeader, STARKNET_HEADER_TYPE_URL}; +use crate::header::{ + SignedStarknetHeader, StarknetHeader, SIGNED_STARKNET_HEADER_TYPE_URL, STARKNET_HEADER_TYPE_URL, +}; use crate::{ StarknetClientState, StarknetConsensusState, STARKNET_CLIENT_STATE_TYPE_URL, STARKNET_CONSENSUS_STATE_TYPE_URL, @@ -145,5 +147,5 @@ impl_type_url!( impl_type_url!( StarknetLightClientTypeUrlSchemas, SignedStarknetHeader, - STARKNET_HEADER_TYPE_URL, + SIGNED_STARKNET_HEADER_TYPE_URL, ); diff --git a/light-client/ibc-client-starknet-types/src/encoding/impls/client_state.rs b/light-client/ibc-client-starknet-types/src/encoding/impls/client_state.rs index 7cf266324..5847c2a24 100644 --- a/light-client/ibc-client-starknet-types/src/encoding/impls/client_state.rs +++ b/light-client/ibc-client-starknet-types/src/encoding/impls/client_state.rs @@ -6,6 +6,7 @@ use hermes_encoding_components::impls::encode_mut::field::EncodeField; use hermes_encoding_components::impls::encode_mut::from::DecodeFrom; use hermes_encoding_components::traits::transform::Transformer; use hermes_protobuf_encoding_components::components::{MutDecoderComponent, MutEncoderComponent}; +use hermes_protobuf_encoding_components::impls::encode_mut::proto_field::bytes::EncodeByteField; use hermes_protobuf_encoding_components::impls::encode_mut::proto_field::decode_required::DecodeRequiredProtoField; use hermes_protobuf_encoding_components::impls::encode_mut::proto_field::encode::EncodeLengthDelimitedProtoField; use ibc_core::client::types::Height; @@ -27,26 +28,32 @@ delegate_components! { symbol!("chain_id"), EncodeChainIdField<2>, >, + EncodeField< + symbol!("pub_key"), + EncodeByteField<3>, + >, ]>, MutDecoderComponent: DecodeFrom< Self, CombineEncoders, EncodeChainIdField<2>, + EncodeByteField<3>, ]> >, } } impl Transformer for EncodeStarknetClientState { - type From = Product![Height, ChainId]; + type From = Product![Height, ChainId, Vec]; type To = StarknetClientState; - fn transform(product![latest_height, chain_id]: Self::From) -> Self::To { + fn transform(product![latest_height, chain_id, pub_key]: Self::From) -> Self::To { StarknetClientState { latest_height, chain_id, + pub_key, } } } diff --git a/light-client/ibc-client-starknet-types/src/encoding/impls/header.rs b/light-client/ibc-client-starknet-types/src/encoding/impls/header.rs index 480932da1..f9b7f1b95 100644 --- a/light-client/ibc-client-starknet-types/src/encoding/impls/header.rs +++ b/light-client/ibc-client-starknet-types/src/encoding/impls/header.rs @@ -59,7 +59,7 @@ delegate_components! { CombineEncoders, + EncodeByteField<1>, >, EncodeField< symbol!("signature"), @@ -69,7 +69,7 @@ delegate_components! { MutDecoderComponent: DecodeFrom< Self, CombineEncoders, + EncodeByteField<1>, EncodeByteField<2>, ]> >, @@ -77,7 +77,7 @@ delegate_components! { } impl Transformer for EncodeSignedStarknetHeader { - type From = Product![StarknetHeader, Vec]; + type From = Product![Vec, Vec]; type To = SignedStarknetHeader; diff --git a/light-client/ibc-client-starknet-types/src/header.rs b/light-client/ibc-client-starknet-types/src/header.rs index bae7525cb..72a1e3759 100644 --- a/light-client/ibc-client-starknet-types/src/header.rs +++ b/light-client/ibc-client-starknet-types/src/header.rs @@ -4,6 +4,7 @@ use ibc_core::client::types::Height; use crate::StarknetConsensusState; pub const STARKNET_HEADER_TYPE_URL: &str = "/StarknetHeader"; +pub const SIGNED_STARKNET_HEADER_TYPE_URL: &str = "/SignedStarknetHeader"; #[derive(Debug, Clone, HasField)] pub struct StarknetHeader { @@ -13,6 +14,6 @@ pub struct StarknetHeader { #[derive(Debug, Clone, HasField)] pub struct SignedStarknetHeader { - pub header: StarknetHeader, + pub header: Vec, pub signature: Vec, } diff --git a/light-client/ibc-client-starknet/Cargo.toml b/light-client/ibc-client-starknet/Cargo.toml index 6e58ccdf3..eebd1fea0 100644 --- a/light-client/ibc-client-starknet/Cargo.toml +++ b/light-client/ibc-client-starknet/Cargo.toml @@ -27,6 +27,7 @@ hermes-cosmos-encoding-components = { workspace = true } # ibc dependencies ibc-core = { workspace = true } ibc-client-starknet-types = { workspace = true } +ibc-client-cw = { workspace = true } [features] default = [ "std" ] 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 537064fac..c13c2aa4f 100644 --- a/light-client/ibc-client-starknet/src/client_state/execution.rs +++ b/light-client/ibc-client-starknet/src/client_state/execution.rs @@ -2,7 +2,10 @@ use cgp::core::component::UseContext; use hermes_cosmos_encoding_components::impls::any::ConvertIbcAny; use hermes_encoding_components::impls::convert::ConvertVia; use hermes_encoding_components::traits::convert::Converter; -use ibc_client_starknet_types::header::SignedStarknetHeader; +use hermes_encoding_components::traits::decode::CanDecode; +use hermes_protobuf_encoding_components::types::strategy::ViaProtobuf; +use ibc_client_cw::context::client_ctx::CwClientExecution; +use ibc_client_starknet_types::header::{SignedStarknetHeader, StarknetHeader}; use ibc_client_starknet_types::StarknetClientState as ClientStateType; use ibc_core::client::context::client_state::ClientStateExecution; use ibc_core::client::context::prelude::{ClientStateCommon, ConsensusState}; @@ -18,9 +21,10 @@ use super::ClientState; use crate::encoding::context::StarknetLightClientEncoding; use crate::ConsensusState as StarknetConsensusState; -impl ClientStateExecution for ClientState +impl<'a, E> ClientStateExecution for ClientState where - E: ClientExecutionContext< + E: CwClientExecution< + 'a, ClientStateMut = ClientState, ConsensusStateRef = StarknetConsensusState, >, @@ -56,7 +60,37 @@ where &header, )?; - let header = signed_header.header; + let raw_header = signed_header.header; + + let header_digest = ctx.generate_sha256_digest(&raw_header); + + let deps = ctx + .cosmwasm_execute_context() + .ok_or_else(|| ClientError::ClientSpecific { + description: "missing Deps from context".to_owned(), + })?; + + match deps.api.secp256k1_verify( + header_digest.as_slice(), + &signed_header.signature, + &self.0.pub_key, + ) { + Ok(true) => {} + Ok(false) => { + return Err(ClientError::ClientSpecific { + description: "Header signature not valid".to_owned(), + }) + } + Err(e) => { + return Err(ClientError::ClientSpecific { + description: format!("Header signature verification failed:{e} "), + }) + } + } + let header: StarknetHeader = >::decode(&StarknetLightClientEncoding, &raw_header)?; let latest_height = header.height; @@ -65,6 +99,7 @@ where let new_client_state = ClientStateType { latest_height: header.height, chain_id: self.0.chain_id.clone(), + pub_key: self.0.pub_key.clone(), } .into(); diff --git a/light-client/ibc-client-starknet/src/client_state/validation.rs b/light-client/ibc-client-starknet/src/client_state/validation.rs index 572f387c6..ae598ab4c 100644 --- a/light-client/ibc-client-starknet/src/client_state/validation.rs +++ b/light-client/ibc-client-starknet/src/client_state/validation.rs @@ -1,5 +1,5 @@ +use ibc_client_cw::context::client_ctx::CwClientValidation; use ibc_core::client::context::client_state::ClientStateValidation; -use ibc_core::client::context::ClientValidationContext; use ibc_core::client::types::error::ClientError; use ibc_core::client::types::Status; use ibc_core::host::types::identifiers::ClientId; @@ -8,9 +8,9 @@ use ibc_core::primitives::proto::Any; use super::ClientState; use crate::ConsensusState; -impl ClientStateValidation for ClientState +impl<'a, V> ClientStateValidation for ClientState where - V: ClientValidationContext, + V: CwClientValidation<'a, ClientStateRef = ClientState, ConsensusStateRef = ConsensusState>, { fn verify_client_message( &self, diff --git a/nix/ibc-starknet-cw.nix b/nix/ibc-starknet-cw.nix index 4a611fbd5..e1c3bae31 100644 --- a/nix/ibc-starknet-cw.nix +++ b/nix/ibc-starknet-cw.nix @@ -12,6 +12,7 @@ let outputHashes = { "hermes-cosmos-encoding-components-0.1.0" = "sha256-V1TlMnVHBwlSBJmB9gSJV/BgUTy7S0yhrtn3anZyorU="; "cgp-0.3.1" = "sha256-AOQ+WVQWPlF2ZfYYc5Eq3t7XAljd5P2qExWLYZWNnd8="; + "ibc-client-cw-0.56.0" = "sha256-EkLxuJfr3vf0busmSZD7DwOS9GfgfhT+sdopi1nNiCs="; }; }; diff --git a/relayer/Cargo.lock b/relayer/Cargo.lock index ff7278e51..0b3f8506a 100644 --- a/relayer/Cargo.lock +++ b/relayer/Cargo.lock @@ -2277,8 +2277,10 @@ dependencies = [ "ibc-client-starknet-types", "ibc-proto", "prost-types", + "secp256k1", "serde", "serde_json", + "sha2 0.10.8", "starknet", "tonic", ] diff --git a/relayer/Cargo.toml b/relayer/Cargo.toml index 97aba73ef..842a6fdb4 100644 --- a/relayer/Cargo.toml +++ b/relayer/Cargo.toml @@ -35,6 +35,7 @@ starknet-types-core = { version = "0.1.7" } url = { version = "2.4.0" } eyre = { version = "0.6.12" } tokio = { version = "1.38" } +secp256k1 = { version = "0.28.2" } serde = { version = "1.0" } serde_json = { version = "1.0" } rand = { version = "0.8.5" } diff --git a/relayer/crates/starknet-chain-components/Cargo.toml b/relayer/crates/starknet-chain-components/Cargo.toml index 93de6eeaa..ce8af6f3b 100644 --- a/relayer/crates/starknet-chain-components/Cargo.toml +++ b/relayer/crates/starknet-chain-components/Cargo.toml @@ -32,8 +32,10 @@ cairo-lang-starknet-classes = { workspace = true } http = { workspace = true } ibc-client-starknet-types = { workspace = true } prost-types = { workspace = true } +secp256k1 = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } +sha2 = { workspace = true } starknet = { workspace = true } tonic = { workspace = true } futures = { workspace = true } diff --git a/relayer/crates/starknet-chain-components/src/components/starknet_to_cosmos.rs b/relayer/crates/starknet-chain-components/src/components/starknet_to_cosmos.rs index 26f6ade91..5a9aca0f4 100644 --- a/relayer/crates/starknet-chain-components/src/components/starknet_to_cosmos.rs +++ b/relayer/crates/starknet-chain-components/src/components/starknet_to_cosmos.rs @@ -28,6 +28,7 @@ use hermes_relayer_components::chain::traits::queries::consensus_state::{ use crate::impls::starknet_to_cosmos::channel_message::BuildStarknetToCosmosChannelHandshakeMessage; use crate::impls::starknet_to_cosmos::connection_message::BuildStarknetToCosmosConnectionHandshake; use crate::impls::starknet_to_cosmos::counterparty_message_height::GetCosmosCounterpartyMessageStarknetHeight; +use crate::impls::starknet_to_cosmos::create_client_message::BuildStarknetCreateClientMessage; use crate::impls::starknet_to_cosmos::packet_fields::ReadPacketDstStarknetFields; use crate::impls::starknet_to_cosmos::query_consensus_state_height::QueryStarknetConsensusStateHeightsFromGrpc; use crate::impls::starknet_to_cosmos::update_client_message::BuildStarknetUpdateClientMessage; @@ -46,11 +47,12 @@ cgp_preset! { CreateClientPayloadTypeComponent, CreateClientMessageOptionsTypeComponent, CreateClientPayloadOptionsTypeComponent, - CreateClientMessageBuilderComponent, CreateClientPayloadBuilderComponent, ChannelOpenInitMessageBuilderComponent, ]: CosmosToCosmosComponents, + CreateClientMessageBuilderComponent: + BuildStarknetCreateClientMessage, [ ClientStateTypeComponent, ClientStateFieldsComponent, 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 84ef9aac8..e816da8e0 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 @@ -10,7 +10,6 @@ use ibc::core::client::types::Height; use ibc::core::host::types::identifiers::ChainId; use ibc::primitives::Timestamp; -use crate::types::client_state::{StarknetClientState, WasmStarknetClientState}; use crate::types::consensus_state::{StarknetConsensusState, WasmStarknetConsensusState}; use crate::types::payloads::client::{ StarknetCreateClientPayload, StarknetCreateClientPayloadOptions, @@ -38,14 +37,6 @@ where let root = Vec::from(chain_status.block_hash.to_bytes_be()); - let client_state = WasmStarknetClientState { - wasm_code_hash: create_client_options.wasm_code_hash.into(), - client_state: StarknetClientState { - latest_height: Height::new(0, 1).map_err(Chain::raise_error)?, - chain_id: chain.chain_id().clone(), - }, - }; - let consensus_state = WasmStarknetConsensusState { consensus_state: StarknetConsensusState { root: root.into(), @@ -54,7 +45,9 @@ where }; Ok(StarknetCreateClientPayload { - client_state, + latest_height: Height::new(0, 1).map_err(Chain::raise_error)?, + chain_id: chain.chain_id().clone(), + client_state_wasm_code_hash: create_client_options.wasm_code_hash.into(), consensus_state, }) } 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 new file mode 100644 index 000000000..3a33e554e --- /dev/null +++ b/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/create_client_message.rs @@ -0,0 +1,73 @@ +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; +use hermes_encoding_components::types::AsBytes; +use hermes_relayer_components::chain::traits::message_builders::create_client::CreateClientMessageBuilder; +use hermes_relayer_components::chain::traits::types::client_state::HasClientStateType; +use hermes_relayer_components::chain::traits::types::consensus_state::HasConsensusStateType; +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; + +use crate::types::client_state::WasmStarknetClientState; +use crate::types::consensus_state::WasmStarknetConsensusState; +use crate::types::payloads::client::StarknetCreateClientPayload; + +pub struct BuildStarknetCreateClientMessage; + +impl CreateClientMessageBuilder + for BuildStarknetCreateClientMessage +where + Chain: HasMessageType + + HasCreateClientMessageOptionsType + + HasDefaultSigner + + CanRaiseAsyncError, + Counterparty: HasCreateClientPayloadType + + HasClientStateType + + HasConsensusStateType + + HasDefaultEncoding, + Encoding: Async + + CanConvert + + CanConvert, +{ + async fn build_create_client_message( + chain: &Chain, + _options: &Chain::CreateClientMessageOptions, + payload: StarknetCreateClientPayload, + ) -> Result { + let encoding = Counterparty::default_encoding(); + + 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(), + }; + + let client_state = WasmStarknetClientState { + client_state: starknet_client_state, + wasm_code_hash: payload.client_state_wasm_code_hash, + }; + + let client_state = encoding + .convert(&client_state) + .map_err(Chain::raise_error)?; + + let consensus_state = encoding + .convert(&payload.consensus_state) + .map_err(Chain::raise_error)?; + + let message = CosmosCreateClientMessage { + client_state, + consensus_state, + }; + + Ok(message.to_cosmos_message()) + } +} diff --git a/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/mod.rs b/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/mod.rs index 6e046422f..0f5510313 100644 --- a/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/mod.rs +++ b/relayer/crates/starknet-chain-components/src/impls/starknet_to_cosmos/mod.rs @@ -1,6 +1,7 @@ pub mod channel_message; pub mod connection_message; pub mod counterparty_message_height; +pub mod create_client_message; pub mod packet_fields; pub mod query_consensus_state_height; pub mod update_client_message; 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 9c41cedc7..ae69b1a0b 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 @@ -3,8 +3,10 @@ use hermes_cosmos_chain_components::traits::message::{CosmosMessage, ToCosmosMes 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; 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::message_builders::update_client::UpdateClientMessageBuilder; use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes; use hermes_relayer_components::chain::traits::types::message::HasMessageType; @@ -28,7 +30,9 @@ where + CanRaiseAsyncError, Counterparty: HasUpdateClientPayloadType + HasDefaultEncoding, - Encoding: Async + CanConvert + CanConvert, + Encoding: Async + + CanEncode> + + CanConvert, { async fn build_update_client_message( chain: &Chain, @@ -37,28 +41,26 @@ where ) -> Result, Chain::Error> { let encoding = Counterparty::default_encoding(); - let header_bytes: Any = encoding - .convert(&payload.header) + let encoded_header = encoding + .encode(&payload.header) .map_err(Chain::raise_error)?; let signer = chain.get_default_signer(); - let signature = signer - .sign(&header_bytes.value) - .map_err(Chain::raise_error)?; + let signature = signer.sign(&encoded_header).map_err(Chain::raise_error)?; let signed_header = SignedStarknetHeader { - header: payload.header.clone(), + header: encoded_header.clone(), signature, }; - let header_any: Any = encoding + let signed_header_any: Any = encoding .convert(&signed_header) .map_err(Chain::raise_error)?; let update_client_message = CosmosUpdateClientMessage { client_id: client_id.clone(), - header: header_any, + header: signed_header_any, } .to_cosmos_message(); 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 814c1156e..c5ac4c7f8 100644 --- a/relayer/crates/starknet-chain-components/src/types/payloads/client.rs +++ b/relayer/crates/starknet-chain-components/src/types/payloads/client.rs @@ -1,12 +1,15 @@ use cgp::prelude::*; +use ibc::core::client::types::Height; +use ibc::core::host::types::identifiers::ChainId; use ibc_client_starknet_types::header::StarknetHeader; -use crate::types::client_state::WasmStarknetClientState; use crate::types::consensus_state::WasmStarknetConsensusState; #[derive(Debug, HasField)] pub struct StarknetCreateClientPayload { - pub client_state: WasmStarknetClientState, + pub latest_height: Height, + pub chain_id: ChainId, + pub client_state_wasm_code_hash: Vec, pub consensus_state: WasmStarknetConsensusState, }