Skip to content

Commit

Permalink
Natively implement Cosmos UpdateClient and Comet light client (#479)
Browse files Browse the repository at this point in the history
* Add comet-light-client-components crate

* Implement DoVerifyToTarget

* Add CanVerifyUpdateHeader

* Draft implementation of verify_forward

* Move comet crate to separate sub-directory

* Implement UpdateHeaderVerifier

* Remove VerifierState

* Rename Chain to Client

* Implement BisectHeight

* Implement FetchTendermintLightBlock

* Implement FetchTendermintLightBlockWithStatus

* Implement TraceTendermintVerification

* Implement DoUpdateVerifactionStatus

* Implement ValidateTendermintLightBlock

* Implement light client context and fields

* Implement QueryHighestTrustedOrVerifiedBefore

* Implement methods for CometLightClient

* Try using new light client

* Implement CanUpdateVerificationStatus<TrustedStatus>

* Implement CanBuildLightBlocksForUpdateClient

* Build UpdateClient headers

* Use back Hermes v1 types for now

* Use new UpdateClient payload builder

* New UpdateClient is working

* Remove old UpdateClient payload builder
  • Loading branch information
soareschen authored Nov 26, 2024
1 parent 4b50f6d commit 923643a
Show file tree
Hide file tree
Showing 58 changed files with 1,412 additions and 35 deletions.
29 changes: 29 additions & 0 deletions Cargo.lock

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

12 changes: 12 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ members = [
"crates/cosmos/cosmos-relayer",
"crates/cosmos/cosmos-wasm-relayer",

"crates/comet/comet-light-client-components",
"crates/comet/comet-light-client-context",

"crates/celestia/celestia-test-components",
"crates/celestia/celestia-integration-tests",

Expand Down Expand Up @@ -75,6 +78,7 @@ overflow-checks = true
[workspace.dependencies]
async-trait = { version = "0.1.83" }
ibc = { version = "0.56.0", default-features = false }
ibc-client-tendermint = { version = "0.56.0", default-features = false }
ibc-proto = { version = "0.51.1", default-features = false }
ibc-relayer = { version = "0.29.3" }
ibc-relayer-types = { version = "0.29.3" }
Expand All @@ -83,6 +87,8 @@ tendermint = { version = "0.40" }
tendermint-proto = { version = "0.40" }
tendermint-rpc = { version = "0.40" }
tendermint-testgen = { version = "0.40" }
tendermint-light-client-verifier = { version = "0.40" }
tendermint-light-client = { version = "0.40" }
basecoin = { version = "0.2.0" }
cgp = { version = "0.1.0" }
cgp-core = { version = "0.1.0" }
Expand Down Expand Up @@ -153,6 +159,9 @@ hermes-cosmos-wasm-relayer = { version = "0.1.0" }
hermes-cosmos-test-components = { version = "0.1.0" }
hermes-cosmos-integration-tests = { version = "0.1.0" }

hermes-comet-light-client-components = { version = "0.1.0" }
hermes-comet-light-client-context = { version = "0.1.0" }

hermes-celestia-test-components = { version = "0.1.0" }
hermes-celestia-integration-tests = { version = "0.1.0" }

Expand Down Expand Up @@ -224,6 +233,9 @@ hermes-cosmos-wasm-relayer = { path = "./crates/cosmos/cosmos-wasm-rela
hermes-cosmos-test-components = { path = "./crates/cosmos/cosmos-test-components" }
hermes-cosmos-integration-tests = { path = "./crates/cosmos/cosmos-integration-tests" }

hermes-comet-light-client-components = { path = "./crates/comet/comet-light-client-components" }
hermes-comet-light-client-context = { path = "./crates/comet/comet-light-client-context" }

hermes-celestia-test-components = { path = "./crates/celestia/celestia-test-components" }
hermes-celestia-integration-tests = { path = "./crates/celestia/celestia-integration-tests" }

Expand Down
16 changes: 16 additions & 0 deletions crates/comet/comet-light-client-components/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "hermes-comet-light-client-components"
version = { workspace = true }
edition = { workspace = true }
license = { workspace = true }
keywords = { workspace = true }
repository = { workspace = true }
authors = { workspace = true }
rust-version = { workspace = true }
description = """
Implementation of an IBC Relayer in Rust, as a library
"""

[dependencies]
cgp = { workspace = true }
hermes-chain-type-components = { workspace = true }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod verify_target_height;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod verify_forward;
pub mod verify_to_target;
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use core::fmt::Debug;

use cgp::core::Async;
use cgp::prelude::CanRaiseError;
use hermes_chain_type_components::traits::types::height::HasHeightType;

use crate::traits::compute_verification_height::CanComputeNextVerificationHeight;
use crate::traits::fetch_light_block::CanFetchLightBlockWithStatus;
use crate::traits::light_block::height::HasLightBlockHeight;
use crate::traits::query_light_block::{CanQueryLightBlock, GetHighestTrustedOrVerifiedBefore};
use crate::traits::trace_verification_height::CanTraceVerificationHeight;
use crate::traits::types::status::HasVerificationStatusType;
use crate::traits::types::verdict::HasVerdictType;
use crate::traits::update_verification_status::{CanUpdateVerificationStatus, VerifiedStatus};
use crate::traits::validate_light_block::{CanValidateLightBlock, IsWithinTrustingPeriod};
use crate::traits::verify_target_height::{NoInitialTrustedState, TargetHeightVerifier};
use crate::traits::verify_update_header::CanVerifyUpdateHeader;
use crate::types::status::VerificationStatus;
use crate::types::verdict::Verdict;

pub struct DoVerifyForward;

pub struct TargetLowerThanTrustedHeight<'a, Client>
where
Client: HasHeightType,
{
pub target_height: &'a Client::Height,
pub trusted_height: &'a Client::Height,
}

impl<Client, Mode> TargetHeightVerifier<Client, Mode> for DoVerifyForward
where
Client: HasLightBlockHeight
+ HasVerdictType<Verdict = Verdict>
+ HasVerificationStatusType<VerificationStatus = VerificationStatus>
+ CanVerifyUpdateHeader
+ CanTraceVerificationHeight
+ CanFetchLightBlockWithStatus
+ CanComputeNextVerificationHeight
+ CanUpdateVerificationStatus<VerifiedStatus>
+ CanValidateLightBlock<IsWithinTrustingPeriod>
+ CanQueryLightBlock<GetHighestTrustedOrVerifiedBefore>
+ CanRaiseError<NoInitialTrustedState>
+ for<'a> CanRaiseError<TargetLowerThanTrustedHeight<'a, Client>>,
Mode: Async,
{
async fn verify_target_height(
client: &mut Client,
_mode: Mode,
target_height: &Client::Height,
) -> Result<Client::LightBlock, Client::Error> {
let mut current_height = target_height.clone();

loop {
let trusted_block = client
.query_light_block(GetHighestTrustedOrVerifiedBefore, target_height)
.ok_or_else(|| Client::raise_error(NoInitialTrustedState))?;

let trusted_height = Client::light_block_height(&trusted_block);

if target_height < trusted_height {
return Err(Client::raise_error(TargetLowerThanTrustedHeight {
target_height,
trusted_height,
}));
}

client.validate_light_block(IsWithinTrustingPeriod, &trusted_block)?;

client.trace_verification_height(target_height, &current_height);

if target_height == trusted_height {
return Ok(trusted_block);
}

let (current_block, current_status) = client
.fetch_light_block_with_status(&current_height)
.await?;

let verdict = client.verify_update_header(&current_block, &trusted_block)?;

if verdict == Verdict::Success {
if current_status == VerificationStatus::Unverified {
client.update_verification_status(VerifiedStatus, &current_block);
}

client.trace_verification_height(&current_height, trusted_height);
}

current_height =
client.compute_next_verification_height(&current_height, target_height)?;
}
}
}

impl<'a, Client> Debug for TargetLowerThanTrustedHeight<'a, Client>
where
Client: HasHeightType<Height: Debug>,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TargetLowerThanTrustedHeight")
.field("target_height", &self.target_height)
.field("trusted_height", &self.trusted_height)
.finish()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use cgp::prelude::CanRaiseError;

use crate::traits::light_block::height::HasLightBlockHeight;
use crate::traits::query_light_block::{
CanQueryLightBlock, GetHighestTrustedOrVerifiedBefore, GetLowestTrustedOrVerified,
GetTrustedOrVerified,
};
use crate::traits::verify_target_height::{
CanVerifyTargetHeight, NoInitialTrustedState, TargetHeightVerifier, VerifyBackward,
VerifyForward, VerifyToTarget,
};

pub struct DoVerifyToTarget;

impl<Client> TargetHeightVerifier<Client, VerifyToTarget> for DoVerifyToTarget
where
Client: HasLightBlockHeight
+ CanVerifyTargetHeight<VerifyForward>
+ CanVerifyTargetHeight<VerifyBackward>
+ CanQueryLightBlock<GetTrustedOrVerified>
+ CanQueryLightBlock<GetHighestTrustedOrVerifiedBefore>
+ CanQueryLightBlock<GetLowestTrustedOrVerified>
+ CanRaiseError<NoInitialTrustedState>,
{
async fn verify_target_height(
client: &mut Client,
_mode: VerifyToTarget,
target_height: &Client::Height,
) -> Result<Client::LightBlock, Client::Error> {
if let Some(block) = client.query_light_block(GetTrustedOrVerified, target_height) {
return Ok(block);
}

let highest_block = client
.query_light_block(GetHighestTrustedOrVerifiedBefore, target_height)
.or_else(|| client.query_light_block(GetHighestTrustedOrVerifiedBefore, target_height))
.ok_or_else(|| Client::raise_error(NoInitialTrustedState))?;

let highest_height = Client::light_block_height(&highest_block);

if target_height >= highest_height {
client
.verify_target_height(VerifyForward, target_height)
.await
} else {
client
.verify_target_height(VerifyBackward, target_height)
.await
}
}
}
3 changes: 3 additions & 0 deletions crates/comet/comet-light-client-components/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod impls;
pub mod traits;
pub mod types;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use cgp::prelude::*;
use hermes_chain_type_components::traits::types::height::HasHeightType;

#[derive_component(NextVerificationHeightComputerComponent, NextVerificationHeightComputer<Client>)]
pub trait CanComputeNextVerificationHeight: HasHeightType + HasErrorType {
fn compute_next_verification_height(
&self,
current_height: &Self::Height,
target_height: &Self::Height,
) -> Result<Self::Height, Self::Error>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use cgp::prelude::*;
use hermes_chain_type_components::traits::types::height::HasHeightType;

use crate::traits::types::light_block::HasLightBlockType;
use crate::traits::types::status::HasVerificationStatusType;

#[derive_component(LightBlockFetcherComponent, LightBlockFetcher<Client>)]
#[async_trait]
pub trait CanFetchLightBlock: HasHeightType + HasLightBlockType + HasErrorType {
async fn fetch_light_block(
&self,
height: &Self::Height,
) -> Result<Self::LightBlock, Self::Error>;
}

#[derive_component(LightBlockWithStatusFetcherComponent, LightBlockWithStatusFetcher<Client>)]
#[async_trait]
pub trait CanFetchLightBlockWithStatus:
HasHeightType + HasLightBlockType + HasVerificationStatusType + HasErrorType
{
async fn fetch_light_block_with_status(
&mut self,
height: &Self::Height,
) -> Result<(Self::LightBlock, Self::VerificationStatus), Self::Error>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use cgp::prelude::*;
use hermes_chain_type_components::traits::types::height::HasHeightType;

use crate::traits::types::light_block::HasLightBlockType;

#[derive_component(LightBlockHeightGetterComponent, LightBlockHeightGetter<Client>)]
pub trait HasLightBlockHeight: HasLightBlockType + HasHeightType {
fn light_block_height(light_block: &Self::LightBlock) -> &Self::Height;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod height;
11 changes: 11 additions & 0 deletions crates/comet/comet-light-client-components/src/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
pub mod compute_verification_height;
pub mod fetch_light_block;
pub mod light_block;
pub mod query_light_block;
pub mod trace_verification_height;
pub mod types;
pub mod update_client;
pub mod update_verification_status;
pub mod validate_light_block;
pub mod verify_target_height;
pub mod verify_update_header;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use cgp::prelude::*;
use hermes_chain_type_components::traits::types::height::HasHeightType;

use crate::traits::types::light_block::HasLightBlockType;

#[derive_component(LightBlockQuerierComponent, LightBlockQuerier<Client>)]
pub trait CanQueryLightBlock<Mode>: HasHeightType + HasLightBlockType {
fn query_light_block(&self, _mode: Mode, height: &Self::Height) -> Option<Self::LightBlock>;
}

pub struct GetTrustedOrVerified;

pub struct GetHighestTrustedOrVerifiedBefore;

pub struct GetLowestTrustedOrVerified;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use cgp::prelude::*;
use hermes_chain_type_components::traits::types::height::HasHeightType;

#[derive_component(VerificationHeightTracerComponent, VerificationHeightTracer<Client>)]
pub trait CanTraceVerificationHeight: HasHeightType {
fn trace_verification_height(
&mut self,
target_height: &Self::Height,
current_height: &Self::Height,
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use cgp::prelude::*;

#[derive_component(LightBlockTypeComponent, ProvideLightBlockType<Client>)]
pub trait HasLightBlockType: Async {
type LightBlock: Async;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod light_block;
pub mod status;
pub mod verdict;
Loading

0 comments on commit 923643a

Please sign in to comment.