From 9b4af4f7bbfc924df91b69dbf9341d7b2ac3c928 Mon Sep 17 00:00:00 2001 From: aeryz Date: Wed, 8 Jan 2025 14:54:50 +0300 Subject: [PATCH 1/3] chore(voyager): make client-update for state lenses generic Signed-off-by: aeryz --- Cargo.toml | 4 +- lib/state-lens-light-client-types/Cargo.toml | 23 ++++ .../src/header.rs | 123 ++++++++++++++++++ lib/state-lens-light-client-types/src/lib.rs | 3 + .../client-update/state-lens/evm/src/main.rs | 48 ++----- 5 files changed, 164 insertions(+), 37 deletions(-) create mode 100644 lib/state-lens-light-client-types/Cargo.toml create mode 100644 lib/state-lens-light-client-types/src/header.rs create mode 100644 lib/state-lens-light-client-types/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 8624fcc77c..404f545cff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -171,7 +171,7 @@ members = [ "mpc/coordinator", "lib/ibc-union-spec", - "lib/ibc-classic-spec", + "lib/ibc-classic-spec", "lib/state-lens-light-client-types", ] [workspace.package] @@ -200,6 +200,8 @@ chain-utils = { path = "lib/chain-utils", default-features = false } cometbft-rpc = { path = "lib/cometbft-rpc", default-features = false } cometbft-types = { path = "lib/cometbft-types", default-features = false } +state-lens-light-client-types = { path = "lib/state-lens-light-client-types", default-features = false } + arbitrum-light-client-types = { path = "lib/arbitrum-light-client-types", default-features = false } arbitrum-verifier = { path = "lib/arbitrum-verifier", default-features = false } diff --git a/lib/state-lens-light-client-types/Cargo.toml b/lib/state-lens-light-client-types/Cargo.toml new file mode 100644 index 0000000000..8fa7736cff --- /dev/null +++ b/lib/state-lens-light-client-types/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "state-lens-light-client-types" +version = "0.1.0" +edition.workspace = true +license-file.workspace = true +repository.workspace = true + +[dependencies] +alloy = { workspace = true, features = ["sol-types"], optional = true } +bincode = { workspace = true, features = ["alloc", "derive"], optional = true } +protos = { workspace = true, optional = true, features = ["proto_full", "serde"] } +serde = { workspace = true, optional = true, features = ["derive"] } +thiserror = { workspace = true } +unionlabs = { workspace = true, features = ["ethabi", "proto"] } + +[features] +bincode = ["dep:bincode", "unionlabs/bincode"] +default = [] +ethabi = ["unionlabs/ethabi", "dep:alloy", "dep:protos"] +serde = ["dep:serde"] + +[lints] +workspace = true diff --git a/lib/state-lens-light-client-types/src/header.rs b/lib/state-lens-light-client-types/src/header.rs new file mode 100644 index 0000000000..985a919d79 --- /dev/null +++ b/lib/state-lens-light-client-types/src/header.rs @@ -0,0 +1,123 @@ +use unionlabs::{ + ibc::core::{client::height::Height, commitment::merkle_proof::MerkleProof}, + primitives::Bytes, +}; + +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] +pub struct Header { + pub l1_height: Height, + pub l2_height: Height, + pub l2_consensus_state_proof: MerkleProof, + pub l2_consensus_state: Bytes, +} + +#[cfg(feature = "ethabi")] +pub mod ethabi { + use alloy::sol_types::SolValue; + use unionlabs::{ + encoding::{Encode, EthAbi}, + union::ics23, + }; + + use crate::Header; + + impl Encode for Header { + fn encode(self) -> Vec { + Into::::into(self).abi_encode_params() + } + } + + alloy::sol! { + struct SolHeader { + uint64 l1Height; + uint64 l2Height; + bytes l2InclusionProof; + bytes l2ConsensusState; + } + } + + impl From
for SolHeader { + fn from(value: Header) -> Self { + Self { + l1Height: value.l1_height.height(), + l2Height: value.l2_height.height(), + l2InclusionProof: encode_merkle_proof_for_evm(value.l2_consensus_state_proof) + .into(), + l2ConsensusState: value.l2_consensus_state.into(), + } + } + } + + // FIXME: deduplicate with voyager/module/client/cometbls, in unionlabs? + fn encode_merkle_proof_for_evm( + proof: unionlabs::ibc::core::commitment::merkle_proof::MerkleProof, + ) -> Vec { + alloy::sol! { + struct ExistenceProof { + bytes key; + bytes value; + bytes leafPrefix; + InnerOp[] path; + } + + struct NonExistenceProof { + bytes key; + ExistenceProof left; + ExistenceProof right; + } + + struct InnerOp { + bytes prefix; + bytes suffix; + } + + struct ProofSpec { + uint256 childSize; + uint256 minPrefixLength; + uint256 maxPrefixLength; + } + } + + let merkle_proof = ics23::merkle_proof::MerkleProof::try_from( + protos::ibc::core::commitment::v1::MerkleProof::from(proof), + ) + .unwrap(); + + let convert_inner_op = |i: unionlabs::union::ics23::inner_op::InnerOp| InnerOp { + prefix: i.prefix.into(), + suffix: i.suffix.into(), + }; + + let convert_existence_proof = + |e: unionlabs::union::ics23::existence_proof::ExistenceProof| ExistenceProof { + key: e.key.into(), + value: e.value.into(), + leafPrefix: e.leaf_prefix.into(), + path: e.path.into_iter().map(convert_inner_op).collect(), + }; + + let exist_default = || ics23::existence_proof::ExistenceProof { + key: vec![].into(), + value: vec![].into(), + leaf_prefix: vec![].into(), + path: vec![], + }; + + match merkle_proof { + ics23::merkle_proof::MerkleProof::Membership(a, b) => { + (convert_existence_proof(a), convert_existence_proof(b)).abi_encode_params() + } + ics23::merkle_proof::MerkleProof::NonMembership(a, b) => ( + NonExistenceProof { + key: a.key.into(), + left: convert_existence_proof(a.left.unwrap_or_else(exist_default)), + right: convert_existence_proof(a.right.unwrap_or_else(exist_default)), + }, + convert_existence_proof(b), + ) + .abi_encode_params(), + } + } +} diff --git a/lib/state-lens-light-client-types/src/lib.rs b/lib/state-lens-light-client-types/src/lib.rs new file mode 100644 index 0000000000..cbe90f5737 --- /dev/null +++ b/lib/state-lens-light-client-types/src/lib.rs @@ -0,0 +1,3 @@ +mod header; + +pub use header::*; diff --git a/voyager/plugins/client-update/state-lens/evm/src/main.rs b/voyager/plugins/client-update/state-lens/evm/src/main.rs index d91325a96b..94e25d1106 100644 --- a/voyager/plugins/client-update/state-lens/evm/src/main.rs +++ b/voyager/plugins/client-update/state-lens/evm/src/main.rs @@ -1,9 +1,5 @@ use std::{collections::VecDeque, fmt::Debug}; -use alloy::{ - providers::{Provider, ProviderBuilder, RootProvider}, - transports::BoxTransport, -}; use call::FetchUpdateAfterL1Update; use ibc_union_spec::{ConsensusStatePath, IbcUnion}; use jsonrpsee::{ @@ -11,7 +7,7 @@ use jsonrpsee::{ Extensions, }; use serde::{Deserialize, Serialize}; -use state_lens_ics23_mpt_light_client_types::Header; +use state_lens_light_client_types::Header; use tracing::{debug, instrument}; use unionlabs::ibc::core::commitment::merkle_proof::MerkleProof; use voyager_message::{ @@ -45,9 +41,8 @@ pub struct Module { pub l1_client_id: u32, pub l1_chain_id: ChainId, pub l2_chain_id: ChainId, - - pub l2_eth_provider: RootProvider, - pub l1_tm_client: cometbft_rpc::Client, + pub l2_client_type: String, + pub state_lens_client_type: String, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -56,9 +51,8 @@ pub struct Config { pub l1_client_id: u32, pub l1_chain_id: ChainId, pub l2_chain_id: ChainId, - - pub l1_ws_url: String, - pub l2_rpc_url: String, + pub l2_client_type: String, + pub state_lens_client_type: String, } impl Plugin for Module { @@ -69,31 +63,13 @@ impl Plugin for Module { type Cmd = DefaultCmd; async fn new(config: Self::Config) -> Result { - let l1_tm_client = cometbft_rpc::Client::new(config.l1_ws_url).await?; - - let l1_chain_id = l1_tm_client.status().await?.node_info.network.to_string(); - - if l1_chain_id != config.l1_chain_id.as_str() { - return Err(format!( - "incorrect chain id: expected `{}`, but found `{}`", - config.l1_chain_id, l1_chain_id - ) - .into()); - } - - let l2_eth_provider = ProviderBuilder::new() - .on_builtin(&config.l2_rpc_url) - .await?; - - let l2_chain_id = ChainId::new(l2_eth_provider.get_chain_id().await?.to_string()); - Ok(Self { l0_client_id: config.l0_client_id, l1_client_id: config.l1_client_id, - l1_chain_id: ChainId::new(l1_chain_id), - l2_chain_id, - l1_tm_client, - l2_eth_provider, + l1_chain_id: config.l1_chain_id, + l2_chain_id: config.l2_chain_id, + l2_client_type: config.l2_client_type, + state_lens_client_type: config.state_lens_client_type, }) } @@ -102,7 +78,7 @@ impl Plugin for Module { name: plugin_name(&config.l2_chain_id), interest_filter: UpdateHook::filter( &config.l2_chain_id, - &ClientType::new(ClientType::STATE_LENS_ICS23_MPT), + &ClientType::new(config.state_lens_client_type), ), } } @@ -139,7 +115,7 @@ impl PluginServer for Module { .map(|mut op| { UpdateHook::new( &self.l2_chain_id, - &ClientType::new(ClientType::STATE_LENS_ICS23_MPT), + &ClientType::new(self.state_lens_client_type.clone()), |fetch| { Call::Plugin(PluginMessage::new( self.plugin_name(), @@ -209,7 +185,7 @@ impl PluginServer for Module { // Update the L2 (eth) client on L1 (union) and then dispatch the continuation promise( [call(FetchUpdateHeaders { - client_type: ClientType::new(ClientType::ETHEREUM), + client_type: ClientType::new(self.l2_client_type.clone()), chain_id: self.l2_chain_id.clone(), counterparty_chain_id: self.l1_chain_id.clone(), update_from, From bedb6ad566e8ad8fe83f4948422903c5a63907ec Mon Sep 17 00:00:00 2001 From: benluelo Date: Wed, 8 Jan 2025 15:45:36 +0000 Subject: [PATCH 2/3] chore: helping ben to write proper commit messages --- Cargo.lock | 14 ++- .../src/header.rs | 85 ++----------------- lib/state-lens-light-client-types/src/lib.rs | 2 +- .../client-update/state-lens/evm/Cargo.toml | 46 +++++----- .../client-update/state-lens/evm/src/main.rs | 77 ++++++++++------- 5 files changed, 88 insertions(+), 136 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e08588e2f4..6bc1964cca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11344,6 +11344,18 @@ dependencies = [ "unionlabs", ] +[[package]] +name = "state-lens-light-client-types" +version = "0.1.0" +dependencies = [ + "alloy", + "bincode 2.0.0-rc.3", + "protos", + "serde", + "thiserror", + "unionlabs", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -13359,7 +13371,7 @@ dependencies = [ "protos", "serde", "serde_json", - "state-lens-ics23-mpt-light-client-types", + "state-lens-light-client-types", "thiserror", "tokio", "tracing", diff --git a/lib/state-lens-light-client-types/src/header.rs b/lib/state-lens-light-client-types/src/header.rs index 985a919d79..1fa0fd1deb 100644 --- a/lib/state-lens-light-client-types/src/header.rs +++ b/lib/state-lens-light-client-types/src/header.rs @@ -1,7 +1,4 @@ -use unionlabs::{ - ibc::core::{client::height::Height, commitment::merkle_proof::MerkleProof}, - primitives::Bytes, -}; +use unionlabs::{ibc::core::client::height::Height, primitives::Bytes}; #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -9,7 +6,8 @@ use unionlabs::{ pub struct Header { pub l1_height: Height, pub l2_height: Height, - pub l2_consensus_state_proof: MerkleProof, + /// Proof of the L2 consensus state as stored in the state of the L1. + pub l2_consensus_state_proof: Bytes, pub l2_consensus_state: Bytes, } @@ -18,11 +16,14 @@ pub mod ethabi { use alloy::sol_types::SolValue; use unionlabs::{ encoding::{Encode, EthAbi}, + impl_ethabi_via_try_from_into, union::ics23, }; use crate::Header; + impl_ethabi_via_try_from_into!(Header => SolHeader); + impl Encode for Header { fn encode(self) -> Vec { Into::::into(self).abi_encode_params() @@ -43,81 +44,9 @@ pub mod ethabi { Self { l1Height: value.l1_height.height(), l2Height: value.l2_height.height(), - l2InclusionProof: encode_merkle_proof_for_evm(value.l2_consensus_state_proof) - .into(), + l2InclusionProof: value.l2_consensus_state_proof.into(), l2ConsensusState: value.l2_consensus_state.into(), } } } - - // FIXME: deduplicate with voyager/module/client/cometbls, in unionlabs? - fn encode_merkle_proof_for_evm( - proof: unionlabs::ibc::core::commitment::merkle_proof::MerkleProof, - ) -> Vec { - alloy::sol! { - struct ExistenceProof { - bytes key; - bytes value; - bytes leafPrefix; - InnerOp[] path; - } - - struct NonExistenceProof { - bytes key; - ExistenceProof left; - ExistenceProof right; - } - - struct InnerOp { - bytes prefix; - bytes suffix; - } - - struct ProofSpec { - uint256 childSize; - uint256 minPrefixLength; - uint256 maxPrefixLength; - } - } - - let merkle_proof = ics23::merkle_proof::MerkleProof::try_from( - protos::ibc::core::commitment::v1::MerkleProof::from(proof), - ) - .unwrap(); - - let convert_inner_op = |i: unionlabs::union::ics23::inner_op::InnerOp| InnerOp { - prefix: i.prefix.into(), - suffix: i.suffix.into(), - }; - - let convert_existence_proof = - |e: unionlabs::union::ics23::existence_proof::ExistenceProof| ExistenceProof { - key: e.key.into(), - value: e.value.into(), - leafPrefix: e.leaf_prefix.into(), - path: e.path.into_iter().map(convert_inner_op).collect(), - }; - - let exist_default = || ics23::existence_proof::ExistenceProof { - key: vec![].into(), - value: vec![].into(), - leaf_prefix: vec![].into(), - path: vec![], - }; - - match merkle_proof { - ics23::merkle_proof::MerkleProof::Membership(a, b) => { - (convert_existence_proof(a), convert_existence_proof(b)).abi_encode_params() - } - ics23::merkle_proof::MerkleProof::NonMembership(a, b) => ( - NonExistenceProof { - key: a.key.into(), - left: convert_existence_proof(a.left.unwrap_or_else(exist_default)), - right: convert_existence_proof(a.right.unwrap_or_else(exist_default)), - }, - convert_existence_proof(b), - ) - .abi_encode_params(), - } - } } diff --git a/lib/state-lens-light-client-types/src/lib.rs b/lib/state-lens-light-client-types/src/lib.rs index cbe90f5737..193c80e3a9 100644 --- a/lib/state-lens-light-client-types/src/lib.rs +++ b/lib/state-lens-light-client-types/src/lib.rs @@ -1,3 +1,3 @@ mod header; -pub use header::*; +pub use header::Header; diff --git a/voyager/plugins/client-update/state-lens/evm/Cargo.toml b/voyager/plugins/client-update/state-lens/evm/Cargo.toml index da8598a618..a99c3bffff 100644 --- a/voyager/plugins/client-update/state-lens/evm/Cargo.toml +++ b/voyager/plugins/client-update/state-lens/evm/Cargo.toml @@ -4,26 +4,26 @@ name = "voyager-client-update-plugin-state-lens-evm" version = "0.1.0" [dependencies] -alloy = { workspace = true, features = ["rpc", "rpc-types", "transports", "transport-http", "transport-ws", "reqwest", "provider-ws"] } -cometbft-rpc = { workspace = true } -cometbft-types.workspace = true -dashmap = { workspace = true } -enumorph = { workspace = true } -futures = { workspace = true } -ibc-union-spec.workspace = true -ics23 = { workspace = true } -jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } -macros = { workspace = true } -num-bigint = { workspace = true } -prost = { workspace = true } -protos = { workspace = true } -serde = { workspace = true, features = ["derive"] } -serde_json = { workspace = true } -state-lens-ics23-mpt-light-client-types = { workspace = true, features = ["serde"] } -thiserror = { workspace = true } -tokio = { workspace = true } -tracing = { workspace = true } -tracing-subscriber = { workspace = true } -unionlabs = { workspace = true } -voyager-message = { workspace = true } -voyager-vm = { workspace = true } +alloy = { workspace = true, features = ["rpc", "rpc-types", "transports", "transport-http", "transport-ws", "reqwest", "provider-ws"] } +cometbft-rpc = { workspace = true } +cometbft-types = { workspace = true } +dashmap = { workspace = true } +enumorph = { workspace = true } +futures = { workspace = true } +ibc-union-spec = { workspace = true } +ics23 = { workspace = true } +jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } +macros = { workspace = true } +num-bigint = { workspace = true } +prost = { workspace = true } +protos = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +state-lens-light-client-types = { workspace = true, features = ["serde"] } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +unionlabs = { workspace = true } +voyager-message = { workspace = true } +voyager-vm = { workspace = true } diff --git a/voyager/plugins/client-update/state-lens/evm/src/main.rs b/voyager/plugins/client-update/state-lens/evm/src/main.rs index 94e25d1106..c33de122a7 100644 --- a/voyager/plugins/client-update/state-lens/evm/src/main.rs +++ b/voyager/plugins/client-update/state-lens/evm/src/main.rs @@ -42,7 +42,7 @@ pub struct Module { pub l1_chain_id: ChainId, pub l2_chain_id: ChainId, pub l2_client_type: String, - pub state_lens_client_type: String, + pub state_lens_client_type: ClientType, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -52,7 +52,7 @@ pub struct Config { pub l1_chain_id: ChainId, pub l2_chain_id: ChainId, pub l2_client_type: String, - pub state_lens_client_type: String, + pub state_lens_client_type: ClientType, } impl Plugin for Module { @@ -78,7 +78,7 @@ impl Plugin for Module { name: plugin_name(&config.l2_chain_id), interest_filter: UpdateHook::filter( &config.l2_chain_id, - &ClientType::new(config.state_lens_client_type), + &config.state_lens_client_type, ), } } @@ -113,20 +113,16 @@ impl PluginServer for Module { ready: msgs .into_iter() .map(|mut op| { - UpdateHook::new( - &self.l2_chain_id, - &ClientType::new(self.state_lens_client_type.clone()), - |fetch| { - Call::Plugin(PluginMessage::new( - self.plugin_name(), - ModuleCall::from(FetchUpdate { - counterparty_chain_id: fetch.counterparty_chain_id.clone(), - update_from: fetch.update_from, - update_to: fetch.update_to, - }), - )) - }, - ) + UpdateHook::new(&self.l2_chain_id, &self.state_lens_client_type, |fetch| { + Call::Plugin(PluginMessage::new( + self.plugin_name(), + ModuleCall::from(FetchUpdate { + counterparty_chain_id: fetch.counterparty_chain_id.clone(), + update_from: fetch.update_from, + update_to: fetch.update_to, + }), + )) + }) .visit_op(&mut op); op @@ -236,11 +232,13 @@ impl PluginServer for Module { .await?; // The client has been updated to at least update_to let update_to = l1_client_meta.counterparty_height; - debug!("l0 client meta {:#?}", l0_client_meta); + debug!("l0 client meta {:?}", l0_client_meta); + let l2_consensus_state_path = ConsensusStatePath { client_id: self.l1_client_id, height: update_to.height(), }; + let l2_consensus_state = voy_client .query_ibc_state( self.l1_chain_id.clone(), @@ -249,20 +247,33 @@ impl PluginServer for Module { ) .await? .state; - debug!("l2 consensus state {:#?}", l2_consensus_state); - let l2_consensus_state_proof = serde_json::from_value::( - voy_client - .query_ibc_proof( - self.l1_chain_id.clone(), - QueryHeight::Specific(l1_latest_height), - l2_consensus_state_path, - ) - .await - .expect("big trouble") - .proof, - ) - .expect("impossible"); - debug!("l2 consensus state proof {:#?}", l2_consensus_state_proof); + + debug!("l2 consensus state {:?}", l2_consensus_state); + + let l2_consensus_state_proof = voy_client + .query_ibc_proof( + self.l1_chain_id.clone(), + QueryHeight::Specific(l1_latest_height), + l2_consensus_state_path, + ) + .await + .expect("big trouble") + .proof; + + // let state_lens_client_type = voy_client + // .client_info(counterparty_chain_id, l1_client_meta) + // .await?; + + let l2_consensus_state_proof_bytes = voy_client + .encode_proof::( + self.state_lens_client_type.clone(), + todo!(), + l2_consensus_state_proof, + ) + .await?; + + debug!("l2 consensus state proof {:?}", l2_consensus_state_proof); + // Dispatch an update for the L1 on the destination, then dispatch the L2 update on the destination Ok(conc([ promise( @@ -294,7 +305,7 @@ impl PluginServer for Module { into_value(Header { l1_height: l1_latest_height, l2_height: update_to, - l2_consensus_state_proof, + l2_consensus_state_proof: l2_consensus_state_proof_bytes, l2_consensus_state, }), )], From fdc287c23ea7596f66c88069569e82a42b90c708 Mon Sep 17 00:00:00 2001 From: aeryz Date: Thu, 9 Jan 2025 11:45:15 +0300 Subject: [PATCH 3/3] chore(voyager): have a unified state lens update client Signed-off-by: aeryz --- Cargo.lock | 38 +-- Cargo.toml | 6 +- lib/state-lens-light-client-types/Cargo.toml | 8 +- .../state-lens/{evm => }/Cargo.toml | 9 +- .../state-lens/ics23-ics23/Cargo.toml | 29 -- .../state-lens/ics23-ics23/src/call.rs | 25 -- .../state-lens/ics23-ics23/src/callback.rs | 6 - .../state-lens/ics23-ics23/src/data.rs | 4 - .../state-lens/ics23-ics23/src/main.rs | 311 ------------------ .../state-lens/{evm => }/src/call.rs | 0 .../state-lens/{evm => }/src/callback.rs | 0 .../state-lens/{evm => }/src/data.rs | 0 .../state-lens/{evm => }/src/main.rs | 12 +- 13 files changed, 15 insertions(+), 433 deletions(-) rename voyager/plugins/client-update/state-lens/{evm => }/Cargo.toml (72%) delete mode 100644 voyager/plugins/client-update/state-lens/ics23-ics23/Cargo.toml delete mode 100644 voyager/plugins/client-update/state-lens/ics23-ics23/src/call.rs delete mode 100644 voyager/plugins/client-update/state-lens/ics23-ics23/src/callback.rs delete mode 100644 voyager/plugins/client-update/state-lens/ics23-ics23/src/data.rs delete mode 100644 voyager/plugins/client-update/state-lens/ics23-ics23/src/main.rs rename voyager/plugins/client-update/state-lens/{evm => }/src/call.rs (100%) rename voyager/plugins/client-update/state-lens/{evm => }/src/callback.rs (100%) rename voyager/plugins/client-update/state-lens/{evm => }/src/data.rs (100%) rename voyager/plugins/client-update/state-lens/{evm => }/src/main.rs (98%) diff --git a/Cargo.lock b/Cargo.lock index 6bc1964cca..ed3ff9fd40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13353,55 +13353,19 @@ dependencies = [ ] [[package]] -name = "voyager-client-update-plugin-state-lens-evm" +name = "voyager-client-update-plugin-state-lens" version = "0.1.0" dependencies = [ "alloy", - "cometbft-rpc", - "cometbft-types", - "dashmap 5.5.3", "enumorph", - "futures", "ibc-union-spec", "ics23", "jsonrpsee", "macros", - "num-bigint 0.4.6", - "prost 0.12.6", "protos", "serde", "serde_json", "state-lens-light-client-types", - "thiserror", - "tokio", - "tracing", - "tracing-subscriber 0.3.18", - "unionlabs", - "voyager-message", - "voyager-vm", -] - -[[package]] -name = "voyager-client-update-plugin-state-lens-ics23-ics23" -version = "0.1.0" -dependencies = [ - "alloy", - "cometbft-rpc", - "cometbft-types", - "dashmap 5.5.3", - "enumorph", - "futures", - "ibc-union-spec", - "ics23", - "jsonrpsee", - "macros", - "num-bigint 0.4.6", - "prost 0.12.6", - "protos", - "serde", - "serde_json", - "state-lens-ics23-ics23-light-client-types", - "thiserror", "tokio", "tracing", "tracing-subscriber 0.3.18", diff --git a/Cargo.toml b/Cargo.toml index 404f545cff..2a58d11cd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -139,8 +139,7 @@ members = [ "voyager/plugins/client-update/ethereum", "voyager/plugins/client-update/movement", "voyager/plugins/client-update/tendermint", - "voyager/plugins/client-update/state-lens/evm", - "voyager/plugins/client-update/state-lens/ics23-ics23", + "voyager/plugins/client-update/state-lens", "voyager/plugins/periodic-client-update", @@ -171,7 +170,8 @@ members = [ "mpc/coordinator", "lib/ibc-union-spec", - "lib/ibc-classic-spec", "lib/state-lens-light-client-types", + "lib/ibc-classic-spec", + "lib/state-lens-light-client-types", ] [workspace.package] diff --git a/lib/state-lens-light-client-types/Cargo.toml b/lib/state-lens-light-client-types/Cargo.toml index 8fa7736cff..6d50cc8ebe 100644 --- a/lib/state-lens-light-client-types/Cargo.toml +++ b/lib/state-lens-light-client-types/Cargo.toml @@ -1,9 +1,9 @@ [package] -name = "state-lens-light-client-types" -version = "0.1.0" -edition.workspace = true +edition.workspace = true license-file.workspace = true -repository.workspace = true +name = "state-lens-light-client-types" +repository.workspace = true +version = "0.1.0" [dependencies] alloy = { workspace = true, features = ["sol-types"], optional = true } diff --git a/voyager/plugins/client-update/state-lens/evm/Cargo.toml b/voyager/plugins/client-update/state-lens/Cargo.toml similarity index 72% rename from voyager/plugins/client-update/state-lens/evm/Cargo.toml rename to voyager/plugins/client-update/state-lens/Cargo.toml index a99c3bffff..8f4a300953 100644 --- a/voyager/plugins/client-update/state-lens/evm/Cargo.toml +++ b/voyager/plugins/client-update/state-lens/Cargo.toml @@ -1,26 +1,19 @@ [package] edition = "2021" -name = "voyager-client-update-plugin-state-lens-evm" +name = "voyager-client-update-plugin-state-lens" version = "0.1.0" [dependencies] alloy = { workspace = true, features = ["rpc", "rpc-types", "transports", "transport-http", "transport-ws", "reqwest", "provider-ws"] } -cometbft-rpc = { workspace = true } -cometbft-types = { workspace = true } -dashmap = { workspace = true } enumorph = { workspace = true } -futures = { workspace = true } ibc-union-spec = { workspace = true } ics23 = { workspace = true } jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } macros = { workspace = true } -num-bigint = { workspace = true } -prost = { workspace = true } protos = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } state-lens-light-client-types = { workspace = true, features = ["serde"] } -thiserror = { workspace = true } tokio = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true } diff --git a/voyager/plugins/client-update/state-lens/ics23-ics23/Cargo.toml b/voyager/plugins/client-update/state-lens/ics23-ics23/Cargo.toml deleted file mode 100644 index 8827b42c43..0000000000 --- a/voyager/plugins/client-update/state-lens/ics23-ics23/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -edition = "2021" -name = "voyager-client-update-plugin-state-lens-ics23-ics23" -version = "0.1.0" - -[dependencies] -alloy = { workspace = true, features = ["rpc", "rpc-types", "transports", "transport-http", "transport-ws", "reqwest", "provider-ws"] } -cometbft-rpc = { workspace = true } -cometbft-types.workspace = true -dashmap = { workspace = true } -enumorph = { workspace = true } -futures = { workspace = true } -ibc-union-spec.workspace = true -ics23 = { workspace = true } -jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } -macros = { workspace = true } -num-bigint = { workspace = true } -prost = { workspace = true } -protos = { workspace = true } -serde = { workspace = true, features = ["derive"] } -serde_json = { workspace = true } -state-lens-ics23-ics23-light-client-types = { workspace = true, features = ["serde"] } -thiserror = { workspace = true } -tokio = { workspace = true } -tracing = { workspace = true } -tracing-subscriber = { workspace = true } -unionlabs = { workspace = true } -voyager-message = { workspace = true } -voyager-vm = { workspace = true } diff --git a/voyager/plugins/client-update/state-lens/ics23-ics23/src/call.rs b/voyager/plugins/client-update/state-lens/ics23-ics23/src/call.rs deleted file mode 100644 index 3d9897aafd..0000000000 --- a/voyager/plugins/client-update/state-lens/ics23-ics23/src/call.rs +++ /dev/null @@ -1,25 +0,0 @@ -use enumorph::Enumorph; -use macros::model; -use unionlabs::ibc::core::client::height::Height; -use voyager_message::core::ChainId; - -#[model] -#[derive(Enumorph)] -pub enum ModuleCall { - FetchUpdate(FetchUpdate), - FetchUpdateAfterL1Update(FetchUpdateAfterL1Update), -} - -#[model] -pub struct FetchUpdate { - pub counterparty_chain_id: ChainId, - pub update_from: Height, - pub update_to: Height, -} - -#[model] -pub struct FetchUpdateAfterL1Update { - pub counterparty_chain_id: ChainId, - pub update_from: Height, - pub update_to: Height, -} diff --git a/voyager/plugins/client-update/state-lens/ics23-ics23/src/callback.rs b/voyager/plugins/client-update/state-lens/ics23-ics23/src/callback.rs deleted file mode 100644 index a332e95f9a..0000000000 --- a/voyager/plugins/client-update/state-lens/ics23-ics23/src/callback.rs +++ /dev/null @@ -1,6 +0,0 @@ -use enumorph::Enumorph; -use macros::model; - -#[model] -#[derive(Enumorph)] -pub enum ModuleCallback {} diff --git a/voyager/plugins/client-update/state-lens/ics23-ics23/src/data.rs b/voyager/plugins/client-update/state-lens/ics23-ics23/src/data.rs deleted file mode 100644 index f52f66d6b6..0000000000 --- a/voyager/plugins/client-update/state-lens/ics23-ics23/src/data.rs +++ /dev/null @@ -1,4 +0,0 @@ -use macros::model; - -#[model] -pub enum ModuleData {} diff --git a/voyager/plugins/client-update/state-lens/ics23-ics23/src/main.rs b/voyager/plugins/client-update/state-lens/ics23-ics23/src/main.rs deleted file mode 100644 index 1bf6c303cf..0000000000 --- a/voyager/plugins/client-update/state-lens/ics23-ics23/src/main.rs +++ /dev/null @@ -1,311 +0,0 @@ -use std::{collections::VecDeque, fmt::Debug}; - -use call::FetchUpdateAfterL1Update; -use ibc_union_spec::{ConsensusStatePath, IbcUnion}; -use jsonrpsee::{ - core::{async_trait, RpcResult}, - Extensions, -}; -use serde::{Deserialize, Serialize}; -use state_lens_ics23_ics23_light_client_types::Header; -use tracing::{debug, instrument}; -use unionlabs::ibc::core::commitment::merkle_proof::MerkleProof; -use voyager_message::{ - call::{Call, FetchUpdateHeaders, WaitForTrustedHeight}, - callback::AggregateMsgUpdateClientsFromOrderedHeaders, - core::{ChainId, ClientType, IbcSpec, QueryHeight}, - data::{Data, DecodedHeaderMeta, OrderedHeaders}, - hook::UpdateHook, - into_value, - module::{PluginInfo, PluginServer}, - DefaultCmd, ExtensionsExt, Plugin, PluginMessage, RawClientId, VoyagerClient, VoyagerMessage, -}; -use voyager_vm::{call, conc, data, pass::PassResult, promise, seq, BoxDynError, Op, Visit}; - -use crate::{ - call::{FetchUpdate, ModuleCall}, - callback::ModuleCallback, -}; - -pub mod call; -pub mod callback; - -#[tokio::main(flavor = "multi_thread")] -async fn main() { - Module::run().await -} - -#[derive(Debug, Clone)] -pub struct Module { - pub l0_client_id: u32, - pub l1_client_id: u32, - pub l1_chain_id: ChainId, - pub l2_chain_id: ChainId, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Config { - pub l0_client_id: u32, - pub l1_client_id: u32, - pub l1_chain_id: ChainId, - pub l2_chain_id: ChainId, -} - -impl Plugin for Module { - type Call = ModuleCall; - type Callback = ModuleCallback; - - type Config = Config; - type Cmd = DefaultCmd; - - async fn new(config: Self::Config) -> Result { - Ok(Self { - l0_client_id: config.l0_client_id, - l1_client_id: config.l1_client_id, - l1_chain_id: config.l1_chain_id, - l2_chain_id: config.l2_chain_id, - }) - } - - fn info(config: Self::Config) -> PluginInfo { - PluginInfo { - name: plugin_name(&config.l2_chain_id), - interest_filter: UpdateHook::filter( - &config.l2_chain_id, - &ClientType::new(ClientType::STATE_LENS_ICS23_ICS23), - ), - } - } - - async fn cmd(_config: Self::Config, cmd: Self::Cmd) { - match cmd {} - } -} - -fn plugin_name(chain_id: &ChainId) -> String { - pub const PLUGIN_NAME: &str = env!("CARGO_PKG_NAME"); - - format!("{PLUGIN_NAME}/{}", chain_id) -} - -impl Module { - fn plugin_name(&self) -> String { - plugin_name(&self.l2_chain_id) - } -} - -#[async_trait] -impl PluginServer for Module { - #[instrument(skip_all, fields(chain_id = %self.l2_chain_id))] - async fn run_pass( - &self, - _: &Extensions, - msgs: Vec>, - ) -> RpcResult> { - Ok(PassResult { - optimize_further: vec![], - ready: msgs - .into_iter() - .map(|mut op| { - UpdateHook::new( - &self.l2_chain_id, - &ClientType::new(ClientType::STATE_LENS_ICS23_ICS23), - |fetch| { - Call::Plugin(PluginMessage::new( - self.plugin_name(), - ModuleCall::from(FetchUpdate { - counterparty_chain_id: fetch.counterparty_chain_id.clone(), - update_from: fetch.update_from, - update_to: fetch.update_to, - }), - )) - }, - ) - .visit_op(&mut op); - - op - }) - .enumerate() - .map(|(i, op)| (vec![i], op)) - .collect(), - }) - } - - #[instrument(skip_all, fields(chain_id = %self.l2_chain_id))] - async fn call(&self, ext: &Extensions, msg: ModuleCall) -> RpcResult> { - match msg { - ModuleCall::FetchUpdate(FetchUpdate { - counterparty_chain_id, - update_from, - update_to, - }) => { - let voy_client = ext.try_get::()?; - let l1_latest_height = voy_client - .query_latest_height(self.l1_chain_id.clone(), true) - .await?; - let l2_consensus_state_proof = serde_json::from_value::( - voy_client - .query_ibc_proof( - self.l1_chain_id.clone(), - QueryHeight::Specific(l1_latest_height), - ConsensusStatePath { - client_id: self.l1_client_id, - height: update_to.height(), - }, - ) - .await - .expect("big trouble") - .proof, - ) - .expect("impossible"); - let l2_merkle_proof = unionlabs::union::ics23::merkle_proof::MerkleProof::try_from( - protos::ibc::core::commitment::v1::MerkleProof::from(l2_consensus_state_proof), - ) - .expect("impossible"); - let continuation = call(PluginMessage::new( - self.plugin_name(), - ModuleCall::from(FetchUpdateAfterL1Update { - counterparty_chain_id, - update_from, - update_to, - }), - )); - // If the L2 consensus proof exists on the L1, we don't have to update the L2 on the L1. - match l2_merkle_proof { - unionlabs::union::ics23::merkle_proof::MerkleProof::Membership(_, _) => { - Ok(continuation) - } - _ => Ok(conc([ - // Update the L2 (tm) client on L1 (union) and then dispatch the continuation - promise( - [call(FetchUpdateHeaders { - client_type: ClientType::new(ClientType::TENDERMINT), - chain_id: self.l2_chain_id.clone(), - counterparty_chain_id: self.l1_chain_id.clone(), - update_from, - update_to, - })], - [], - AggregateMsgUpdateClientsFromOrderedHeaders { - ibc_spec_id: IbcUnion::ID, - chain_id: self.l1_chain_id.clone(), - client_id: RawClientId::new(self.l1_client_id), - }, - ), - seq([ - call(WaitForTrustedHeight { - chain_id: self.l1_chain_id.clone(), - ibc_spec_id: IbcUnion::ID, - client_id: RawClientId::new(self.l1_client_id), - height: update_to, - finalized: true, - }), - continuation, - ]), - ])), - } - } - ModuleCall::FetchUpdateAfterL1Update(FetchUpdateAfterL1Update { - counterparty_chain_id, - .. - }) => { - let voy_client = ext.try_get::()?; - let l1_latest_height = voy_client - .query_latest_height(self.l1_chain_id.clone(), false) - .await?; - debug!("l1 latest height {}", l1_latest_height); - let l0_client_meta = voy_client - .client_meta::( - counterparty_chain_id.clone(), - QueryHeight::Latest, - self.l0_client_id, - ) - .await?; - let l1_client_meta = voy_client - .client_meta::( - self.l1_chain_id.clone(), - QueryHeight::Specific(l1_latest_height), - self.l1_client_id, - ) - .await?; - // The client has been updated to at least update_to - let update_to = l1_client_meta.counterparty_height; - debug!("l0 client meta {:#?}", l0_client_meta); - let l2_consensus_state_path = ConsensusStatePath { - client_id: self.l1_client_id, - height: update_to.height(), - }; - let l2_consensus_state = voy_client - .query_ibc_state( - self.l1_chain_id.clone(), - QueryHeight::Specific(l1_latest_height), - l2_consensus_state_path.clone(), - ) - .await? - .state; - debug!("l2 consensus state {:#?}", l2_consensus_state); - let l2_consensus_state_proof = serde_json::from_value::( - voy_client - .query_ibc_proof( - self.l1_chain_id.clone(), - QueryHeight::Specific(l1_latest_height), - l2_consensus_state_path, - ) - .await - .expect("big trouble") - .proof, - ) - .expect("impossible"); - debug!("l2 consensus state proof {:#?}", l2_consensus_state_proof); - // Dispatch an update for the L1 on the destination, then dispatch the L2 update on the destination - Ok(conc([ - promise( - [call(FetchUpdateHeaders { - client_type: ClientType::new(ClientType::COMETBLS), - chain_id: self.l1_chain_id.clone(), - counterparty_chain_id: counterparty_chain_id.clone(), - update_from: l0_client_meta.counterparty_height, - update_to: l1_latest_height, - })], - [], - AggregateMsgUpdateClientsFromOrderedHeaders { - ibc_spec_id: IbcUnion::ID, - chain_id: counterparty_chain_id.clone(), - client_id: RawClientId::new(self.l0_client_id), - }, - ), - seq([ - call(WaitForTrustedHeight { - chain_id: counterparty_chain_id, - ibc_spec_id: IbcUnion::ID, - client_id: RawClientId::new(self.l0_client_id), - height: l1_latest_height, - finalized: false, - }), - data(OrderedHeaders { - headers: vec![( - DecodedHeaderMeta { height: update_to }, - into_value(Header { - l1_height: l1_latest_height, - l2_height: update_to, - l2_consensus_state_proof, - l2_consensus_state, - }), - )], - }), - ]), - ])) - } - } - } - - #[instrument(skip_all, fields(chain_id = %self.l2_chain_id))] - async fn callback( - &self, - _: &Extensions, - callback: ModuleCallback, - _data: VecDeque, - ) -> RpcResult> { - match callback {} - } -} diff --git a/voyager/plugins/client-update/state-lens/evm/src/call.rs b/voyager/plugins/client-update/state-lens/src/call.rs similarity index 100% rename from voyager/plugins/client-update/state-lens/evm/src/call.rs rename to voyager/plugins/client-update/state-lens/src/call.rs diff --git a/voyager/plugins/client-update/state-lens/evm/src/callback.rs b/voyager/plugins/client-update/state-lens/src/callback.rs similarity index 100% rename from voyager/plugins/client-update/state-lens/evm/src/callback.rs rename to voyager/plugins/client-update/state-lens/src/callback.rs diff --git a/voyager/plugins/client-update/state-lens/evm/src/data.rs b/voyager/plugins/client-update/state-lens/src/data.rs similarity index 100% rename from voyager/plugins/client-update/state-lens/evm/src/data.rs rename to voyager/plugins/client-update/state-lens/src/data.rs diff --git a/voyager/plugins/client-update/state-lens/evm/src/main.rs b/voyager/plugins/client-update/state-lens/src/main.rs similarity index 98% rename from voyager/plugins/client-update/state-lens/evm/src/main.rs rename to voyager/plugins/client-update/state-lens/src/main.rs index c33de122a7..f92d3cc06c 100644 --- a/voyager/plugins/client-update/state-lens/evm/src/main.rs +++ b/voyager/plugins/client-update/state-lens/src/main.rs @@ -260,20 +260,20 @@ impl PluginServer for Module { .expect("big trouble") .proof; - // let state_lens_client_type = voy_client - // .client_info(counterparty_chain_id, l1_client_meta) - // .await?; + let state_lens_client = voy_client + .client_info::(counterparty_chain_id.clone(), self.l0_client_id) + .await?; + + debug!("l2 consensus state proof {:?}", l2_consensus_state_proof); let l2_consensus_state_proof_bytes = voy_client .encode_proof::( self.state_lens_client_type.clone(), - todo!(), + state_lens_client.ibc_interface, l2_consensus_state_proof, ) .await?; - debug!("l2 consensus state proof {:?}", l2_consensus_state_proof); - // Dispatch an update for the L1 on the destination, then dispatch the L2 update on the destination Ok(conc([ promise(