Skip to content

Commit

Permalink
solana-ibc: introduce ClientStateUpdate event (#315)
Browse files Browse the repository at this point in the history
Introduce ClientStateUpdate event which is emitted when client state
is updated and includes the updated serialised client state.

---------

Co-authored-by: Michal Nazarewicz <mina86@mina86.com>
  • Loading branch information
dhruvja and mina86 authored May 5, 2024
1 parent 42251bf commit 3882ee9
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 14 deletions.
2 changes: 1 addition & 1 deletion solana/solana-ibc/programs/solana-ibc/src/client_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ impl cf_guest::CommonContext<sigverify::ed25519::PubKey>
client_id: &ibc::ClientId,
state: Self::AnyClientState,
) -> Result<()> {
Self::set_client_state(self, client_id, state)
self.store_client_state_impl(client_id, state)
}

fn consensus_state(
Expand Down
32 changes: 32 additions & 0 deletions solana/solana-ibc/programs/solana-ibc/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub enum Event<'a> {
NewBlock(NewBlock<'a>),
BlockSigned(BlockSigned),
BlockFinalised(BlockFinalised),
ClientStateUpdate(ClientStateUpdate<'a>),
}

/// Event emitted once blockchain is implemented.
Expand Down Expand Up @@ -112,6 +113,24 @@ pub struct BlockFinalised {
pub block_height: guestchain::BlockHeight,
}

/// Event emitted each time IBC client state is updated.
#[derive(
Clone,
Debug,
PartialEq,
Eq,
borsh::BorshSerialize,
borsh::BorshDeserialize,
derive_more::From,
)]
pub struct ClientStateUpdate<'a> {
/// Client identifier which got updated.
pub client_id: CowClientId<'a>,

/// Borsh-serialised [`crate::client_state::AnyClientState`].
pub state: alloc::borrow::Cow<'a, [u8]>,
}

impl Event<'_> {
pub fn emit(&self) -> Result<(), String> {
borsh::BorshSerialize::try_to_vec(self)
Expand Down Expand Up @@ -205,6 +224,19 @@ macro_rules! impl_cow {
impl_cow!(header: BlockHeader, CowHeader, BoxedHeader);
impl_cow!(epoch: Epoch, CowEpoch, BoxedEpoch);

pub type CowClientId<'a> = alloc::borrow::Cow<'a, crate::ibc::ClientId>;

#[inline]
pub fn client_id(value: &crate::ibc::ClientId) -> CowClientId {
alloc::borrow::Cow::Borrowed(value)
}

#[inline]
pub fn bytes(value: &[u8]) -> alloc::borrow::Cow<'_, [u8]> {
alloc::borrow::Cow::Borrowed(value)
}


#[cfg(test)]
// insta uses open to read the snapshot file which is not available when running
// through Miri.
Expand Down
21 changes: 15 additions & 6 deletions solana/solana-ibc/programs/solana-ibc/src/execution_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use lib::hash::CryptoHash;

use crate::client_state::AnyClientState;
use crate::consensus_state::AnyConsensusState;
use crate::ibc;
use crate::storage::{self, IbcStorage};
use crate::{events, ibc};

type Result<T = (), E = ibc::ContextError> = core::result::Result<T, E>;

Expand All @@ -19,7 +19,8 @@ impl ibc::ClientExecutionContext for IbcStorage<'_, '_> {
path: ibc::path::ClientStatePath,
state: Self::AnyClientState,
) -> Result {
self.set_client_state(&path.0, state).map_err(ibc::ContextError::from)
self.store_client_state_impl(&path.0, state)
.map_err(ibc::ContextError::from)
}

fn store_consensus_state(
Expand Down Expand Up @@ -78,7 +79,7 @@ impl IbcStorage<'_, '_> {
height: ibc::Height,
state: AnyConsensusState,
) -> Result<(), ibc::ClientError> {
msg!("store_consensus_state({}, {:?})", client_id, state);
msg!("store_consensus_state({})", client_id);
let mut store = self.borrow_mut();
let (processed_time, processed_height) = {
let head = store.chain.head()?;
Expand Down Expand Up @@ -288,7 +289,7 @@ impl ibc::ExecutionContext for IbcStorage<'_, '_> {
}

fn emit_ibc_event(&mut self, event: ibc::IbcEvent) -> Result {
crate::events::emit(event).map_err(ctx_error)
events::emit(event).map_err(ctx_error)
}

fn log_message(&mut self, message: String) -> Result {
Expand All @@ -300,15 +301,23 @@ impl ibc::ExecutionContext for IbcStorage<'_, '_> {
}

impl storage::IbcStorage<'_, '_> {
pub(crate) fn set_client_state(
pub(crate) fn store_client_state_impl(
&mut self,
client_id: &ibc::ClientId,
state: AnyClientState,
) -> Result<(), ibc::ClientError> {
msg!("store_client_state({}, {:?})", client_id, state);
msg!("store_client_state({})", client_id);
let mut store = self.borrow_mut();

let mut client = store.private.client_mut(client_id, true)?;
client.client_state.set(&state)?;

events::emit(events::ClientStateUpdate {
client_id: events::client_id(client_id),
state: events::bytes(client.client_state.as_bytes()),
})
.map_err(client_error)?;

let state_any = state.encode_vec();
let hash =
cf_guest::digest_with_client_id(client_id, state_any.as_slice());
Expand Down
7 changes: 0 additions & 7 deletions solana/solana-ibc/programs/solana-ibc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,13 +371,6 @@ pub mod solana_ibc {
.map_err(error::Error::ContextError)
.map_err(move |err| error!((&err)))?;

// Log client state only when it is updated which is when `UpdateClient` message
// sent.
if ctx.remaining_accounts.split_last().is_some() {
let storage = &store.borrow().private;
let client_state = &storage.clients[0].client_state;
msg!("This is updated client state {:?}", client_state.as_bytes());
}
Ok(())
}

Expand Down

0 comments on commit 3882ee9

Please sign in to comment.