Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verify Header in Wasm light client #205

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions light-client/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions light-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
1 change: 1 addition & 0 deletions light-client/ibc-client-starknet-types/src/client_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8>,
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -27,26 +28,32 @@ delegate_components! {
symbol!("chain_id"),
EncodeChainIdField<2>,
>,
EncodeField<
symbol!("pub_key"),
EncodeByteField<3>,
>,
]>,
MutDecoderComponent: DecodeFrom<
Self,
CombineEncoders<Product![
DecodeRequiredProtoField<1, UseContext>,
EncodeChainIdField<2>,
EncodeByteField<3>,
]>
>,
}
}

impl Transformer for EncodeStarknetClientState {
type From = Product![Height, ChainId];
type From = Product![Height, ChainId, Vec<u8>];

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,
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ delegate_components! {
CombineEncoders<Product![
EncodeField<
symbol!("header"),
EncodeLengthDelimitedProtoField<1, UseContext>,
EncodeByteField<1>,
>,
EncodeField<
symbol!("signature"),
Expand All @@ -69,15 +69,15 @@ delegate_components! {
MutDecoderComponent: DecodeFrom<
Self,
CombineEncoders<Product![
DecodeRequiredProtoField<1, UseContext>,
EncodeByteField<1>,
EncodeByteField<2>,
]>
>,
}
}

impl Transformer for EncodeSignedStarknetHeader {
type From = Product![StarknetHeader, Vec<u8>];
type From = Product![Vec<u8>, Vec<u8>];

type To = SignedStarknetHeader;

Expand Down
2 changes: 1 addition & 1 deletion light-client/ibc-client-starknet-types/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ pub struct StarknetHeader {

#[derive(Debug, Clone, HasField)]
pub struct SignedStarknetHeader {
pub header: StarknetHeader,
pub header: Vec<u8>,
pub signature: Vec<u8>,
}
1 change: 1 addition & 0 deletions light-client/ibc-client-starknet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" ]
Expand Down
44 changes: 40 additions & 4 deletions light-client/ibc-client-starknet/src/client_state/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 ibc_client_cw::context::client_ctx::CwClientExecution;
use ibc_client_starknet_types::header::{
SignedStarknetHeader, StarknetHeader, STARKNET_HEADER_TYPE_URL,
};
use ibc_client_starknet_types::StarknetClientState as ClientStateType;
use ibc_core::client::context::client_state::ClientStateExecution;
use ibc_core::client::context::prelude::{ClientStateCommon, ConsensusState};
Expand All @@ -18,9 +21,10 @@ use super::ClientState;
use crate::encoding::context::StarknetLightClientEncoding;
use crate::ConsensusState as StarknetConsensusState;

impl<E> ClientStateExecution<E> for ClientState
impl<'a, E> ClientStateExecution<E> for ClientState
where
E: ClientExecutionContext<
E: CwClientExecution<
'a,
ClientStateMut = ClientState,
ConsensusStateRef = StarknetConsensusState,
>,
Expand Down Expand Up @@ -56,7 +60,38 @@ 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(validation) if validation => {}
_ => {
return Err(ClientError::ClientSpecific {
description: "Header signature not valid".to_owned(),
})
}
}

let any_header = Any {
type_url: STARKNET_HEADER_TYPE_URL.to_owned(),
value: raw_header,
};

let header: StarknetHeader = <ConvertVia<ProstAny, ConvertIbcAny, UseContext>>::convert(
&StarknetLightClientEncoding,
&any_header,
)?;

let latest_height = header.height;

Expand All @@ -65,6 +100,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();

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -8,9 +8,9 @@ use ibc_core::primitives::proto::Any;
use super::ClientState;
use crate::ConsensusState;

impl<V> ClientStateValidation<V> for ClientState
impl<'a, V> ClientStateValidation<V> for ClientState
where
V: ClientValidationContext<ClientStateRef = ClientState, ConsensusStateRef = ConsensusState>,
V: CwClientValidation<'a, ClientStateRef = ClientState, ConsensusStateRef = ConsensusState>,
{
fn verify_client_message(
&self,
Expand Down
1 change: 1 addition & 0 deletions nix/ibc-starknet-cw.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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=";
};
};

Expand Down
3 changes: 3 additions & 0 deletions relayer/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions relayer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
2 changes: 2 additions & 0 deletions relayer/crates/starknet-chain-components/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -46,11 +47,12 @@ cgp_preset! {
CreateClientPayloadTypeComponent,
CreateClientMessageOptionsTypeComponent,
CreateClientPayloadOptionsTypeComponent,
CreateClientMessageBuilderComponent,
CreateClientPayloadBuilderComponent,
ChannelOpenInitMessageBuilderComponent,
]:
CosmosToCosmosComponents,
CreateClientMessageBuilderComponent:
BuildStarknetCreateClientMessage,
[
ClientStateTypeComponent,
ClientStateFieldsComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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(),
Expand All @@ -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,
})
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Chain, Counterparty, Encoding> CreateClientMessageBuilder<Chain, Counterparty>
for BuildStarknetCreateClientMessage
where
Chain: HasMessageType<Message = CosmosMessage>
+ HasCreateClientMessageOptionsType<Counterparty>
+ HasDefaultSigner<Signer = Secp256k1KeyPair>
+ CanRaiseAsyncError<Encoding::Error>,
Counterparty: HasCreateClientPayloadType<Chain, CreateClientPayload = StarknetCreateClientPayload>
+ HasClientStateType<Chain, ClientState = WasmStarknetClientState>
+ HasConsensusStateType<Chain, ConsensusState = WasmStarknetConsensusState>
+ HasDefaultEncoding<AsBytes, Encoding = Encoding>,
Encoding: Async
+ CanConvert<Counterparty::ClientState, Any>
+ CanConvert<Counterparty::ConsensusState, Any>,
{
async fn build_create_client_message(
chain: &Chain,
_options: &Chain::CreateClientMessageOptions,
payload: StarknetCreateClientPayload,
) -> Result<CosmosMessage, Chain::Error> {
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())
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Loading
Loading