From 13be90db829ac32433de1738673e4edd457f4a44 Mon Sep 17 00:00:00 2001 From: Dhruv D Jain Date: Wed, 16 Oct 2024 00:14:39 +0530 Subject: [PATCH] solana-ibc: add guest client and consensus states (#390) Adding guest client and consensus states so that the solana-ibc on the rollup can store them. The guest client and consensus state was previous removed since we used to store the wasm wrapped guest states. It was removed here https://github.com/ComposableFi/emulated-light-client/pull/255 and now its added again. --- .../programs/solana-ibc/src/client_state.rs | 66 +++++++++++++------ .../solana-ibc/src/client_state/impls.rs | 12 ++++ .../solana-ibc/src/consensus_state.rs | 39 +++++------ 3 files changed, 74 insertions(+), 43 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/client_state.rs b/solana/solana-ibc/programs/solana-ibc/src/client_state.rs index 9b10c32a..9b3970f0 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/client_state.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/client_state.rs @@ -15,6 +15,7 @@ pub enum AnyClientState { Tendermint(ibc::tm::ClientState), Wasm(ibc::wasm::ClientState), Rollup(cf_solana::ClientState), + Guest(cf_guest::ClientState), #[cfg(any(test, feature = "mocks"))] Mock(ibc::mock::MockClientState), } @@ -28,6 +29,7 @@ enum AnyClientStateTag { Tendermint = 0, Wasm = 1, Rollup = 2, + Guest = 3, #[cfg(any(test, feature = "mocks"))] Mock = 255, } @@ -40,6 +42,7 @@ impl AnyClientStateTag { AnyClientState::TENDERMINT_TYPE => Some(Self::Tendermint), AnyClientState::WASM_TYPE => Some(Self::Wasm), AnyClientState::ROLLUP_TYPE => Some(Self::Rollup), + AnyClientState::GUEST_TYPE => Some(Self::Guest), #[cfg(any(test, feature = "mocks"))] AnyClientState::MOCK_TYPE => Some(Self::Mock), _ => None, @@ -56,6 +59,8 @@ impl AnyClientState { /// Protobuf type URL for Rollup client state used in Any message. const ROLLUP_TYPE: &'static str = cf_solana::proto::ClientState::IBC_TYPE_URL; + /// Protobuf type URL for Guest client state used in Any message. + const GUEST_TYPE: &'static str = cf_guest::proto::ClientState::IBC_TYPE_URL; #[cfg(any(test, feature = "mocks"))] /// Protobuf type URL for Mock client state used in Any message. const MOCK_TYPE: &'static str = ibc::mock::MOCK_CLIENT_STATE_TYPE_URL; @@ -89,6 +94,11 @@ impl AnyClientState { Self::ROLLUP_TYPE, Protobuf::::encode_vec(state), ), + Self::Guest(state) => ( + AnyClientStateTag::Guest, + Self::GUEST_TYPE, + Protobuf::::encode_vec(state), + ), #[cfg(any(test, feature = "mocks"))] Self::Mock(state) => ( AnyClientStateTag::Mock, @@ -119,6 +129,11 @@ impl AnyClientState { .map_err(|err| err.to_string()) .map(Self::Rollup) } + AnyClientStateTag::Guest => { + Protobuf::::decode_vec(&value) + .map_err(|err| err.to_string()) + .map(Self::Guest) + } #[cfg(any(test, feature = "mocks"))] AnyClientStateTag::Mock => { Protobuf::::decode_vec(&value) @@ -135,21 +150,6 @@ impl From for AnyClientState { } } -impl From> - for AnyClientState -{ - fn from(state: cf_guest::ClientState) -> Self { - Self::from(ibc::wasm::ClientState { - data: prost::Message::encode_to_vec(&cf_guest::proto::Any::from( - &state, - )), - checksum: Default::default(), - latest_height: ibc::Height::new(1, u64::from(state.latest_height)) - .unwrap(), - }) - } -} - impl From for ibc::Any { fn from(value: AnyClientState) -> Self { let (_, type_url, value) = value.into_any(); @@ -231,11 +231,30 @@ impl ibc::tm::CommonContext for IbcStorage<'_, '_> { impl cf_guest::CommonContext for IbcStorage<'_, '_> { - type ConversionError = cf_guest::DecodeError; + type ConversionError = &'static str; type AnyClientState = AnyClientState; type AnyConsensusState = AnyConsensusState; fn host_metadata(&self) -> Result<(ibc::Timestamp, ibc::Height)> { + #[cfg(feature = "witness")] + { + let clock = + anchor_lang::solana_program::sysvar::clock::Clock::get() + .map_err(|e| ibc::ClientError::ClientSpecific { + description: e.to_string(), + })?; + + let slot = clock.slot; + let timestamp_sec = clock.unix_timestamp as u64; + + let timestamp = + ibc::Timestamp::from_nanoseconds(timestamp_sec * 10u64.pow(9)) + .map_err(|e| ibc::ClientError::ClientSpecific { + description: e.to_string(), + })?; + let height = ibc::Height::new(1, slot)?; + return Ok((timestamp, height)); + } let timestamp = self.borrow().chain.head()?.timestamp_ns.get(); let timestamp = ibc::Timestamp::from_nanoseconds(timestamp).map_err(|err| { @@ -331,11 +350,18 @@ impl cf_guest::CommonContext impl guestchain::Verifier for IbcStorage<'_, '_> { fn verify( &self, - _message: &[u8], - _pubkey: &sigverify::ed25519::PubKey, - _signature: &sigverify::ed25519::Signature, + message: &[u8], + pubkey: &sigverify::ed25519::PubKey, + signature: &sigverify::ed25519::Signature, ) -> bool { - unimplemented!() + let pubkey = pubkey.as_ref(); + let sig = signature.as_ref(); + if let Some(verifier) = crate::global().verifier() { + if verifier.verify(message, pubkey, sig).unwrap_or(false) { + return true; + } + } + false } } diff --git a/solana/solana-ibc/programs/solana-ibc/src/client_state/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/client_state/impls.rs index 01a8bb30..b9524102 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/client_state/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/client_state/impls.rs @@ -19,6 +19,7 @@ macro_rules! delegate { AnyClientState::Tendermint(cs) => cs.$name($($arg),*), AnyClientState::Wasm(_) => unimplemented!(), AnyClientState::Rollup(cs) => cs.$name($($arg),*), + AnyClientState::Guest(cs) => cs.$name($($arg),*), #[cfg(any(test, feature = "mocks"))] AnyClientState::Mock(cs) => cs.$name($($arg),*), } @@ -55,6 +56,7 @@ impl ibc::ClientStateCommon for AnyClientState { } AnyClientState::Wasm(_) => unimplemented!(), AnyClientState::Rollup(_) => unimplemented!(), + AnyClientState::Guest(_) => unimplemented!(), #[cfg(any(test, feature = "mocks"))] AnyClientState::Mock(cs) => cs.verify_upgrade_client( upgraded_client_state, @@ -89,6 +91,9 @@ impl ibc::ClientStateCommon for AnyClientState { AnyClientState::Rollup(cs) => { cs.verify_membership(prefix, proof, root, path, value) } + AnyClientState::Guest(cs) => { + cs.verify_membership(prefix, proof, root, path, value) + } #[cfg(any(test, feature = "mocks"))] AnyClientState::Mock(cs) => { cs.verify_membership(prefix, proof, root, path, value) @@ -115,6 +120,9 @@ impl ibc::ClientStateCommon for AnyClientState { AnyClientState::Rollup(cs) => { cs.verify_non_membership(prefix, proof, root, path) } + AnyClientState::Guest(cs) => { + cs.verify_non_membership(prefix, proof, root, path) + } #[cfg(any(test, feature = "mocks"))] AnyClientState::Mock(cs) => { cs.verify_non_membership(prefix, proof, root, path) @@ -143,6 +151,9 @@ impl<'a, 'b> ibc::ClientStateValidation> for AnyClientState { AnyClientState::Rollup(cs) => { cs.verify_client_message(ctx, client_id, client_message) } + AnyClientState::Guest(cs) => { + cs.verify_client_message(ctx, client_id, client_message) + } #[cfg(any(test, feature = "mocks"))] AnyClientState::Mock(cs) => { cs.verify_client_message(ctx, client_id, client_message) @@ -167,6 +178,7 @@ impl<'a, 'b> ibc::ClientStateValidation> for AnyClientState { } AnyClientState::Wasm(_) => unimplemented!(), AnyClientState::Rollup(_) => unimplemented!(), + AnyClientState::Guest(_) => unimplemented!(), #[cfg(any(test, feature = "mocks"))] AnyClientState::Mock(_) => unimplemented!(), } diff --git a/solana/solana-ibc/programs/solana-ibc/src/consensus_state.rs b/solana/solana-ibc/programs/solana-ibc/src/consensus_state.rs index 17a5bd55..ffc7bfb9 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/consensus_state.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/consensus_state.rs @@ -16,6 +16,7 @@ pub enum AnyConsensusState { Tendermint(ibc::tm::ConsensusState), Wasm(ibc::wasm::ConsensusState), Rollup(cf_solana::ConsensusState), + Guest(cf_guest::ConsensusState), #[cfg(any(test, feature = "mocks"))] Mock(ibc::mock::MockConsensusState), } @@ -27,6 +28,7 @@ enum AnyConsensusStateTag { Tendermint = 0, Wasm = 1, Rollup = 2, + Guest = 3, #[cfg(any(test, feature = "mocks"))] Mock = 255, } @@ -39,6 +41,7 @@ impl AnyConsensusStateTag { AnyConsensusState::TENDERMINT_TYPE => Some(Self::Tendermint), AnyConsensusState::WASM_TYPE => Some(Self::Wasm), AnyConsensusState::ROLLUP_TYPE => Some(Self::Rollup), + AnyConsensusState::GUEST_TYPE => Some(Self::Guest), #[cfg(any(test, feature = "mocks"))] AnyConsensusState::MOCK_TYPE => Some(Self::Mock), _ => None, @@ -55,6 +58,9 @@ impl AnyConsensusState { /// Protobuf type URL for Rollup consensus state used in Any message. const ROLLUP_TYPE: &'static str = cf_solana::proto::ConsensusState::IBC_TYPE_URL; + /// Protobuf type URL for Guest consensus state used in Any message. + const GUEST_TYPE: &'static str = + cf_guest::proto::ConsensusState::IBC_TYPE_URL; #[cfg(any(test, feature = "mocks"))] /// Protobuf type URL for Mock consensus state used in Any message. const MOCK_TYPE: &'static str = ibc::mock::MOCK_CONSENSUS_STATE_TYPE_URL; @@ -88,6 +94,11 @@ impl AnyConsensusState { Self::ROLLUP_TYPE, Protobuf::::encode_vec(state), ), + AnyConsensusState::Guest(state) => ( + AnyConsensusStateTag::Guest, + Self::GUEST_TYPE, + Protobuf::::encode_vec(state), + ), #[cfg(any(test, feature = "mocks"))] AnyConsensusState::Mock(state) => ( AnyConsensusStateTag::Mock, @@ -118,6 +129,11 @@ impl AnyConsensusState { .map_err(|err| err.to_string()) .map(Self::Rollup) } + AnyConsensusStateTag::Guest => { + Protobuf::::decode_vec(&value) + .map_err(|err| err.to_string()) + .map(Self::Guest) + } #[cfg(any(test, feature = "mocks"))] AnyConsensusStateTag::Mock => { Protobuf::::decode_vec(&value) @@ -128,35 +144,12 @@ impl AnyConsensusState { } } - impl From for AnyConsensusState { fn from(state: ibc::tm::types::ConsensusState) -> Self { Self::Tendermint(state.into()) } } -impl From for AnyConsensusState { - fn from(state: cf_guest::ConsensusState) -> Self { - Self::from(ibc::wasm::ConsensusState { - data: prost::Message::encode_to_vec(&cf_guest::proto::Any::from( - &state, - )), - timestamp_ns: state.timestamp_ns.get(), - }) - } -} - -impl TryFrom for cf_guest::ConsensusState { - type Error = cf_guest::DecodeError; - fn try_from(state: AnyConsensusState) -> Result { - use prost::Message; - let state = ibc::wasm::ConsensusState::try_from(state) - .map_err(|_| cf_guest::DecodeError::BadMessage)?; - let any = cf_guest::proto::Any::decode(state.data.as_slice())?; - cf_guest::ConsensusState::try_from(any) - } -} - impl Protobuf for AnyConsensusState {} impl TryFrom for AnyConsensusState {