From b1d7b5f4f93d1c38d69f54466da5313f5374ade0 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Tue, 17 Oct 2023 21:49:36 +0530 Subject: [PATCH 01/12] added trie as attribute to context --- .../solana-ibc/programs/solana-ibc/Cargo.toml | 5 + .../programs/solana-ibc/src/client_state.rs | 10 +- .../solana-ibc/src/execution_context.rs | 4 +- .../solana-ibc/programs/solana-ibc/src/lib.rs | 170 +++++++-- .../programs/solana-ibc/src/tests.rs | 13 +- .../programs/solana-ibc/src/transfer/impls.rs | 4 +- .../programs/solana-ibc/src/trie.rs | 329 ++++++++++++++++++ .../solana-ibc/src/validation_context.rs | 2 +- 8 files changed, 486 insertions(+), 51 deletions(-) create mode 100644 solana/solana-ibc/programs/solana-ibc/src/trie.rs diff --git a/solana/solana-ibc/programs/solana-ibc/Cargo.toml b/solana/solana-ibc/programs/solana-ibc/Cargo.toml index bb4690d7..079a5bfd 100644 --- a/solana/solana-ibc/programs/solana-ibc/Cargo.toml +++ b/solana/solana-ibc/programs/solana-ibc/Cargo.toml @@ -23,6 +23,11 @@ ibc-proto.workspace = true serde.workspace = true serde_json.workspace = true +lib.workspace = true +memory.workspace = true +sealable-trie.workspace = true +stdx.workspace = true + [dev-dependencies] anchor-client.workspace = true anyhow.workspace = true 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 35d855b4..1bf571e9 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/client_state.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/client_state.rs @@ -82,7 +82,7 @@ impl From for Any { } } -impl ClientStateValidation for AnyClientState { +impl ClientStateValidation> for AnyClientState { fn verify_client_message( &self, ctx: &SolanaIbcStorage, @@ -283,7 +283,7 @@ impl From for AnyClientState { fn from(value: MockClientState) -> Self { AnyClientState::Mock(value) } } -impl ClientStateExecution for AnyClientState { +impl ClientStateExecution> for AnyClientState { fn initialise( &self, ctx: &mut SolanaIbcStorage, @@ -371,7 +371,7 @@ impl ClientStateExecution for AnyClientState { } } -impl ibc::clients::ics07_tendermint::CommonContext for SolanaIbcStorage { +impl ibc::clients::ics07_tendermint::CommonContext for SolanaIbcStorage<'_, '_> { type ConversionError = ClientError; type AnyConsensusState = AnyConsensusState; @@ -385,7 +385,7 @@ impl ibc::clients::ics07_tendermint::CommonContext for SolanaIbcStorage { } #[cfg(any(test, feature = "mocks"))] -impl MockClientContext for SolanaIbcStorage { +impl MockClientContext for SolanaIbcStorage<'_, '_> { type ConversionError = ClientError; type AnyConsensusState = AnyConsensusState; @@ -401,7 +401,7 @@ impl MockClientContext for SolanaIbcStorage { } } -impl ibc::clients::ics07_tendermint::ValidationContext for SolanaIbcStorage { +impl ibc::clients::ics07_tendermint::ValidationContext for SolanaIbcStorage<'_, '_> { fn host_timestamp(&self) -> Result { ValidationContext::host_timestamp(self) } diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index bdfb21a4..0e464205 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -31,7 +31,7 @@ use crate::{ type Result = core::result::Result; -impl ClientExecutionContext for SolanaIbcStorage { +impl ClientExecutionContext for SolanaIbcStorage<'_, '_> { type ClientValidationContext = Self; type AnyClientState = AnyClientState; type AnyConsensusState = AnyConsensusState; @@ -77,7 +77,7 @@ impl ClientExecutionContext for SolanaIbcStorage { } } -impl ExecutionContext for SolanaIbcStorage { +impl ExecutionContext for SolanaIbcStorage<'_, '_> { fn increase_client_counter(&mut self) -> Result { self.client_counter.checked_add(1).unwrap(); msg!("client_counter has increased to: {}", self.client_counter); diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index b2d86651..c1973bd8 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -11,6 +11,7 @@ use ibc::core::router::{Module, ModuleId, Router}; use module_holder::ModuleHolder; const SOLANA_IBC_STORAGE_SEED: &[u8] = b"solana_ibc_storage"; +const TEST_TRIE_SEED: &[u8] = b"test_trie"; declare_id!("EnfDJsAK7BGgetnmKzBx86CsgC5kfSPcsktFCQ4YLC81"); @@ -21,9 +22,16 @@ mod module_holder; #[cfg(test)] mod tests; mod transfer; +mod trie; mod validation_context; // mod client_context; +/// Discriminants for the data stored in the accounts. +mod magic { + pub(crate) const UNINITIALISED: u32 = 0; + pub(crate) const TRIE_ROOT: u32 = 1; +} + #[anchor_lang::program] pub mod solana_ibc { use super::*; @@ -34,7 +42,8 @@ pub mod solana_ibc { ) -> Result<()> { msg!("Called deliver method"); let _sender = ctx.accounts.sender.to_account_info(); - let solana_ibc_store: &mut SolanaIbcStorage = &mut ctx.accounts.storage; + let solana_ibc_store: &SolanaIbcStorageTemp = + &ctx.accounts.storage; msg!("This is solana_ibc_store {:?}", solana_ibc_store); let all_messages = messages @@ -46,13 +55,73 @@ pub mod solana_ibc { .collect::>(); msg!("These are messages {:?}", all_messages); - let router = &mut solana_ibc_store.clone(); + + + let account = &ctx.accounts.trie; + let mut trie = trie::AccountTrie::new(account.try_borrow_mut_data()?) + .ok_or(ProgramError::InvalidAccountData)?; + + let mut solana_real_storage = SolanaIbcStorage { + height: solana_ibc_store.height, + module_holder: solana_ibc_store.module_holder.clone(), + clients: solana_ibc_store.clients.clone(), + client_id_set: solana_ibc_store.client_id_set.clone(), + client_counter: solana_ibc_store.client_counter.clone(), + client_processed_times: solana_ibc_store.client_processed_times.clone(), + client_processed_heights: solana_ibc_store.client_processed_heights.clone(), + consensus_states: solana_ibc_store.consensus_states.clone(), + client_consensus_state_height_sets: solana_ibc_store.client_consensus_state_height_sets.clone(), + connection_id_set: solana_ibc_store.connection_id_set.clone(), + connection_counter: solana_ibc_store.connection_counter.clone(), + connections: solana_ibc_store.connections.clone(), + channel_ends: solana_ibc_store.channel_ends.clone(), + connection_to_client: solana_ibc_store.connection_to_client.clone(), + port_channel_id_set: solana_ibc_store.port_channel_id_set.clone(), + channel_counter: solana_ibc_store.channel_counter.clone(), + next_sequence_send: solana_ibc_store.next_sequence_send.clone(), + next_sequence_recv: solana_ibc_store.next_sequence_recv.clone(), + next_sequence_ack: solana_ibc_store.next_sequence_ack.clone(), + packet_commitment_sequence_sets: solana_ibc_store.packet_commitment_sequence_sets.clone(), + packet_receipt_sequence_sets: solana_ibc_store.packet_receipt_sequence_sets.clone(), + packet_acknowledgement_sequence_sets: solana_ibc_store.packet_acknowledgement_sequence_sets.clone(), + ibc_events_history: solana_ibc_store.ibc_events_history.clone(), + trie: Some(trie) + }; + + let mut solana_real_storage_another = SolanaIbcStorage { + height: solana_ibc_store.height, + module_holder: solana_ibc_store.module_holder.clone(), + clients: solana_ibc_store.clients.clone(), + client_id_set: solana_ibc_store.client_id_set.clone(), + client_counter: solana_ibc_store.client_counter.clone(), + client_processed_times: solana_ibc_store.client_processed_times.clone(), + client_processed_heights: solana_ibc_store.client_processed_heights.clone(), + consensus_states: solana_ibc_store.consensus_states.clone(), + client_consensus_state_height_sets: solana_ibc_store.client_consensus_state_height_sets.clone(), + connection_id_set: solana_ibc_store.connection_id_set.clone(), + connection_counter: solana_ibc_store.connection_counter.clone(), + connections: solana_ibc_store.connections.clone(), + channel_ends: solana_ibc_store.channel_ends.clone(), + connection_to_client: solana_ibc_store.connection_to_client.clone(), + port_channel_id_set: solana_ibc_store.port_channel_id_set.clone(), + channel_counter: solana_ibc_store.channel_counter.clone(), + next_sequence_send: solana_ibc_store.next_sequence_send.clone(), + next_sequence_recv: solana_ibc_store.next_sequence_recv.clone(), + next_sequence_ack: solana_ibc_store.next_sequence_ack.clone(), + packet_commitment_sequence_sets: solana_ibc_store.packet_commitment_sequence_sets.clone(), + packet_receipt_sequence_sets: solana_ibc_store.packet_receipt_sequence_sets.clone(), + packet_acknowledgement_sequence_sets: solana_ibc_store.packet_acknowledgement_sequence_sets.clone(), + ibc_events_history: solana_ibc_store.ibc_events_history.clone(), + trie: None, + }; + + let router = &mut solana_real_storage_another; let errors = all_messages.into_iter().fold(vec![], |mut errors, msg| { match ibc::core::MsgEnvelope::try_from(msg) { Ok(msg) => { - match ibc::core::dispatch(solana_ibc_store, router, msg) + match ibc::core::dispatch(&mut solana_real_storage, router, msg) { Ok(()) => (), Err(e) => errors.push(e), @@ -68,6 +137,7 @@ pub mod solana_ibc { Ok(()) } + } #[derive(Accounts)] @@ -75,10 +145,15 @@ pub struct Deliver<'info> { #[account(mut)] pub sender: Signer<'info>, #[account(init_if_needed, payer = sender, seeds = [SOLANA_IBC_STORAGE_SEED],bump, space = 10000)] - pub storage: Account<'info, SolanaIbcStorage>, + pub storage: Account<'info, SolanaIbcStorageTemp>, + #[account(init_if_needed, payer = sender, seeds = [TEST_TRIE_SEED], bump, space = 1000)] + /// CHECK: + pub trie: AccountInfo<'info>, pub system_program: Program<'info, System>, } +pub struct MyTrie {} + #[event] pub struct EmitIBCEvent { pub ibc_event: Vec, @@ -116,7 +191,7 @@ pub type InnerConsensusState = String; // Serialized #[account] #[derive(Debug)] /// All the structs from IBC are stored as String since they dont implement AnchorSerialize and AnchorDeserialize -pub struct SolanaIbcStorage { +pub struct SolanaIbcStorageTemp { pub height: InnerHeight, /// To support the mutable borrow in `Router::get_route_mut`. pub module_holder: ModuleHolder, @@ -163,47 +238,70 @@ pub struct SolanaIbcStorage { pub ibc_events_history: BTreeMap>, } -impl SolanaIbcStorage { - pub fn new(account: Pubkey) -> Self { - SolanaIbcStorage { - height: (0, 0), - module_holder: ModuleHolder::new(account), - clients: BTreeMap::new(), - client_id_set: Vec::new(), - client_counter: 0, - client_processed_times: BTreeMap::new(), - client_processed_heights: BTreeMap::new(), - consensus_states: BTreeMap::new(), - client_consensus_state_height_sets: BTreeMap::new(), - connection_id_set: Vec::new(), - connection_counter: 0, - connections: BTreeMap::new(), - channel_ends: BTreeMap::new(), - connection_to_client: BTreeMap::new(), - port_channel_id_set: Vec::new(), - channel_counter: 0, - next_sequence_send: BTreeMap::new(), - next_sequence_recv: BTreeMap::new(), - next_sequence_ack: BTreeMap::new(), - packet_commitment_sequence_sets: BTreeMap::new(), - packet_receipt_sequence_sets: BTreeMap::new(), - packet_acknowledgement_sequence_sets: BTreeMap::new(), - ibc_events_history: BTreeMap::new(), - } - } +/// All the structs from IBC are stored as String since they dont implement AnchorSerialize and AnchorDeserialize +pub struct SolanaIbcStorage<'a, 'b> { + pub height: InnerHeight, + /// To support the mutable borrow in `Router::get_route_mut`. + pub module_holder: ModuleHolder, + pub clients: BTreeMap, + /// The client ids of the clients. + pub client_id_set: Vec, + pub client_counter: u64, + pub client_processed_times: + BTreeMap>, + pub client_processed_heights: + BTreeMap>, + pub consensus_states: + BTreeMap<(InnerClientId, InnerHeight), InnerConsensusState>, + /// This collection contains the heights corresponding to all consensus states of + /// all clients stored in the contract. + pub client_consensus_state_height_sets: + BTreeMap>, + /// The connection ids of the connections. + pub connection_id_set: Vec, + pub connection_counter: u64, + pub connections: BTreeMap, + pub channel_ends: BTreeMap<(InnerPortId, InnerChannelId), InnerChannelEnd>, + // Contains the client id corresponding to the connectionId + pub connection_to_client: BTreeMap, + /// The port and channel id tuples of the channels. + pub port_channel_id_set: Vec<(InnerPortId, InnerChannelId)>, + pub channel_counter: u64, + pub next_sequence_send: + BTreeMap<(InnerPortId, InnerChannelId), InnerSequence>, + pub next_sequence_recv: + BTreeMap<(InnerPortId, InnerChannelId), InnerSequence>, + pub next_sequence_ack: + BTreeMap<(InnerPortId, InnerChannelId), InnerSequence>, + /// The sequence numbers of the packet commitments. + pub packet_commitment_sequence_sets: + BTreeMap<(InnerPortId, InnerChannelId), Vec>, + /// The sequence numbers of the packet receipts. + pub packet_receipt_sequence_sets: + BTreeMap<(InnerPortId, InnerChannelId), Vec>, + /// The sequence numbers of the packet acknowledgements. + pub packet_acknowledgement_sequence_sets: + BTreeMap<(InnerPortId, InnerChannelId), Vec>, + /// The history of IBC events. + pub ibc_events_history: BTreeMap>, + pub trie: Option>, } pub trait SolanaIbcStorageHost { /// - fn get_solana_ibc_store(_account: Pubkey) -> SolanaIbcStorage { + fn get_solana_ibc_store( + _account: Pubkey, + ) -> SolanaIbcStorage<'static, 'static> { // Unpack the account todo!() } /// - fn set_solana_ibc_store(_store: &SolanaIbcStorage) { todo!() } + fn set_solana_ibc_store(_store: &SolanaIbcStorage) { + todo!() + } } -impl Router for SolanaIbcStorage { +impl Router for SolanaIbcStorage<'_, '_> { // fn get_route(&self, module_id: &ModuleId) -> Option<&dyn Module> { match module_id.to_string().as_str() { diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index 16ce4cff..5f25ea95 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -21,7 +21,7 @@ use ibc_proto::protobuf::Protobuf; use crate::{ accounts, instruction, AnyCheck, SolanaIbcStorage, ID, - SOLANA_IBC_STORAGE_SEED, + SOLANA_IBC_STORAGE_SEED, TEST_TRIE_SEED, }; const TYPE_URL: &str = "/ibc.core.client.v1.MsgCreateClient"; @@ -66,6 +66,8 @@ fn anchor_test_deliver() -> Result<()> { // Build, sign, and send program instruction let seeds = &[SOLANA_IBC_STORAGE_SEED]; let solana_ibc_storage = Pubkey::find_program_address(seeds, &crate::ID).0; + let trie_seeds = &[TEST_TRIE_SEED]; + let trie = Pubkey::find_program_address(trie_seeds, &crate::ID).0; let (mock_client_state, mock_cs_state) = create_mock_client_and_cs_state(); let _client_id = ClientId::new(mock_client_state.client_type(), 0).unwrap(); @@ -84,6 +86,7 @@ fn anchor_test_deliver() -> Result<()> { .accounts(accounts::Deliver { sender: authority.pubkey(), storage: solana_ibc_storage, + trie, system_program: system_program::ID, }) .args(instruction::Deliver { messages: all_messages }) @@ -96,11 +99,11 @@ fn anchor_test_deliver() -> Result<()> { println!("demo sig: {sig}"); - // Retrieve and validate state - let solana_ibc_storage_account: SolanaIbcStorage = - program.account(solana_ibc_storage).unwrap(); + // // Retrieve and validate state + // let solana_ibc_storage_account: SolanaIbcStorage = + // program.account(solana_ibc_storage).unwrap(); - println!("This is solana storage account {:?}", solana_ibc_storage_account); + // println!("This is solana storage account {:?}", solana_ibc_storage_account); Ok(()) } diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 1c8176ee..a643a718 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -125,9 +125,9 @@ impl TokenTransferValidationContext for ModuleHolder { } impl SendPacketValidationContext for ModuleHolder { - type ClientValidationContext = SolanaIbcStorage; + type ClientValidationContext = SolanaIbcStorage<'static, 'static>; - type E = SolanaIbcStorage; + type E = SolanaIbcStorage<'static, 'static>; type AnyConsensusState = AnyConsensusState; diff --git a/solana/solana-ibc/programs/solana-ibc/src/trie.rs b/solana/solana-ibc/programs/solana-ibc/src/trie.rs new file mode 100644 index 00000000..2741af37 --- /dev/null +++ b/solana/solana-ibc/programs/solana-ibc/src/trie.rs @@ -0,0 +1,329 @@ +use anchor_lang::prelude::*; + +use core::cell::RefMut; +use core::mem::ManuallyDrop; + +use lib::hash::CryptoHash; +use memory::Ptr; + +use std::result::Result; + +use crate::magic; + +type DataRef<'a, 'b> = RefMut<'a, &'b mut [u8]>; + +const SZ: usize = sealable_trie::nodes::RawNode::SIZE; + +/// Trie stored in a Solana account. +// #[account] +pub struct AccountTrie<'a, 'b>( + core::mem::ManuallyDrop>>, +); + +impl<'a, 'b> AccountTrie<'a, 'b> { + /// Creates a new Trie from data in an account. + /// + /// If the data in the account isn’t initialised (i.e. has zero + /// discriminant) initialises a new empty trie. + pub(crate) fn new(data: DataRef<'a, 'b>) -> Option { + let (alloc, root) = Allocator::new(data)?; + let trie = sealable_trie::Trie::from_parts(alloc, root.0, root.1); + Some(Self(ManuallyDrop::new(trie))) + } +} + +impl<'a, 'b> core::ops::Drop for AccountTrie<'a, 'b> { + /// Updates the header in the Solana account. + fn drop(&mut self) { + // SAFETY: Once we’re done with self.0 we are dropped and no one else is + // going to have access to self.0. + let trie = unsafe { ManuallyDrop::take(&mut self.0) }; + let (mut alloc, root_ptr, root_hash) = trie.into_parts(); + let hdr = Header { + root_ptr, + root_hash, + next_block: alloc.next_block, + first_free: alloc.first_free.map_or(0, |ptr| ptr.get()), + }; + alloc + .data + .get_mut(..Header::ENCODED_SIZE) + .unwrap() + .copy_from_slice(&hdr.encode()); + } +} + +/// Data stored in the first 72-bytes of the account describing the trie. +#[derive(Clone, Debug, PartialEq)] +struct Header { + root_ptr: Option, + root_hash: CryptoHash, + next_block: u32, + first_free: u32, +} + +impl Header { + /// Size of the encoded header. + const ENCODED_SIZE: usize = 64; + + /// Decodes the header from given block of memory. + /// + /// Returns `None` if the block is shorter than length of encoded header or + /// encoded data is invalid. + // Encoding: + // magic: u32 + // version: u32 + // root_ptr: u32 + // root_hash: [u8; 32] + // next_block: u32 + // first_free: u32 + // padding: [u8; 12], + fn decode(data: &[u8]) -> Option { + let data = data.get(..Self::ENCODED_SIZE)?.try_into().unwrap(); + + // Check magic number. Zero means the account hasn’t been initialised + // so return default value, and anything other than magic::TRIE_ROOT + // means it’s an account storing data different than a trie root. + let (magic, data) = read::<4, 60, 64, _>(data, u32::from_ne_bytes); + if magic == magic::UNINITIALISED { + return Some(Self { + root_ptr: None, + root_hash: sealable_trie::trie::EMPTY_TRIE_ROOT, + next_block: Self::ENCODED_SIZE as u32, + first_free: 0, + }); + } else if magic != magic::TRIE_ROOT { + return None; + } + + // Check version. This is for future-proofing in case format of the + // encoding changes. + let (version, data) = read::<4, 56, 60, _>(data, u32::from_ne_bytes); + if version != 0 { + return None; + } + + let (root_ptr, data) = read::<4, 52, 56, _>(data, u32::from_ne_bytes); + let (root_hash, data) = read::<32, 20, 52, _>(data, CryptoHash); + let (next_block, data) = read::<4, 16, 20, _>(data, u32::from_ne_bytes); + let (first_free, _) = read::<4, 12, 16, _>(data, u32::from_ne_bytes); + + let root_ptr = Ptr::new(root_ptr).ok()?; + Some(Self { root_ptr, root_hash, next_block, first_free }) + } + + /// Returns encoded representation of values in the header. + fn encode(&self) -> [u8; Self::ENCODED_SIZE] { + let root_ptr = + self.root_ptr.map_or([0; 4], |ptr| ptr.get().to_ne_bytes()); + + let mut buf = [0; Self::ENCODED_SIZE]; + let data = &mut buf; + let data = write::<4, 60, 64>(data, magic::TRIE_ROOT.to_ne_bytes()); + let data = write::<4, 56, 60>(data, [0; 4]); + let data = write::<4, 52, 56>(data, root_ptr); + let data = write::<32, 20, 52>(data, self.root_hash.0); + let data = write::<4, 16, 20>(data, self.next_block.to_ne_bytes()); + write::<4, 12, 16>(data, self.first_free.to_ne_bytes()); + buf + } +} + +pub struct Allocator<'a, 'b> { + /// Pool of memory to allocate blocks in. + /// + /// The data is always at least long enough to fit encoded [`Header`]. + data: DataRef<'a, 'b>, + + /// Position of the next unallocated block. + /// + /// Blocks which were allocated and then freed don’t count as ‘unallocated’ + /// in this context. This is position of the next block to return if the + /// free list is empty. + next_block: u32, + + /// Pointer to the first freed block; `None` if there were no freed blocks + /// yet. + first_free: Option, +} + +impl<'a, 'b> Allocator<'a, 'b> { + /// Initialises the allocator with data in given account. + fn new(data: DataRef<'a, 'b>) -> Option<(Self, (Option, CryptoHash))> { + let hdr = Header::decode(*data)?; + let next_block = hdr.next_block; + let first_free = Ptr::new(hdr.first_free).ok()?; + let alloc = Self { data, next_block, first_free }; + let root = (hdr.root_ptr, hdr.root_hash); + Some((alloc, root)) + } + + /// Grabs a block from a free list. Returns `None` if free list is empty. + fn alloc_from_freelist(&mut self) -> Option { + let ptr = self.first_free.take()?; + let idx = ptr.get() as usize; + let next = self.data.get(idx..idx + 4).unwrap().try_into().unwrap(); + self.first_free = Ptr::new(u32::from_ne_bytes(next)).unwrap(); + Some(ptr) + } + + /// Grabs a next available block. Returns `None` if account run out of + /// space. + fn alloc_next_block(&mut self) -> Option { + let len = u32::try_from(self.data.len()).unwrap_or(u32::MAX); + let end = + self.next_block.checked_add(SZ as u32).filter(|&e| e <= len)?; + let ptr = Ptr::new(self.next_block).ok().flatten()?; + self.next_block = end; + Some(ptr) + } +} + +impl<'a, 'b> memory::Allocator for Allocator<'a, 'b> { + type Value = [u8; SZ]; + + fn alloc( + &mut self, + value: Self::Value, + ) -> Result { + let ptr = self + .alloc_from_freelist() + .or_else(|| self.alloc_next_block()) + .ok_or(memory::OutOfMemory)?; + self.set(ptr, value); + Ok(ptr) + } + + #[inline] + fn get(&self, ptr: Ptr) -> &Self::Value { + let idx = ptr.get() as usize; + self.data.get(idx..idx + SZ).unwrap().try_into().unwrap() + } + + #[inline] + fn get_mut(&mut self, ptr: Ptr) -> &mut Self::Value { + let idx = ptr.get() as usize; + self.data.get_mut(idx..idx + SZ).unwrap().try_into().unwrap() + } + + #[inline] + fn free(&mut self, ptr: Ptr) { + let next = + self.first_free.map_or([0; 4], |ptr| ptr.get().to_ne_bytes()); + let idx = ptr.get() as usize; + self.data.get_mut(idx..idx + 4).unwrap().copy_from_slice(&next); + self.first_free = Some(ptr); + } +} + + + +impl<'a, 'b> core::ops::Deref for AccountTrie<'a, 'b> { + type Target = sealable_trie::Trie>; + fn deref(&self) -> &Self::Target { &self.0 } +} + +impl<'a, 'b> core::ops::DerefMut for AccountTrie<'a, 'b> { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } +} + +/// Reads fixed-width value from start of the buffer and returns the value and +/// remaining portion of the buffer. +/// +/// By working on a fixed-size buffers, this avoids any run-time checks. Sizes +/// are verified at compile-time. +fn read( + buf: &[u8; N], + f: impl Fn([u8; L]) -> T, +) -> (T, &[u8; R]) { + let (left, right) = stdx::split_array_ref(buf); + (f(*left), right) +} + +/// Writes given fixed-width buffer at the start the buffer and returns the +/// remaining portion of the buffer. +/// +/// By working on a fixed-size buffers, this avoids any run-time checks. Sizes +/// are verified at compile-time. +fn write( + buf: &mut [u8; N], + data: [u8; L], +) -> &mut [u8; R] { + let (left, right) = stdx::split_array_mut(buf); + *left = data; + right +} + + +#[test] +fn test_header_encoding() { + const ONE: CryptoHash = CryptoHash([1; 32]); + + assert_eq!( + Some(Header { + root_ptr: None, + root_hash: sealable_trie::trie::EMPTY_TRIE_ROOT, + next_block: Header::ENCODED_SIZE as u32, + first_free: 0, + }), + Header::decode(&[0; 72]) + ); + + let hdr = Header { + root_ptr: Ptr::new(420).unwrap(), + root_hash: ONE.clone(), + next_block: 42, + first_free: 24, + }; + let got_bytes = hdr.encode(); + let got_hdr = Header::decode(&got_bytes); + + #[rustfmt::skip] + assert_eq!([ + /* magic: */ 1, 0, 0, 0, + /* version: */ 0, 0, 0, 0, + /* root_ptr: */ 164, 1, 0, 0, + /* root_hash: */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* next_block: */ 42, 0, 0, 0, + /* first_free: */ 24, 0, 0, 0, + /* tail: */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], got_bytes); + assert_eq!(Some(hdr), got_hdr); +} + +// #[test] +// fn test_trie_sanity() { +// const ONE: CryptoHash = CryptoHash([1; 32]); + +// let key = solana_program::pubkey::Pubkey::new_unique(); +// let mut lamports: u64 = 10 * solana_program::native_token::LAMPORTS_PER_SOL; +// let mut data = [0; SZ * 1000]; +// let owner = solana_program::pubkey::Pubkey::new_unique(); +// let account = solana_program::account_info::AccountInfo::new( +// /* key: */ &key, +// /* is signer: */ false, +// /* is writable: */ true, +// /* lamports: */ &mut lamports, +// /* data: */ &mut data[..], +// /* owner: */ &owner, +// /* executable: */ false, +// /* rent_epoch: */ 42, +// ); + +// { +// let mut trie = AccountTrie::new(account.data.borrow_mut()).unwrap(); +// assert_eq!(Ok(None), trie.get(&[0])); + +// assert_eq!(Ok(()), trie.set(&[0], &ONE)); +// assert_eq!(Ok(Some(ONE.clone())), trie.get(&[0])); +// } + +// { +// let mut trie = AccountTrie::new(account.data.borrow_mut()).unwrap(); +// assert_eq!(Ok(Some(ONE.clone())), trie.get(&[0])); + +// assert_eq!(Ok(()), trie.seal(&[0])); +// assert_eq!(Err(sealable_trie::Error::Sealed), trie.get(&[0])); +// } +// } diff --git a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs index db2e48ee..237290a3 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs @@ -25,7 +25,7 @@ use crate::client_state::AnyClientState; use crate::consensus_state::AnyConsensusState; use crate::SolanaIbcStorage; -impl ValidationContext for SolanaIbcStorage { +impl ValidationContext for SolanaIbcStorage<'_, '_> { type AnyConsensusState = AnyConsensusState; type AnyClientState = AnyClientState; type E = Self; From c9492ee8d3e463e4b5cd1b40f0d5e6c91aeb0bfd Mon Sep 17 00:00:00 2001 From: dhruvja Date: Wed, 18 Oct 2023 14:15:35 +0530 Subject: [PATCH 02/12] added trie key and impl for ser and de --- .../solana-ibc/src/execution_context.rs | 9 +- .../solana-ibc/programs/solana-ibc/src/lib.rs | 245 +++++++++++++++--- .../programs/solana-ibc/src/tests.rs | 11 +- 3 files changed, 229 insertions(+), 36 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index 0e464205..ebb84263 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use anchor_lang::emit; +use anchor_lang::prelude::borsh; use anchor_lang::solana_program::msg; use ibc::core::events::IbcEvent; use ibc::core::ics02_client::ClientExecutionContext; @@ -26,7 +27,7 @@ use crate::client_state::AnyClientState; use crate::consensus_state::AnyConsensusState; use crate::{ EmitIBCEvent, HostHeight, InnerChannelId, InnerHeight, InnerPortId, - InnerSequence, SolanaIbcStorage, SolanaTimestamp, + InnerSequence, SolanaIbcStorage, SolanaTimestamp, TrieKey }; type Result = core::result::Result; @@ -49,6 +50,12 @@ impl ClientExecutionContext for SolanaIbcStorage<'_, '_> { let client_state_key = client_state_path.0.to_string(); let serialized_client_state = serde_json::to_string(&client_state).unwrap(); + + let client_state_trie_key = &TrieKey::ClientState { client_id: client_state_path.0.to_string() }.to_vec(); + let trie = self.trie.as_mut().unwrap(); + let client_state_hash = borsh::to_vec(&serialized_client_state).unwrap(); + trie.set(&client_state_trie_key, &lib::hash::CryptoHash::digest(&client_state_hash)).unwrap(); + self.clients.insert(client_state_key, serialized_client_state); Ok(()) } diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index c1973bd8..a1ee98cf 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -3,6 +3,7 @@ #![allow(clippy::result_large_err)] use std::collections::BTreeMap; +use std::mem::size_of; use anchor_lang::prelude::*; use borsh::{BorshDeserialize, BorshSerialize}; @@ -32,6 +33,8 @@ mod magic { pub(crate) const TRIE_ROOT: u32 = 1; } + + #[anchor_lang::program] pub mod solana_ibc { use super::*; @@ -42,8 +45,8 @@ pub mod solana_ibc { ) -> Result<()> { msg!("Called deliver method"); let _sender = ctx.accounts.sender.to_account_info(); - let solana_ibc_store: &SolanaIbcStorageTemp = - &ctx.accounts.storage; + let mut solana_ibc_store: &mut SolanaIbcStorageTemp = + &mut ctx.accounts.storage; msg!("This is solana_ibc_store {:?}", solana_ibc_store); let all_messages = messages @@ -55,7 +58,6 @@ pub mod solana_ibc { .collect::>(); msg!("These are messages {:?}", all_messages); - let account = &ctx.accounts.trie; let mut trie = trie::AccountTrie::new(account.try_borrow_mut_data()?) @@ -67,10 +69,16 @@ pub mod solana_ibc { clients: solana_ibc_store.clients.clone(), client_id_set: solana_ibc_store.client_id_set.clone(), client_counter: solana_ibc_store.client_counter.clone(), - client_processed_times: solana_ibc_store.client_processed_times.clone(), - client_processed_heights: solana_ibc_store.client_processed_heights.clone(), + client_processed_times: solana_ibc_store + .client_processed_times + .clone(), + client_processed_heights: solana_ibc_store + .client_processed_heights + .clone(), consensus_states: solana_ibc_store.consensus_states.clone(), - client_consensus_state_height_sets: solana_ibc_store.client_consensus_state_height_sets.clone(), + client_consensus_state_height_sets: solana_ibc_store + .client_consensus_state_height_sets + .clone(), connection_id_set: solana_ibc_store.connection_id_set.clone(), connection_counter: solana_ibc_store.connection_counter.clone(), connections: solana_ibc_store.connections.clone(), @@ -81,11 +89,17 @@ pub mod solana_ibc { next_sequence_send: solana_ibc_store.next_sequence_send.clone(), next_sequence_recv: solana_ibc_store.next_sequence_recv.clone(), next_sequence_ack: solana_ibc_store.next_sequence_ack.clone(), - packet_commitment_sequence_sets: solana_ibc_store.packet_commitment_sequence_sets.clone(), - packet_receipt_sequence_sets: solana_ibc_store.packet_receipt_sequence_sets.clone(), - packet_acknowledgement_sequence_sets: solana_ibc_store.packet_acknowledgement_sequence_sets.clone(), + packet_commitment_sequence_sets: solana_ibc_store + .packet_commitment_sequence_sets + .clone(), + packet_receipt_sequence_sets: solana_ibc_store + .packet_receipt_sequence_sets + .clone(), + packet_acknowledgement_sequence_sets: solana_ibc_store + .packet_acknowledgement_sequence_sets + .clone(), ibc_events_history: solana_ibc_store.ibc_events_history.clone(), - trie: Some(trie) + trie: Some(trie), }; let mut solana_real_storage_another = SolanaIbcStorage { @@ -94,10 +108,16 @@ pub mod solana_ibc { clients: solana_ibc_store.clients.clone(), client_id_set: solana_ibc_store.client_id_set.clone(), client_counter: solana_ibc_store.client_counter.clone(), - client_processed_times: solana_ibc_store.client_processed_times.clone(), - client_processed_heights: solana_ibc_store.client_processed_heights.clone(), + client_processed_times: solana_ibc_store + .client_processed_times + .clone(), + client_processed_heights: solana_ibc_store + .client_processed_heights + .clone(), consensus_states: solana_ibc_store.consensus_states.clone(), - client_consensus_state_height_sets: solana_ibc_store.client_consensus_state_height_sets.clone(), + client_consensus_state_height_sets: solana_ibc_store + .client_consensus_state_height_sets + .clone(), connection_id_set: solana_ibc_store.connection_id_set.clone(), connection_counter: solana_ibc_store.connection_counter.clone(), connections: solana_ibc_store.connections.clone(), @@ -108,9 +128,15 @@ pub mod solana_ibc { next_sequence_send: solana_ibc_store.next_sequence_send.clone(), next_sequence_recv: solana_ibc_store.next_sequence_recv.clone(), next_sequence_ack: solana_ibc_store.next_sequence_ack.clone(), - packet_commitment_sequence_sets: solana_ibc_store.packet_commitment_sequence_sets.clone(), - packet_receipt_sequence_sets: solana_ibc_store.packet_receipt_sequence_sets.clone(), - packet_acknowledgement_sequence_sets: solana_ibc_store.packet_acknowledgement_sequence_sets.clone(), + packet_commitment_sequence_sets: solana_ibc_store + .packet_commitment_sequence_sets + .clone(), + packet_receipt_sequence_sets: solana_ibc_store + .packet_receipt_sequence_sets + .clone(), + packet_acknowledgement_sequence_sets: solana_ibc_store + .packet_acknowledgement_sequence_sets + .clone(), ibc_events_history: solana_ibc_store.ibc_events_history.clone(), trie: None, }; @@ -121,8 +147,11 @@ pub mod solana_ibc { all_messages.into_iter().fold(vec![], |mut errors, msg| { match ibc::core::MsgEnvelope::try_from(msg) { Ok(msg) => { - match ibc::core::dispatch(&mut solana_real_storage, router, msg) - { + match ibc::core::dispatch( + &mut solana_real_storage, + router, + msg, + ) { Ok(()) => (), Err(e) => errors.push(e), } @@ -132,12 +161,59 @@ pub mod solana_ibc { errors }); + solana_ibc_store.height = solana_real_storage.height; + solana_ibc_store.module_holder = + solana_real_storage.module_holder.clone(); + solana_ibc_store.clients = solana_real_storage.clients.clone(); + solana_ibc_store.client_id_set = + solana_real_storage.client_id_set.clone(); + solana_ibc_store.client_counter = + solana_real_storage.client_counter.clone(); + solana_ibc_store.client_processed_times = + solana_real_storage.client_processed_times.clone(); + solana_ibc_store.client_processed_heights = + solana_real_storage.client_processed_heights.clone(); + solana_ibc_store.consensus_states = + solana_real_storage.consensus_states.clone(); + solana_ibc_store.client_consensus_state_height_sets = + solana_real_storage.client_consensus_state_height_sets.clone(); + solana_ibc_store.connection_id_set = + solana_real_storage.connection_id_set.clone(); + solana_ibc_store.connection_counter = + solana_real_storage.connection_counter.clone(); + solana_ibc_store.connections = solana_real_storage.connections.clone(); + solana_ibc_store.channel_ends = + solana_real_storage.channel_ends.clone(); + solana_ibc_store.connection_to_client = + solana_real_storage.connection_to_client.clone(); + solana_ibc_store.port_channel_id_set = + solana_real_storage.port_channel_id_set.clone(); + solana_ibc_store.channel_counter = + solana_real_storage.channel_counter.clone(); + solana_ibc_store.next_sequence_send = + solana_real_storage.next_sequence_send.clone(); + solana_ibc_store.next_sequence_recv = + solana_real_storage.next_sequence_recv.clone(); + solana_ibc_store.next_sequence_ack = + solana_real_storage.next_sequence_ack.clone(); + solana_ibc_store.packet_commitment_sequence_sets = + solana_real_storage.packet_commitment_sequence_sets.clone(); + solana_ibc_store.packet_receipt_sequence_sets = + solana_real_storage.packet_receipt_sequence_sets.clone(); + solana_ibc_store.packet_acknowledgement_sequence_sets = + solana_real_storage.packet_acknowledgement_sequence_sets.clone(); + solana_ibc_store.ibc_events_history = + solana_real_storage.ibc_events_history.clone(); + + trie = solana_real_storage.trie.unwrap(); + msg!("These are errors {:?}", errors); msg!("This is final structure {:?}", solana_ibc_store); + // msg!("this is length {}", TrieKey::ClientState{ client_id: String::from("hello")}.into()); + Ok(()) } - } #[derive(Accounts)] @@ -152,7 +228,125 @@ pub struct Deliver<'info> { pub system_program: Program<'info, System>, } -pub struct MyTrie {} +pub enum TrieKey { + ClientState { client_id: String }, + ConsensusState { client_id: String, height: u64 }, + Connection { connection_id: u32 }, + ChannelEnd { port_id: u32, channel_id: u32 }, + NextSequenceSend { port_id: u32, channel_id: u32 }, + NextSequenceRecv { port_id: u32, channel_id: u32 }, + NextSequenceAck { port_id: u32, channel_id: u32 }, + Commitment { port_id: u32, channel_id: u32, sequence: u64 }, + Receipts { port_id: u32, channel_id: u32, sequence: u64 }, + Acks { port_id: u32, channel_id: u32, sequence: u64 }, +} + +#[repr(u8)] +pub enum TrieKeyWithoutFields { + ClientState = 1, + ConsensusState = 2, + Connection = 3, + ChannelEnd = 4, + NextSequenceSend = 5, + NextSequenceRecv = 6, + NextSequenceAck = 7, + Commitment = 8, + Receipts = 9, + Acks = 10, +} + + +impl TrieKey { + pub fn len(&self) -> usize { + size_of::() + match self { + TrieKey::ClientState { client_id } => client_id.len(), + TrieKey::ConsensusState { client_id, height } => client_id.len() + size_of::(), + TrieKey::Connection { connection_id } => size_of::(), + TrieKey::ChannelEnd { port_id, channel_id } => size_of::() + size_of::(), + TrieKey::NextSequenceSend { port_id, channel_id } => size_of::() + size_of::(), + TrieKey::NextSequenceRecv { port_id, channel_id } => size_of::() + size_of::(), + TrieKey::NextSequenceAck { port_id, channel_id } => size_of::() + size_of::(), + TrieKey::Commitment { port_id, channel_id, sequence } => size_of::() + size_of::() + size_of::(), + TrieKey::Receipts { port_id, channel_id, sequence } => size_of::() + size_of::()+ size_of::(), + TrieKey::Acks { port_id, channel_id, sequence } => size_of::() + size_of::()+ size_of::(), + } + } + + pub fn append_into(&self, buf: &mut Vec) { + let expected_len = self.len(); + let start_len = buf.len(); + buf.reserve(self.len()); + match self { + TrieKey::ClientState { client_id } => { + buf.push(TrieKeyWithoutFields::ClientState as u8); + buf.extend(client_id.as_bytes()); + }, + TrieKey::ConsensusState { client_id, height } => { + buf.push(TrieKeyWithoutFields::ConsensusState as u8); + buf.extend(height.to_be_bytes()) + }, + TrieKey::Connection { connection_id } => { + buf.push(TrieKeyWithoutFields::Connection as u8); + buf.extend(connection_id.to_be_bytes()) + }, + TrieKey::ChannelEnd { port_id, channel_id } => { + buf.push(TrieKeyWithoutFields::ChannelEnd as u8); + buf.extend(port_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::ChannelEnd as u8); + buf.extend(channel_id.to_be_bytes()); + }, + TrieKey::NextSequenceSend { port_id, channel_id } => { + buf.push(TrieKeyWithoutFields::NextSequenceSend as u8); + buf.extend(port_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::NextSequenceSend as u8); + buf.extend(channel_id.to_be_bytes()); + }, + TrieKey::NextSequenceRecv { port_id, channel_id } => { + buf.push(TrieKeyWithoutFields::NextSequenceRecv as u8); + buf.extend(port_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::NextSequenceRecv as u8); + buf.extend(channel_id.to_be_bytes()); + }, + TrieKey::NextSequenceAck { port_id, channel_id } => { + buf.push(TrieKeyWithoutFields::NextSequenceAck as u8); + buf.extend(port_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::NextSequenceAck as u8); + buf.extend(channel_id.to_be_bytes()); + }, + TrieKey::Commitment { port_id, channel_id, sequence } => { + buf.push(TrieKeyWithoutFields::Commitment as u8); + buf.extend(port_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::Commitment as u8); + buf.extend(channel_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::Commitment as u8); + buf.extend(sequence.to_be_bytes()); + }, + TrieKey::Receipts { port_id, channel_id, sequence } => { + buf.push(TrieKeyWithoutFields::Receipts as u8); + buf.extend(port_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::Receipts as u8); + buf.extend(channel_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::Receipts as u8); + buf.extend(sequence.to_be_bytes()); + }, + TrieKey::Acks { port_id, channel_id, sequence } => { + buf.push(TrieKeyWithoutFields::Acks as u8); + buf.extend(port_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::Acks as u8); + buf.extend(channel_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::Acks as u8); + buf.extend(sequence.to_be_bytes()); + }, + } + debug_assert_eq!(expected_len, buf.len() - start_len); + } + + pub fn to_vec(&self) -> Vec { + let mut buf = Vec::with_capacity(self.len()); + self.append_into(&mut buf); + buf + } +} #[event] pub struct EmitIBCEvent { @@ -179,15 +373,6 @@ pub type InnerConnectionEnd = String; // Serialized pub type InnerChannelEnd = String; // Serialized pub type InnerConsensusState = String; // Serialized -// #[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize, PartialEq)] -// pub struct InnerHeight { -// /// Previously known as "epoch" -// revision_number: u64, - -// /// The height of a block -// revision_height: u64, -// } - #[account] #[derive(Debug)] /// All the structs from IBC are stored as String since they dont implement AnchorSerialize and AnchorDeserialize @@ -327,4 +512,4 @@ impl Router for SolanaIbcStorage<'_, '_> { fn lookup_module(&self, port_id: &PortId) -> Option { self.module_holder.get_module_id(port_id) } -} +} \ No newline at end of file diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index 5f25ea95..19e85b27 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -19,9 +19,10 @@ use ibc::mock::header::MockHeader; use ibc::Any; use ibc_proto::protobuf::Protobuf; +use crate::trie::AccountTrie; use crate::{ accounts, instruction, AnyCheck, SolanaIbcStorage, ID, - SOLANA_IBC_STORAGE_SEED, TEST_TRIE_SEED, + SOLANA_IBC_STORAGE_SEED, TEST_TRIE_SEED, SolanaIbcStorageTemp, }; const TYPE_URL: &str = "/ibc.core.client.v1.MsgCreateClient"; @@ -99,11 +100,11 @@ fn anchor_test_deliver() -> Result<()> { println!("demo sig: {sig}"); - // // Retrieve and validate state - // let solana_ibc_storage_account: SolanaIbcStorage = - // program.account(solana_ibc_storage).unwrap(); + // Retrieve and validate state + let solana_ibc_storage_account: SolanaIbcStorageTemp = + program.account(solana_ibc_storage).unwrap(); - // println!("This is solana storage account {:?}", solana_ibc_storage_account); + println!("This is solana storage account {:?}", solana_ibc_storage_account); Ok(()) } From 36b1ad243d33dbb395442fee7d737a1e399bd239 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Wed, 18 Oct 2023 14:21:58 +0530 Subject: [PATCH 03/12] fmt --- .../programs/solana-ibc/src/client_state.rs | 8 ++- .../solana-ibc/src/execution_context.rs | 16 +++-- .../solana-ibc/programs/solana-ibc/src/lib.rs | 71 +++++++++++-------- .../programs/solana-ibc/src/tests.rs | 4 +- .../programs/solana-ibc/src/trie.rs | 6 +- 5 files changed, 65 insertions(+), 40 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 1bf571e9..ecfbe51e 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/client_state.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/client_state.rs @@ -371,7 +371,9 @@ impl ClientStateExecution> for AnyClientState { } } -impl ibc::clients::ics07_tendermint::CommonContext for SolanaIbcStorage<'_, '_> { +impl ibc::clients::ics07_tendermint::CommonContext + for SolanaIbcStorage<'_, '_> +{ type ConversionError = ClientError; type AnyConsensusState = AnyConsensusState; @@ -401,7 +403,9 @@ impl MockClientContext for SolanaIbcStorage<'_, '_> { } } -impl ibc::clients::ics07_tendermint::ValidationContext for SolanaIbcStorage<'_, '_> { +impl ibc::clients::ics07_tendermint::ValidationContext + for SolanaIbcStorage<'_, '_> +{ fn host_timestamp(&self) -> Result { ValidationContext::host_timestamp(self) } diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index ebb84263..7be79cad 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -27,7 +27,7 @@ use crate::client_state::AnyClientState; use crate::consensus_state::AnyConsensusState; use crate::{ EmitIBCEvent, HostHeight, InnerChannelId, InnerHeight, InnerPortId, - InnerSequence, SolanaIbcStorage, SolanaTimestamp, TrieKey + InnerSequence, SolanaIbcStorage, SolanaTimestamp, TrieKey, }; type Result = core::result::Result; @@ -51,10 +51,18 @@ impl ClientExecutionContext for SolanaIbcStorage<'_, '_> { let serialized_client_state = serde_json::to_string(&client_state).unwrap(); - let client_state_trie_key = &TrieKey::ClientState { client_id: client_state_path.0.to_string() }.to_vec(); + let client_state_trie_key = &TrieKey::ClientState { + client_id: client_state_path.0.to_string(), + } + .to_vec(); let trie = self.trie.as_mut().unwrap(); - let client_state_hash = borsh::to_vec(&serialized_client_state).unwrap(); - trie.set(&client_state_trie_key, &lib::hash::CryptoHash::digest(&client_state_hash)).unwrap(); + let client_state_hash = + borsh::to_vec(&serialized_client_state).unwrap(); + trie.set( + &client_state_trie_key, + &lib::hash::CryptoHash::digest(&client_state_hash), + ) + .unwrap(); self.clients.insert(client_state_key, serialized_client_state); Ok(()) diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index a1ee98cf..e20b1543 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -251,25 +251,42 @@ pub enum TrieKeyWithoutFields { NextSequenceRecv = 6, NextSequenceAck = 7, Commitment = 8, - Receipts = 9, + Receipts = 9, Acks = 10, } impl TrieKey { pub fn len(&self) -> usize { - size_of::() + match self { - TrieKey::ClientState { client_id } => client_id.len(), - TrieKey::ConsensusState { client_id, height } => client_id.len() + size_of::(), - TrieKey::Connection { connection_id } => size_of::(), - TrieKey::ChannelEnd { port_id, channel_id } => size_of::() + size_of::(), - TrieKey::NextSequenceSend { port_id, channel_id } => size_of::() + size_of::(), - TrieKey::NextSequenceRecv { port_id, channel_id } => size_of::() + size_of::(), - TrieKey::NextSequenceAck { port_id, channel_id } => size_of::() + size_of::(), - TrieKey::Commitment { port_id, channel_id, sequence } => size_of::() + size_of::() + size_of::(), - TrieKey::Receipts { port_id, channel_id, sequence } => size_of::() + size_of::()+ size_of::(), - TrieKey::Acks { port_id, channel_id, sequence } => size_of::() + size_of::()+ size_of::(), - } + size_of::() + + match self { + TrieKey::ClientState { client_id } => client_id.len(), + TrieKey::ConsensusState { client_id, height } => { + client_id.len() + size_of::() + } + TrieKey::Connection { connection_id } => size_of::(), + TrieKey::ChannelEnd { port_id, channel_id } => { + size_of::() + size_of::() + } + TrieKey::NextSequenceSend { port_id, channel_id } => { + size_of::() + size_of::() + } + TrieKey::NextSequenceRecv { port_id, channel_id } => { + size_of::() + size_of::() + } + TrieKey::NextSequenceAck { port_id, channel_id } => { + size_of::() + size_of::() + } + TrieKey::Commitment { port_id, channel_id, sequence } => { + size_of::() + size_of::() + size_of::() + } + TrieKey::Receipts { port_id, channel_id, sequence } => { + size_of::() + size_of::() + size_of::() + } + TrieKey::Acks { port_id, channel_id, sequence } => { + size_of::() + size_of::() + size_of::() + } + } } pub fn append_into(&self, buf: &mut Vec) { @@ -280,39 +297,39 @@ impl TrieKey { TrieKey::ClientState { client_id } => { buf.push(TrieKeyWithoutFields::ClientState as u8); buf.extend(client_id.as_bytes()); - }, + } TrieKey::ConsensusState { client_id, height } => { buf.push(TrieKeyWithoutFields::ConsensusState as u8); buf.extend(height.to_be_bytes()) - }, + } TrieKey::Connection { connection_id } => { buf.push(TrieKeyWithoutFields::Connection as u8); buf.extend(connection_id.to_be_bytes()) - }, + } TrieKey::ChannelEnd { port_id, channel_id } => { buf.push(TrieKeyWithoutFields::ChannelEnd as u8); buf.extend(port_id.to_be_bytes()); buf.push(TrieKeyWithoutFields::ChannelEnd as u8); buf.extend(channel_id.to_be_bytes()); - }, + } TrieKey::NextSequenceSend { port_id, channel_id } => { buf.push(TrieKeyWithoutFields::NextSequenceSend as u8); buf.extend(port_id.to_be_bytes()); buf.push(TrieKeyWithoutFields::NextSequenceSend as u8); buf.extend(channel_id.to_be_bytes()); - }, + } TrieKey::NextSequenceRecv { port_id, channel_id } => { buf.push(TrieKeyWithoutFields::NextSequenceRecv as u8); buf.extend(port_id.to_be_bytes()); buf.push(TrieKeyWithoutFields::NextSequenceRecv as u8); buf.extend(channel_id.to_be_bytes()); - }, + } TrieKey::NextSequenceAck { port_id, channel_id } => { buf.push(TrieKeyWithoutFields::NextSequenceAck as u8); buf.extend(port_id.to_be_bytes()); buf.push(TrieKeyWithoutFields::NextSequenceAck as u8); buf.extend(channel_id.to_be_bytes()); - }, + } TrieKey::Commitment { port_id, channel_id, sequence } => { buf.push(TrieKeyWithoutFields::Commitment as u8); buf.extend(port_id.to_be_bytes()); @@ -320,7 +337,7 @@ impl TrieKey { buf.extend(channel_id.to_be_bytes()); buf.push(TrieKeyWithoutFields::Commitment as u8); buf.extend(sequence.to_be_bytes()); - }, + } TrieKey::Receipts { port_id, channel_id, sequence } => { buf.push(TrieKeyWithoutFields::Receipts as u8); buf.extend(port_id.to_be_bytes()); @@ -328,7 +345,7 @@ impl TrieKey { buf.extend(channel_id.to_be_bytes()); buf.push(TrieKeyWithoutFields::Receipts as u8); buf.extend(sequence.to_be_bytes()); - }, + } TrieKey::Acks { port_id, channel_id, sequence } => { buf.push(TrieKeyWithoutFields::Acks as u8); buf.extend(port_id.to_be_bytes()); @@ -336,8 +353,8 @@ impl TrieKey { buf.extend(channel_id.to_be_bytes()); buf.push(TrieKeyWithoutFields::Acks as u8); buf.extend(sequence.to_be_bytes()); - }, - } + } + } debug_assert_eq!(expected_len, buf.len() - start_len); } @@ -481,9 +498,7 @@ pub trait SolanaIbcStorageHost { todo!() } /// - fn set_solana_ibc_store(_store: &SolanaIbcStorage) { - todo!() - } + fn set_solana_ibc_store(_store: &SolanaIbcStorage) { todo!() } } impl Router for SolanaIbcStorage<'_, '_> { @@ -512,4 +527,4 @@ impl Router for SolanaIbcStorage<'_, '_> { fn lookup_module(&self, port_id: &PortId) -> Option { self.module_holder.get_module_id(port_id) } -} \ No newline at end of file +} diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index 19e85b27..de885df8 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -21,8 +21,8 @@ use ibc_proto::protobuf::Protobuf; use crate::trie::AccountTrie; use crate::{ - accounts, instruction, AnyCheck, SolanaIbcStorage, ID, - SOLANA_IBC_STORAGE_SEED, TEST_TRIE_SEED, SolanaIbcStorageTemp, + accounts, instruction, AnyCheck, SolanaIbcStorage, SolanaIbcStorageTemp, + ID, SOLANA_IBC_STORAGE_SEED, TEST_TRIE_SEED, }; const TYPE_URL: &str = "/ibc.core.client.v1.MsgCreateClient"; diff --git a/solana/solana-ibc/programs/solana-ibc/src/trie.rs b/solana/solana-ibc/programs/solana-ibc/src/trie.rs index 2741af37..10dacf3b 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/trie.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/trie.rs @@ -1,13 +1,11 @@ -use anchor_lang::prelude::*; - use core::cell::RefMut; use core::mem::ManuallyDrop; +use std::result::Result; +use anchor_lang::prelude::*; use lib::hash::CryptoHash; use memory::Ptr; -use std::result::Result; - use crate::magic; type DataRef<'a, 'b> = RefMut<'a, &'b mut [u8]>; From e9e18ae8e7276ec9bf7a820d254470292e177359 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Wed, 18 Oct 2023 18:31:08 +0530 Subject: [PATCH 04/12] storing data in trie in execution context --- .../solana-ibc/src/execution_context.rs | 153 +++++++++++++++++- .../solana-ibc/programs/solana-ibc/src/lib.rs | 56 ++++--- 2 files changed, 181 insertions(+), 28 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index 7be79cad..034717fe 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -32,6 +32,12 @@ use crate::{ type Result = core::result::Result; +const CONNECTION_ID_PREFIX: &str = "connection-"; +const CHANNEL_ID_PREFIX: &str = "channel-"; + +const DEFAULT_PORT_ID: &str = "defaultPort"; +const TRANSFER_PORT_ID: &str = "transfer"; + impl ClientExecutionContext for SolanaIbcStorage<'_, '_> { type ClientValidationContext = Self; type AnyClientState = AnyClientState; @@ -84,6 +90,21 @@ impl ClientExecutionContext for SolanaIbcStorage<'_, '_> { ); let serialized_consensus_state = serde_json::to_string(&consensus_state).unwrap(); + + let consensus_state_trie_key = &TrieKey::ConsensusState { + client_id: consensus_state_path.client_id.to_string(), + height: consensus_state_path.height, + epoch: consensus_state_path.epoch, + }.to_vec(); + let trie = self.trie.as_mut().unwrap(); + let consensus_state_hash = + borsh::to_vec(&serialized_consensus_state).unwrap(); + trie.set( + &consensus_state_trie_key, + &lib::hash::CryptoHash::digest(&consensus_state_hash), + ) + .unwrap(); + self.consensus_states .insert(consensus_state_key, serialized_consensus_state); self.height.0 = consensus_state_path.epoch; @@ -183,9 +204,26 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { connection_path, connection_end ); + + let serialized_connection_end = + serde_json::to_string(&connection_end).unwrap(); + let connection_prefix_length = CONNECTION_ID_PREFIX.len(); + let connection_id = &connection_path.0.to_string()[connection_prefix_length..]; + let consensus_state_trie_key = &TrieKey::Connection { + connection_id: connection_id.parse().unwrap(), + }.to_vec(); + let trie = self.trie.as_mut().unwrap(); + let consensus_state_hash = + borsh::to_vec(&serialized_connection_end).unwrap(); + trie.set( + &consensus_state_trie_key, + &lib::hash::CryptoHash::digest(&consensus_state_hash), + ) + .unwrap(); + self.connections.insert( connection_path.0.to_string(), - serde_json::to_string(&connection_end).unwrap(), + serialized_connection_end ); Ok(()) } @@ -224,6 +262,21 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { commitment_path, commitment ); + let channel_prefix_length = CHANNEL_ID_PREFIX.len(); + let channel_id = &commitment_path.channel_id.to_string()[channel_prefix_length..]; + + let commitment_trie_key = &TrieKey::Commitment { + port_id: commitment_path.port_id.clone().to_string(), + channel_id: channel_id.parse().unwrap(), + sequence: u64::from(commitment_path.sequence) + }.to_vec(); + let trie = self.trie.as_mut().unwrap(); + trie.set( + &commitment_trie_key, + &lib::hash::CryptoHash::digest(&commitment.into_vec()), + ) + .unwrap(); + record_packet_sequence( &mut self.packet_commitment_sequence_sets, &commitment_path.port_id, @@ -262,6 +315,19 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { receipt_path, receipt ); + let channel_prefix_length = CHANNEL_ID_PREFIX.len(); + let channel_id = &receipt_path.channel_id.to_string()[channel_prefix_length..]; + + let receipt_trie_key = &TrieKey::Receipts { + port_id: receipt_path.port_id.clone().to_string(), + channel_id: channel_id.parse().unwrap(), + sequence: u64::from(receipt_path.sequence) + }.to_vec(); + let trie = self.trie.as_mut().unwrap(); + trie.set( + &receipt_trie_key, + &lib::hash::CryptoHash::DEFAULT, + ).unwrap(); record_packet_sequence( &mut self.packet_receipt_sequence_sets, &receipt_path.port_id, @@ -281,6 +347,20 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { ack_path, ack_commitment ); + let channel_prefix_length = CHANNEL_ID_PREFIX.len(); + let channel_id = &ack_path.channel_id.to_string()[channel_prefix_length..]; + + let ack_commitment_trie_key = &TrieKey::Acks { + port_id: ack_path.port_id.clone().to_string(), + channel_id: channel_id.parse().unwrap(), + sequence: u64::from(ack_path.sequence) + }.to_vec(); + let trie = self.trie.as_mut().unwrap(); + trie.set( + &ack_commitment_trie_key, + &lib::hash::CryptoHash::digest(&ack_commitment.into_vec()), + ) + .unwrap(); record_packet_sequence( &mut self.packet_acknowledgement_sequence_sets, &ack_path.port_id, @@ -317,6 +397,25 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { channel_end_path.0.clone().to_string(), channel_end_path.1.clone().to_string(), )); + + let serialized_channel_end = + serde_json::to_string(&channel_end).unwrap(); + let channel_prefix_length = CHANNEL_ID_PREFIX.len(); + let channel_id = &channel_end_path.1.to_string()[channel_prefix_length..]; + + let channel_end_trie_key = &TrieKey::ChannelEnd { + port_id: channel_end_path.0.clone().to_string(), + channel_id: channel_id.parse().unwrap(), + }.to_vec(); + let trie = self.trie.as_mut().unwrap(); + let channel_end_hash = + borsh::to_vec(&serialized_channel_end).unwrap(); + trie.set( + &channel_end_trie_key, + &lib::hash::CryptoHash::digest(&channel_end_hash), + ) + .unwrap(); + self.channel_ends.insert( (channel_end_path.0.to_string(), channel_end_path.1.to_string()), serde_json::to_string(&channel_end).unwrap(), @@ -336,6 +435,24 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { ); let seq_send_key = (seq_send_path.0.to_string(), seq_send_path.1.to_string()); + + let channel_prefix_length = CHANNEL_ID_PREFIX.len(); + let channel_id = &seq_send_path.1.to_string()[channel_prefix_length..]; + + let next_seq_send_trie_key = &TrieKey::NextSequenceSend { + port_id: seq_send_path.0.clone().to_string(), + channel_id: channel_id.parse().unwrap(), + }.to_vec(); + let trie = self.trie.as_mut().unwrap(); + let seq_in_u64: u64 = seq.into(); + let seq_in_bytes = seq_in_u64.to_be_bytes(); + + trie.set( + &next_seq_send_trie_key, + &lib::hash::CryptoHash::digest(&seq_in_bytes), + ) + .unwrap(); + self.next_sequence_send.insert(seq_send_key, u64::from(seq)); Ok(()) } @@ -351,7 +468,23 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { seq ); let seq_recv_key = - (seq_recv_path.0.to_string(), seq_recv_path.1.to_string()); + (seq_recv_path.0.to_string(), seq_recv_path.1.to_string()); + let channel_prefix_length = CHANNEL_ID_PREFIX.len(); + let channel_id = &seq_recv_path.1.to_string()[channel_prefix_length..]; + + let next_seq_recv_trie_key = &TrieKey::NextSequenceRecv { + port_id: seq_recv_path.0.clone().to_string(), + channel_id: channel_id.parse().unwrap(), + }.to_vec(); + let trie = self.trie.as_mut().unwrap(); + let seq_in_u64: u64 = seq.into(); + let seq_in_bytes = seq_in_u64.to_be_bytes(); + + trie.set( + &next_seq_recv_trie_key, + &lib::hash::CryptoHash::digest(&seq_in_bytes), + ) + .unwrap(); self.next_sequence_recv.insert(seq_recv_key, u64::from(seq)); Ok(()) } @@ -364,6 +497,22 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { msg!("store_next_sequence_ack: path: {}, seq: {:?}", seq_ack_path, seq); let seq_ack_key = (seq_ack_path.0.to_string(), seq_ack_path.1.to_string()); + let channel_prefix_length = CHANNEL_ID_PREFIX.len(); + let channel_id = &seq_ack_path.1.to_string()[channel_prefix_length..]; + + let next_seq_ack_trie_key = &TrieKey::NextSequenceAck { + port_id: seq_ack_path.0.clone().to_string(), + channel_id: channel_id.parse().unwrap(), + }.to_vec(); + let trie = self.trie.as_mut().unwrap(); + let seq_in_u64: u64 = seq.into(); + let seq_in_bytes = seq_in_u64.to_be_bytes(); + + trie.set( + &next_seq_ack_trie_key, + &lib::hash::CryptoHash::digest(&seq_in_bytes), + ) + .unwrap(); self.next_sequence_ack.insert(seq_ack_key, u64::from(seq)); Ok(()) } diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index e20b1543..87217864 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -230,15 +230,15 @@ pub struct Deliver<'info> { pub enum TrieKey { ClientState { client_id: String }, - ConsensusState { client_id: String, height: u64 }, + ConsensusState { client_id: String, epoch: u64, height: u64 }, Connection { connection_id: u32 }, - ChannelEnd { port_id: u32, channel_id: u32 }, - NextSequenceSend { port_id: u32, channel_id: u32 }, - NextSequenceRecv { port_id: u32, channel_id: u32 }, - NextSequenceAck { port_id: u32, channel_id: u32 }, - Commitment { port_id: u32, channel_id: u32, sequence: u64 }, - Receipts { port_id: u32, channel_id: u32, sequence: u64 }, - Acks { port_id: u32, channel_id: u32, sequence: u64 }, + ChannelEnd { port_id: String, channel_id: u32 }, + NextSequenceSend { port_id: String, channel_id: u32 }, + NextSequenceRecv { port_id: String, channel_id: u32 }, + NextSequenceAck { port_id: String, channel_id: u32 }, + Commitment { port_id: String, channel_id: u32, sequence: u64 }, + Receipts { port_id: String, channel_id: u32, sequence: u64 }, + Acks { port_id: String, channel_id: u32, sequence: u64 }, } #[repr(u8)] @@ -261,30 +261,30 @@ impl TrieKey { size_of::() + match self { TrieKey::ClientState { client_id } => client_id.len(), - TrieKey::ConsensusState { client_id, height } => { - client_id.len() + size_of::() + TrieKey::ConsensusState { client_id, epoch: u64, height } => { + client_id.len() + size_of::() + size_of::() } TrieKey::Connection { connection_id } => size_of::(), TrieKey::ChannelEnd { port_id, channel_id } => { - size_of::() + size_of::() + port_id.len() + size_of::() } TrieKey::NextSequenceSend { port_id, channel_id } => { - size_of::() + size_of::() + port_id.len() + size_of::() } TrieKey::NextSequenceRecv { port_id, channel_id } => { - size_of::() + size_of::() + port_id.len() + size_of::() } TrieKey::NextSequenceAck { port_id, channel_id } => { - size_of::() + size_of::() + port_id.len() + size_of::() } TrieKey::Commitment { port_id, channel_id, sequence } => { - size_of::() + size_of::() + size_of::() + port_id.len() + size_of::() + size_of::() } TrieKey::Receipts { port_id, channel_id, sequence } => { - size_of::() + size_of::() + size_of::() + port_id.len() + size_of::() + size_of::() } TrieKey::Acks { port_id, channel_id, sequence } => { - size_of::() + size_of::() + size_of::() + port_id.len() + size_of::() + size_of::() } } } @@ -298,9 +298,13 @@ impl TrieKey { buf.push(TrieKeyWithoutFields::ClientState as u8); buf.extend(client_id.as_bytes()); } - TrieKey::ConsensusState { client_id, height } => { + TrieKey::ConsensusState { client_id, epoch, height } => { buf.push(TrieKeyWithoutFields::ConsensusState as u8); - buf.extend(height.to_be_bytes()) + buf.extend(client_id.as_bytes()); + buf.push(TrieKeyWithoutFields::ConsensusState as u8); + buf.extend(height.to_be_bytes()); + buf.push(TrieKeyWithoutFields::ConsensusState as u8); + buf.extend(epoch.to_be_bytes()) } TrieKey::Connection { connection_id } => { buf.push(TrieKeyWithoutFields::Connection as u8); @@ -308,31 +312,31 @@ impl TrieKey { } TrieKey::ChannelEnd { port_id, channel_id } => { buf.push(TrieKeyWithoutFields::ChannelEnd as u8); - buf.extend(port_id.to_be_bytes()); + buf.extend(port_id.as_bytes()); buf.push(TrieKeyWithoutFields::ChannelEnd as u8); buf.extend(channel_id.to_be_bytes()); } TrieKey::NextSequenceSend { port_id, channel_id } => { buf.push(TrieKeyWithoutFields::NextSequenceSend as u8); - buf.extend(port_id.to_be_bytes()); + buf.extend(port_id.as_bytes()); buf.push(TrieKeyWithoutFields::NextSequenceSend as u8); buf.extend(channel_id.to_be_bytes()); } TrieKey::NextSequenceRecv { port_id, channel_id } => { buf.push(TrieKeyWithoutFields::NextSequenceRecv as u8); - buf.extend(port_id.to_be_bytes()); + buf.extend(port_id.as_bytes()); buf.push(TrieKeyWithoutFields::NextSequenceRecv as u8); buf.extend(channel_id.to_be_bytes()); } TrieKey::NextSequenceAck { port_id, channel_id } => { buf.push(TrieKeyWithoutFields::NextSequenceAck as u8); - buf.extend(port_id.to_be_bytes()); + buf.extend(port_id.as_bytes()); buf.push(TrieKeyWithoutFields::NextSequenceAck as u8); buf.extend(channel_id.to_be_bytes()); } TrieKey::Commitment { port_id, channel_id, sequence } => { buf.push(TrieKeyWithoutFields::Commitment as u8); - buf.extend(port_id.to_be_bytes()); + buf.extend(port_id.as_bytes()); buf.push(TrieKeyWithoutFields::Commitment as u8); buf.extend(channel_id.to_be_bytes()); buf.push(TrieKeyWithoutFields::Commitment as u8); @@ -340,7 +344,7 @@ impl TrieKey { } TrieKey::Receipts { port_id, channel_id, sequence } => { buf.push(TrieKeyWithoutFields::Receipts as u8); - buf.extend(port_id.to_be_bytes()); + buf.extend(port_id.as_bytes()); buf.push(TrieKeyWithoutFields::Receipts as u8); buf.extend(channel_id.to_be_bytes()); buf.push(TrieKeyWithoutFields::Receipts as u8); @@ -348,7 +352,7 @@ impl TrieKey { } TrieKey::Acks { port_id, channel_id, sequence } => { buf.push(TrieKeyWithoutFields::Acks as u8); - buf.extend(port_id.to_be_bytes()); + buf.extend(port_id.as_bytes()); buf.push(TrieKeyWithoutFields::Acks as u8); buf.extend(channel_id.to_be_bytes()); buf.push(TrieKeyWithoutFields::Acks as u8); From df1ce21b6e0b85802400bc1cdaf848fdb9fb7cf9 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Wed, 18 Oct 2023 18:31:26 +0530 Subject: [PATCH 05/12] storing data in trie in execution context --- .../solana-ibc/src/execution_context.rs | 108 ++++++++++-------- 1 file changed, 58 insertions(+), 50 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index 034717fe..4f499cd2 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -95,7 +95,8 @@ impl ClientExecutionContext for SolanaIbcStorage<'_, '_> { client_id: consensus_state_path.client_id.to_string(), height: consensus_state_path.height, epoch: consensus_state_path.epoch, - }.to_vec(); + } + .to_vec(); let trie = self.trie.as_mut().unwrap(); let consensus_state_hash = borsh::to_vec(&serialized_consensus_state).unwrap(); @@ -103,8 +104,8 @@ impl ClientExecutionContext for SolanaIbcStorage<'_, '_> { &consensus_state_trie_key, &lib::hash::CryptoHash::digest(&consensus_state_hash), ) - .unwrap(); - + .unwrap(); + self.consensus_states .insert(consensus_state_key, serialized_consensus_state); self.height.0 = consensus_state_path.epoch; @@ -205,13 +206,15 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { connection_end ); - let serialized_connection_end = + let serialized_connection_end = serde_json::to_string(&connection_end).unwrap(); - let connection_prefix_length = CONNECTION_ID_PREFIX.len(); - let connection_id = &connection_path.0.to_string()[connection_prefix_length..]; + let connection_prefix_length = CONNECTION_ID_PREFIX.len(); + let connection_id = + &connection_path.0.to_string()[connection_prefix_length..]; let consensus_state_trie_key = &TrieKey::Connection { connection_id: connection_id.parse().unwrap(), - }.to_vec(); + } + .to_vec(); let trie = self.trie.as_mut().unwrap(); let consensus_state_hash = borsh::to_vec(&serialized_connection_end).unwrap(); @@ -219,12 +222,10 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { &consensus_state_trie_key, &lib::hash::CryptoHash::digest(&consensus_state_hash), ) - .unwrap(); + .unwrap(); - self.connections.insert( - connection_path.0.to_string(), - serialized_connection_end - ); + self.connections + .insert(connection_path.0.to_string(), serialized_connection_end); Ok(()) } @@ -262,14 +263,16 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { commitment_path, commitment ); - let channel_prefix_length = CHANNEL_ID_PREFIX.len(); - let channel_id = &commitment_path.channel_id.to_string()[channel_prefix_length..]; + let channel_prefix_length = CHANNEL_ID_PREFIX.len(); + let channel_id = + &commitment_path.channel_id.to_string()[channel_prefix_length..]; let commitment_trie_key = &TrieKey::Commitment { port_id: commitment_path.port_id.clone().to_string(), channel_id: channel_id.parse().unwrap(), - sequence: u64::from(commitment_path.sequence) - }.to_vec(); + sequence: u64::from(commitment_path.sequence), + } + .to_vec(); let trie = self.trie.as_mut().unwrap(); trie.set( &commitment_trie_key, @@ -315,19 +318,18 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { receipt_path, receipt ); - let channel_prefix_length = CHANNEL_ID_PREFIX.len(); - let channel_id = &receipt_path.channel_id.to_string()[channel_prefix_length..]; + let channel_prefix_length = CHANNEL_ID_PREFIX.len(); + let channel_id = + &receipt_path.channel_id.to_string()[channel_prefix_length..]; let receipt_trie_key = &TrieKey::Receipts { port_id: receipt_path.port_id.clone().to_string(), channel_id: channel_id.parse().unwrap(), - sequence: u64::from(receipt_path.sequence) - }.to_vec(); + sequence: u64::from(receipt_path.sequence), + } + .to_vec(); let trie = self.trie.as_mut().unwrap(); - trie.set( - &receipt_trie_key, - &lib::hash::CryptoHash::DEFAULT, - ).unwrap(); + trie.set(&receipt_trie_key, &lib::hash::CryptoHash::DEFAULT).unwrap(); record_packet_sequence( &mut self.packet_receipt_sequence_sets, &receipt_path.port_id, @@ -347,20 +349,22 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { ack_path, ack_commitment ); - let channel_prefix_length = CHANNEL_ID_PREFIX.len(); - let channel_id = &ack_path.channel_id.to_string()[channel_prefix_length..]; + let channel_prefix_length = CHANNEL_ID_PREFIX.len(); + let channel_id = + &ack_path.channel_id.to_string()[channel_prefix_length..]; let ack_commitment_trie_key = &TrieKey::Acks { port_id: ack_path.port_id.clone().to_string(), channel_id: channel_id.parse().unwrap(), - sequence: u64::from(ack_path.sequence) - }.to_vec(); + sequence: u64::from(ack_path.sequence), + } + .to_vec(); let trie = self.trie.as_mut().unwrap(); trie.set( &ack_commitment_trie_key, &lib::hash::CryptoHash::digest(&ack_commitment.into_vec()), ) - .unwrap(); + .unwrap(); record_packet_sequence( &mut self.packet_acknowledgement_sequence_sets, &ack_path.port_id, @@ -398,23 +402,24 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { channel_end_path.1.clone().to_string(), )); - let serialized_channel_end = + let serialized_channel_end = serde_json::to_string(&channel_end).unwrap(); - let channel_prefix_length = CHANNEL_ID_PREFIX.len(); - let channel_id = &channel_end_path.1.to_string()[channel_prefix_length..]; + let channel_prefix_length = CHANNEL_ID_PREFIX.len(); + let channel_id = + &channel_end_path.1.to_string()[channel_prefix_length..]; let channel_end_trie_key = &TrieKey::ChannelEnd { port_id: channel_end_path.0.clone().to_string(), channel_id: channel_id.parse().unwrap(), - }.to_vec(); + } + .to_vec(); let trie = self.trie.as_mut().unwrap(); - let channel_end_hash = - borsh::to_vec(&serialized_channel_end).unwrap(); + let channel_end_hash = borsh::to_vec(&serialized_channel_end).unwrap(); trie.set( &channel_end_trie_key, &lib::hash::CryptoHash::digest(&channel_end_hash), ) - .unwrap(); + .unwrap(); self.channel_ends.insert( (channel_end_path.0.to_string(), channel_end_path.1.to_string()), @@ -436,23 +441,24 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { let seq_send_key = (seq_send_path.0.to_string(), seq_send_path.1.to_string()); - let channel_prefix_length = CHANNEL_ID_PREFIX.len(); + let channel_prefix_length = CHANNEL_ID_PREFIX.len(); let channel_id = &seq_send_path.1.to_string()[channel_prefix_length..]; let next_seq_send_trie_key = &TrieKey::NextSequenceSend { port_id: seq_send_path.0.clone().to_string(), channel_id: channel_id.parse().unwrap(), - }.to_vec(); + } + .to_vec(); let trie = self.trie.as_mut().unwrap(); let seq_in_u64: u64 = seq.into(); let seq_in_bytes = seq_in_u64.to_be_bytes(); - + trie.set( &next_seq_send_trie_key, &lib::hash::CryptoHash::digest(&seq_in_bytes), ) - .unwrap(); - + .unwrap(); + self.next_sequence_send.insert(seq_send_key, u64::from(seq)); Ok(()) } @@ -468,23 +474,24 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { seq ); let seq_recv_key = - (seq_recv_path.0.to_string(), seq_recv_path.1.to_string()); - let channel_prefix_length = CHANNEL_ID_PREFIX.len(); + (seq_recv_path.0.to_string(), seq_recv_path.1.to_string()); + let channel_prefix_length = CHANNEL_ID_PREFIX.len(); let channel_id = &seq_recv_path.1.to_string()[channel_prefix_length..]; let next_seq_recv_trie_key = &TrieKey::NextSequenceRecv { port_id: seq_recv_path.0.clone().to_string(), channel_id: channel_id.parse().unwrap(), - }.to_vec(); + } + .to_vec(); let trie = self.trie.as_mut().unwrap(); let seq_in_u64: u64 = seq.into(); let seq_in_bytes = seq_in_u64.to_be_bytes(); - + trie.set( &next_seq_recv_trie_key, &lib::hash::CryptoHash::digest(&seq_in_bytes), ) - .unwrap(); + .unwrap(); self.next_sequence_recv.insert(seq_recv_key, u64::from(seq)); Ok(()) } @@ -497,22 +504,23 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { msg!("store_next_sequence_ack: path: {}, seq: {:?}", seq_ack_path, seq); let seq_ack_key = (seq_ack_path.0.to_string(), seq_ack_path.1.to_string()); - let channel_prefix_length = CHANNEL_ID_PREFIX.len(); + let channel_prefix_length = CHANNEL_ID_PREFIX.len(); let channel_id = &seq_ack_path.1.to_string()[channel_prefix_length..]; let next_seq_ack_trie_key = &TrieKey::NextSequenceAck { port_id: seq_ack_path.0.clone().to_string(), channel_id: channel_id.parse().unwrap(), - }.to_vec(); + } + .to_vec(); let trie = self.trie.as_mut().unwrap(); let seq_in_u64: u64 = seq.into(); let seq_in_bytes = seq_in_u64.to_be_bytes(); - + trie.set( &next_seq_ack_trie_key, &lib::hash::CryptoHash::digest(&seq_in_bytes), ) - .unwrap(); + .unwrap(); self.next_sequence_ack.insert(seq_ack_key, u64::from(seq)); Ok(()) } From 6c2c742c81388f4826b780b0361ec3943663ad7e Mon Sep 17 00:00:00 2001 From: dhruvja Date: Wed, 18 Oct 2023 18:45:42 +0530 Subject: [PATCH 06/12] uncommented the trie sanity test --- .../programs/solana-ibc/src/trie.rs | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/trie.rs b/solana/solana-ibc/programs/solana-ibc/src/trie.rs index 10dacf3b..92c22735 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/trie.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/trie.rs @@ -2,7 +2,7 @@ use core::cell::RefMut; use core::mem::ManuallyDrop; use std::result::Result; -use anchor_lang::prelude::*; +use anchor_lang::{prelude::*, solana_program}; use lib::hash::CryptoHash; use memory::Ptr; @@ -290,38 +290,38 @@ fn test_header_encoding() { assert_eq!(Some(hdr), got_hdr); } -// #[test] -// fn test_trie_sanity() { -// const ONE: CryptoHash = CryptoHash([1; 32]); - -// let key = solana_program::pubkey::Pubkey::new_unique(); -// let mut lamports: u64 = 10 * solana_program::native_token::LAMPORTS_PER_SOL; -// let mut data = [0; SZ * 1000]; -// let owner = solana_program::pubkey::Pubkey::new_unique(); -// let account = solana_program::account_info::AccountInfo::new( -// /* key: */ &key, -// /* is signer: */ false, -// /* is writable: */ true, -// /* lamports: */ &mut lamports, -// /* data: */ &mut data[..], -// /* owner: */ &owner, -// /* executable: */ false, -// /* rent_epoch: */ 42, -// ); - -// { -// let mut trie = AccountTrie::new(account.data.borrow_mut()).unwrap(); -// assert_eq!(Ok(None), trie.get(&[0])); - -// assert_eq!(Ok(()), trie.set(&[0], &ONE)); -// assert_eq!(Ok(Some(ONE.clone())), trie.get(&[0])); -// } - -// { -// let mut trie = AccountTrie::new(account.data.borrow_mut()).unwrap(); -// assert_eq!(Ok(Some(ONE.clone())), trie.get(&[0])); - -// assert_eq!(Ok(()), trie.seal(&[0])); -// assert_eq!(Err(sealable_trie::Error::Sealed), trie.get(&[0])); -// } -// } +#[test] +fn test_trie_sanity() { + const ONE: CryptoHash = CryptoHash([1; 32]); + + let key = solana_program::pubkey::Pubkey::new_unique(); + let mut lamports: u64 = 10 * solana_program::native_token::LAMPORTS_PER_SOL; + let mut data = [0; SZ * 1000]; + let owner = solana_program::pubkey::Pubkey::new_unique(); + let account = solana_program::account_info::AccountInfo::new( + /* key: */ &key, + /* is signer: */ false, + /* is writable: */ true, + /* lamports: */ &mut lamports, + /* data: */ &mut data[..], + /* owner: */ &owner, + /* executable: */ false, + /* rent_epoch: */ 42, + ); + + { + let mut trie = AccountTrie::new(account.data.borrow_mut()).unwrap(); + assert_eq!(Ok(None), trie.get(&[0])); + + assert_eq!(Ok(()), trie.set(&[0], &ONE)); + assert_eq!(Ok(Some(ONE.clone())), trie.get(&[0])); + } + + { + let mut trie = AccountTrie::new(account.data.borrow_mut()).unwrap(); + assert_eq!(Ok(Some(ONE.clone())), trie.get(&[0])); + + assert_eq!(Ok(()), trie.seal(&[0])); + assert_eq!(Err(sealable_trie::Error::Sealed), trie.get(&[0])); + } +} From b04dac97971a15845a3af8569b036e579726d109 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Wed, 18 Oct 2023 19:05:32 +0530 Subject: [PATCH 07/12] sealing receipt in trie --- .../solana-ibc/src/execution_context.rs | 24 +++++------ .../solana-ibc/programs/solana-ibc/src/lib.rs | 40 +++++++++---------- .../programs/solana-ibc/src/tests.rs | 3 +- .../programs/solana-ibc/src/trie.rs | 4 +- 4 files changed, 35 insertions(+), 36 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index 4f499cd2..f29a3763 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -35,9 +35,6 @@ type Result = core::result::Result; const CONNECTION_ID_PREFIX: &str = "connection-"; const CHANNEL_ID_PREFIX: &str = "channel-"; -const DEFAULT_PORT_ID: &str = "defaultPort"; -const TRANSFER_PORT_ID: &str = "transfer"; - impl ClientExecutionContext for SolanaIbcStorage<'_, '_> { type ClientValidationContext = Self; type AnyClientState = AnyClientState; @@ -65,7 +62,7 @@ impl ClientExecutionContext for SolanaIbcStorage<'_, '_> { let client_state_hash = borsh::to_vec(&serialized_client_state).unwrap(); trie.set( - &client_state_trie_key, + client_state_trie_key, &lib::hash::CryptoHash::digest(&client_state_hash), ) .unwrap(); @@ -101,7 +98,7 @@ impl ClientExecutionContext for SolanaIbcStorage<'_, '_> { let consensus_state_hash = borsh::to_vec(&serialized_consensus_state).unwrap(); trie.set( - &consensus_state_trie_key, + consensus_state_trie_key, &lib::hash::CryptoHash::digest(&consensus_state_hash), ) .unwrap(); @@ -219,7 +216,7 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { let consensus_state_hash = borsh::to_vec(&serialized_connection_end).unwrap(); trie.set( - &consensus_state_trie_key, + consensus_state_trie_key, &lib::hash::CryptoHash::digest(&consensus_state_hash), ) .unwrap(); @@ -275,7 +272,7 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { .to_vec(); let trie = self.trie.as_mut().unwrap(); trie.set( - &commitment_trie_key, + commitment_trie_key, &lib::hash::CryptoHash::digest(&commitment.into_vec()), ) .unwrap(); @@ -329,7 +326,8 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { } .to_vec(); let trie = self.trie.as_mut().unwrap(); - trie.set(&receipt_trie_key, &lib::hash::CryptoHash::DEFAULT).unwrap(); + trie.set(receipt_trie_key, &lib::hash::CryptoHash::DEFAULT).unwrap(); + trie.seal(receipt_trie_key).unwrap(); record_packet_sequence( &mut self.packet_receipt_sequence_sets, &receipt_path.port_id, @@ -361,7 +359,7 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { .to_vec(); let trie = self.trie.as_mut().unwrap(); trie.set( - &ack_commitment_trie_key, + ack_commitment_trie_key, &lib::hash::CryptoHash::digest(&ack_commitment.into_vec()), ) .unwrap(); @@ -416,7 +414,7 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { let trie = self.trie.as_mut().unwrap(); let channel_end_hash = borsh::to_vec(&serialized_channel_end).unwrap(); trie.set( - &channel_end_trie_key, + channel_end_trie_key, &lib::hash::CryptoHash::digest(&channel_end_hash), ) .unwrap(); @@ -454,7 +452,7 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { let seq_in_bytes = seq_in_u64.to_be_bytes(); trie.set( - &next_seq_send_trie_key, + next_seq_send_trie_key, &lib::hash::CryptoHash::digest(&seq_in_bytes), ) .unwrap(); @@ -488,7 +486,7 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { let seq_in_bytes = seq_in_u64.to_be_bytes(); trie.set( - &next_seq_recv_trie_key, + next_seq_recv_trie_key, &lib::hash::CryptoHash::digest(&seq_in_bytes), ) .unwrap(); @@ -517,7 +515,7 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { let seq_in_bytes = seq_in_u64.to_be_bytes(); trie.set( - &next_seq_ack_trie_key, + next_seq_ack_trie_key, &lib::hash::CryptoHash::digest(&seq_in_bytes), ) .unwrap(); diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 87217864..3656d9a0 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -45,7 +45,7 @@ pub mod solana_ibc { ) -> Result<()> { msg!("Called deliver method"); let _sender = ctx.accounts.sender.to_account_info(); - let mut solana_ibc_store: &mut SolanaIbcStorageTemp = + let solana_ibc_store: &mut SolanaIbcStorageTemp = &mut ctx.accounts.storage; msg!("This is solana_ibc_store {:?}", solana_ibc_store); @@ -68,7 +68,7 @@ pub mod solana_ibc { module_holder: solana_ibc_store.module_holder.clone(), clients: solana_ibc_store.clients.clone(), client_id_set: solana_ibc_store.client_id_set.clone(), - client_counter: solana_ibc_store.client_counter.clone(), + client_counter: solana_ibc_store.client_counter, client_processed_times: solana_ibc_store .client_processed_times .clone(), @@ -80,12 +80,12 @@ pub mod solana_ibc { .client_consensus_state_height_sets .clone(), connection_id_set: solana_ibc_store.connection_id_set.clone(), - connection_counter: solana_ibc_store.connection_counter.clone(), + connection_counter: solana_ibc_store.connection_counter, connections: solana_ibc_store.connections.clone(), channel_ends: solana_ibc_store.channel_ends.clone(), connection_to_client: solana_ibc_store.connection_to_client.clone(), port_channel_id_set: solana_ibc_store.port_channel_id_set.clone(), - channel_counter: solana_ibc_store.channel_counter.clone(), + channel_counter: solana_ibc_store.channel_counter, next_sequence_send: solana_ibc_store.next_sequence_send.clone(), next_sequence_recv: solana_ibc_store.next_sequence_recv.clone(), next_sequence_ack: solana_ibc_store.next_sequence_ack.clone(), @@ -107,7 +107,7 @@ pub mod solana_ibc { module_holder: solana_ibc_store.module_holder.clone(), clients: solana_ibc_store.clients.clone(), client_id_set: solana_ibc_store.client_id_set.clone(), - client_counter: solana_ibc_store.client_counter.clone(), + client_counter: solana_ibc_store.client_counter, client_processed_times: solana_ibc_store .client_processed_times .clone(), @@ -119,12 +119,12 @@ pub mod solana_ibc { .client_consensus_state_height_sets .clone(), connection_id_set: solana_ibc_store.connection_id_set.clone(), - connection_counter: solana_ibc_store.connection_counter.clone(), + connection_counter: solana_ibc_store.connection_counter, connections: solana_ibc_store.connections.clone(), channel_ends: solana_ibc_store.channel_ends.clone(), connection_to_client: solana_ibc_store.connection_to_client.clone(), port_channel_id_set: solana_ibc_store.port_channel_id_set.clone(), - channel_counter: solana_ibc_store.channel_counter.clone(), + channel_counter: solana_ibc_store.channel_counter, next_sequence_send: solana_ibc_store.next_sequence_send.clone(), next_sequence_recv: solana_ibc_store.next_sequence_recv.clone(), next_sequence_ack: solana_ibc_store.next_sequence_ack.clone(), @@ -168,7 +168,7 @@ pub mod solana_ibc { solana_ibc_store.client_id_set = solana_real_storage.client_id_set.clone(); solana_ibc_store.client_counter = - solana_real_storage.client_counter.clone(); + solana_real_storage.client_counter; solana_ibc_store.client_processed_times = solana_real_storage.client_processed_times.clone(); solana_ibc_store.client_processed_heights = @@ -180,7 +180,7 @@ pub mod solana_ibc { solana_ibc_store.connection_id_set = solana_real_storage.connection_id_set.clone(); solana_ibc_store.connection_counter = - solana_real_storage.connection_counter.clone(); + solana_real_storage.connection_counter; solana_ibc_store.connections = solana_real_storage.connections.clone(); solana_ibc_store.channel_ends = solana_real_storage.channel_ends.clone(); @@ -189,7 +189,7 @@ pub mod solana_ibc { solana_ibc_store.port_channel_id_set = solana_real_storage.port_channel_id_set.clone(); solana_ibc_store.channel_counter = - solana_real_storage.channel_counter.clone(); + solana_real_storage.channel_counter; solana_ibc_store.next_sequence_send = solana_real_storage.next_sequence_send.clone(); solana_ibc_store.next_sequence_recv = @@ -257,33 +257,33 @@ pub enum TrieKeyWithoutFields { impl TrieKey { - pub fn len(&self) -> usize { + fn len(&self) -> usize { size_of::() + match self { TrieKey::ClientState { client_id } => client_id.len(), - TrieKey::ConsensusState { client_id, epoch: u64, height } => { + TrieKey::ConsensusState { client_id, epoch: _u64, height: _ } => { client_id.len() + size_of::() + size_of::() } - TrieKey::Connection { connection_id } => size_of::(), - TrieKey::ChannelEnd { port_id, channel_id } => { + TrieKey::Connection { connection_id: _ } => size_of::(), + TrieKey::ChannelEnd { port_id, channel_id: _ } => { port_id.len() + size_of::() } - TrieKey::NextSequenceSend { port_id, channel_id } => { + TrieKey::NextSequenceSend { port_id, channel_id: _ } => { port_id.len() + size_of::() } - TrieKey::NextSequenceRecv { port_id, channel_id } => { + TrieKey::NextSequenceRecv { port_id, channel_id: _ } => { port_id.len() + size_of::() } - TrieKey::NextSequenceAck { port_id, channel_id } => { + TrieKey::NextSequenceAck { port_id, channel_id: _ } => { port_id.len() + size_of::() } - TrieKey::Commitment { port_id, channel_id, sequence } => { + TrieKey::Commitment { port_id, channel_id: _, sequence: _ } => { port_id.len() + size_of::() + size_of::() } - TrieKey::Receipts { port_id, channel_id, sequence } => { + TrieKey::Receipts { port_id, channel_id: _, sequence: _ } => { port_id.len() + size_of::() + size_of::() } - TrieKey::Acks { port_id, channel_id, sequence } => { + TrieKey::Acks { port_id, channel_id: _, sequence: _ } => { port_id.len() + size_of::() + size_of::() } } diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index de885df8..2bb206d7 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -19,9 +19,8 @@ use ibc::mock::header::MockHeader; use ibc::Any; use ibc_proto::protobuf::Protobuf; -use crate::trie::AccountTrie; use crate::{ - accounts, instruction, AnyCheck, SolanaIbcStorage, SolanaIbcStorageTemp, + accounts, instruction, AnyCheck, SolanaIbcStorageTemp, ID, SOLANA_IBC_STORAGE_SEED, TEST_TRIE_SEED, }; diff --git a/solana/solana-ibc/programs/solana-ibc/src/trie.rs b/solana/solana-ibc/programs/solana-ibc/src/trie.rs index 92c22735..d3577ada 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/trie.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/trie.rs @@ -2,12 +2,14 @@ use core::cell::RefMut; use core::mem::ManuallyDrop; use std::result::Result; -use anchor_lang::{prelude::*, solana_program}; use lib::hash::CryptoHash; use memory::Ptr; use crate::magic; +#[cfg(test)] +use anchor_lang::solana_program; + type DataRef<'a, 'b> = RefMut<'a, &'b mut [u8]>; const SZ: usize = sealable_trie::nodes::RawNode::SIZE; From b7bb64807565f3f9ed855ec78d49942b9b72a058 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Wed, 18 Oct 2023 20:56:53 +0530 Subject: [PATCH 08/12] added from impl for trie key --- .../solana-ibc/src/execution_context.rs | 86 +----- .../solana-ibc/programs/solana-ibc/src/lib.rs | 152 +--------- .../programs/solana-ibc/src/tests.rs | 4 +- .../programs/solana-ibc/src/trie.rs | 5 +- .../programs/solana-ibc/src/trie_key.rs | 265 ++++++++++++++++++ 5 files changed, 286 insertions(+), 226 deletions(-) create mode 100644 solana/solana-ibc/programs/solana-ibc/src/trie_key.rs diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index f29a3763..46104ec4 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -25,16 +25,14 @@ use ibc::Height; use crate::client_state::AnyClientState; use crate::consensus_state::AnyConsensusState; +use crate::trie_key::TrieKey; use crate::{ EmitIBCEvent, HostHeight, InnerChannelId, InnerHeight, InnerPortId, - InnerSequence, SolanaIbcStorage, SolanaTimestamp, TrieKey, + InnerSequence, SolanaIbcStorage, SolanaTimestamp, }; type Result = core::result::Result; -const CONNECTION_ID_PREFIX: &str = "connection-"; -const CHANNEL_ID_PREFIX: &str = "channel-"; - impl ClientExecutionContext for SolanaIbcStorage<'_, '_> { type ClientValidationContext = Self; type AnyClientState = AnyClientState; @@ -205,18 +203,12 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { let serialized_connection_end = serde_json::to_string(&connection_end).unwrap(); - let connection_prefix_length = CONNECTION_ID_PREFIX.len(); - let connection_id = - &connection_path.0.to_string()[connection_prefix_length..]; - let consensus_state_trie_key = &TrieKey::Connection { - connection_id: connection_id.parse().unwrap(), - } - .to_vec(); + let connection_trie_key = &TrieKey::from(connection_path).to_vec(); let trie = self.trie.as_mut().unwrap(); let consensus_state_hash = borsh::to_vec(&serialized_connection_end).unwrap(); trie.set( - consensus_state_trie_key, + connection_trie_key, &lib::hash::CryptoHash::digest(&consensus_state_hash), ) .unwrap(); @@ -260,16 +252,7 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { commitment_path, commitment ); - let channel_prefix_length = CHANNEL_ID_PREFIX.len(); - let channel_id = - &commitment_path.channel_id.to_string()[channel_prefix_length..]; - - let commitment_trie_key = &TrieKey::Commitment { - port_id: commitment_path.port_id.clone().to_string(), - channel_id: channel_id.parse().unwrap(), - sequence: u64::from(commitment_path.sequence), - } - .to_vec(); + let commitment_trie_key = &TrieKey::from(commitment_path).to_vec(); let trie = self.trie.as_mut().unwrap(); trie.set( commitment_trie_key, @@ -315,16 +298,7 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { receipt_path, receipt ); - let channel_prefix_length = CHANNEL_ID_PREFIX.len(); - let channel_id = - &receipt_path.channel_id.to_string()[channel_prefix_length..]; - - let receipt_trie_key = &TrieKey::Receipts { - port_id: receipt_path.port_id.clone().to_string(), - channel_id: channel_id.parse().unwrap(), - sequence: u64::from(receipt_path.sequence), - } - .to_vec(); + let receipt_trie_key = &TrieKey::from(receipt_path).to_vec(); let trie = self.trie.as_mut().unwrap(); trie.set(receipt_trie_key, &lib::hash::CryptoHash::DEFAULT).unwrap(); trie.seal(receipt_trie_key).unwrap(); @@ -347,16 +321,7 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { ack_path, ack_commitment ); - let channel_prefix_length = CHANNEL_ID_PREFIX.len(); - let channel_id = - &ack_path.channel_id.to_string()[channel_prefix_length..]; - - let ack_commitment_trie_key = &TrieKey::Acks { - port_id: ack_path.port_id.clone().to_string(), - channel_id: channel_id.parse().unwrap(), - sequence: u64::from(ack_path.sequence), - } - .to_vec(); + let ack_commitment_trie_key = &TrieKey::from(ack_path).to_vec(); let trie = self.trie.as_mut().unwrap(); trie.set( ack_commitment_trie_key, @@ -402,15 +367,7 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { let serialized_channel_end = serde_json::to_string(&channel_end).unwrap(); - let channel_prefix_length = CHANNEL_ID_PREFIX.len(); - let channel_id = - &channel_end_path.1.to_string()[channel_prefix_length..]; - - let channel_end_trie_key = &TrieKey::ChannelEnd { - port_id: channel_end_path.0.clone().to_string(), - channel_id: channel_id.parse().unwrap(), - } - .to_vec(); + let channel_end_trie_key = &TrieKey::from(channel_end_path).to_vec(); let trie = self.trie.as_mut().unwrap(); let channel_end_hash = borsh::to_vec(&serialized_channel_end).unwrap(); trie.set( @@ -439,14 +396,7 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { let seq_send_key = (seq_send_path.0.to_string(), seq_send_path.1.to_string()); - let channel_prefix_length = CHANNEL_ID_PREFIX.len(); - let channel_id = &seq_send_path.1.to_string()[channel_prefix_length..]; - - let next_seq_send_trie_key = &TrieKey::NextSequenceSend { - port_id: seq_send_path.0.clone().to_string(), - channel_id: channel_id.parse().unwrap(), - } - .to_vec(); + let next_seq_send_trie_key = &TrieKey::from(seq_send_path).to_vec(); let trie = self.trie.as_mut().unwrap(); let seq_in_u64: u64 = seq.into(); let seq_in_bytes = seq_in_u64.to_be_bytes(); @@ -473,14 +423,7 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { ); let seq_recv_key = (seq_recv_path.0.to_string(), seq_recv_path.1.to_string()); - let channel_prefix_length = CHANNEL_ID_PREFIX.len(); - let channel_id = &seq_recv_path.1.to_string()[channel_prefix_length..]; - - let next_seq_recv_trie_key = &TrieKey::NextSequenceRecv { - port_id: seq_recv_path.0.clone().to_string(), - channel_id: channel_id.parse().unwrap(), - } - .to_vec(); + let next_seq_recv_trie_key = &TrieKey::from(seq_recv_path).to_vec(); let trie = self.trie.as_mut().unwrap(); let seq_in_u64: u64 = seq.into(); let seq_in_bytes = seq_in_u64.to_be_bytes(); @@ -502,14 +445,7 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { msg!("store_next_sequence_ack: path: {}, seq: {:?}", seq_ack_path, seq); let seq_ack_key = (seq_ack_path.0.to_string(), seq_ack_path.1.to_string()); - let channel_prefix_length = CHANNEL_ID_PREFIX.len(); - let channel_id = &seq_ack_path.1.to_string()[channel_prefix_length..]; - - let next_seq_ack_trie_key = &TrieKey::NextSequenceAck { - port_id: seq_ack_path.0.clone().to_string(), - channel_id: channel_id.parse().unwrap(), - } - .to_vec(); + let next_seq_ack_trie_key = &TrieKey::from(seq_ack_path).to_vec(); let trie = self.trie.as_mut().unwrap(); let seq_in_u64: u64 = seq.into(); let seq_in_bytes = seq_in_u64.to_be_bytes(); diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 3656d9a0..221d7b8d 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -3,16 +3,18 @@ #![allow(clippy::result_large_err)] use std::collections::BTreeMap; -use std::mem::size_of; use anchor_lang::prelude::*; use borsh::{BorshDeserialize, BorshSerialize}; use ibc::core::ics24_host::identifier::PortId; + use ibc::core::router::{Module, ModuleId, Router}; use module_holder::ModuleHolder; const SOLANA_IBC_STORAGE_SEED: &[u8] = b"solana_ibc_storage"; const TEST_TRIE_SEED: &[u8] = b"test_trie"; +pub const CONNECTION_ID_PREFIX: &str = "connection-"; +pub const CHANNEL_ID_PREFIX: &str = "channel-"; declare_id!("EnfDJsAK7BGgetnmKzBx86CsgC5kfSPcsktFCQ4YLC81"); @@ -24,6 +26,7 @@ mod module_holder; mod tests; mod transfer; mod trie; +mod trie_key; mod validation_context; // mod client_context; @@ -167,8 +170,7 @@ pub mod solana_ibc { solana_ibc_store.clients = solana_real_storage.clients.clone(); solana_ibc_store.client_id_set = solana_real_storage.client_id_set.clone(); - solana_ibc_store.client_counter = - solana_real_storage.client_counter; + solana_ibc_store.client_counter = solana_real_storage.client_counter; solana_ibc_store.client_processed_times = solana_real_storage.client_processed_times.clone(); solana_ibc_store.client_processed_heights = @@ -188,8 +190,7 @@ pub mod solana_ibc { solana_real_storage.connection_to_client.clone(); solana_ibc_store.port_channel_id_set = solana_real_storage.port_channel_id_set.clone(); - solana_ibc_store.channel_counter = - solana_real_storage.channel_counter; + solana_ibc_store.channel_counter = solana_real_storage.channel_counter; solana_ibc_store.next_sequence_send = solana_real_storage.next_sequence_send.clone(); solana_ibc_store.next_sequence_recv = @@ -228,147 +229,6 @@ pub struct Deliver<'info> { pub system_program: Program<'info, System>, } -pub enum TrieKey { - ClientState { client_id: String }, - ConsensusState { client_id: String, epoch: u64, height: u64 }, - Connection { connection_id: u32 }, - ChannelEnd { port_id: String, channel_id: u32 }, - NextSequenceSend { port_id: String, channel_id: u32 }, - NextSequenceRecv { port_id: String, channel_id: u32 }, - NextSequenceAck { port_id: String, channel_id: u32 }, - Commitment { port_id: String, channel_id: u32, sequence: u64 }, - Receipts { port_id: String, channel_id: u32, sequence: u64 }, - Acks { port_id: String, channel_id: u32, sequence: u64 }, -} - -#[repr(u8)] -pub enum TrieKeyWithoutFields { - ClientState = 1, - ConsensusState = 2, - Connection = 3, - ChannelEnd = 4, - NextSequenceSend = 5, - NextSequenceRecv = 6, - NextSequenceAck = 7, - Commitment = 8, - Receipts = 9, - Acks = 10, -} - - -impl TrieKey { - fn len(&self) -> usize { - size_of::() + - match self { - TrieKey::ClientState { client_id } => client_id.len(), - TrieKey::ConsensusState { client_id, epoch: _u64, height: _ } => { - client_id.len() + size_of::() + size_of::() - } - TrieKey::Connection { connection_id: _ } => size_of::(), - TrieKey::ChannelEnd { port_id, channel_id: _ } => { - port_id.len() + size_of::() - } - TrieKey::NextSequenceSend { port_id, channel_id: _ } => { - port_id.len() + size_of::() - } - TrieKey::NextSequenceRecv { port_id, channel_id: _ } => { - port_id.len() + size_of::() - } - TrieKey::NextSequenceAck { port_id, channel_id: _ } => { - port_id.len() + size_of::() - } - TrieKey::Commitment { port_id, channel_id: _, sequence: _ } => { - port_id.len() + size_of::() + size_of::() - } - TrieKey::Receipts { port_id, channel_id: _, sequence: _ } => { - port_id.len() + size_of::() + size_of::() - } - TrieKey::Acks { port_id, channel_id: _, sequence: _ } => { - port_id.len() + size_of::() + size_of::() - } - } - } - - pub fn append_into(&self, buf: &mut Vec) { - let expected_len = self.len(); - let start_len = buf.len(); - buf.reserve(self.len()); - match self { - TrieKey::ClientState { client_id } => { - buf.push(TrieKeyWithoutFields::ClientState as u8); - buf.extend(client_id.as_bytes()); - } - TrieKey::ConsensusState { client_id, epoch, height } => { - buf.push(TrieKeyWithoutFields::ConsensusState as u8); - buf.extend(client_id.as_bytes()); - buf.push(TrieKeyWithoutFields::ConsensusState as u8); - buf.extend(height.to_be_bytes()); - buf.push(TrieKeyWithoutFields::ConsensusState as u8); - buf.extend(epoch.to_be_bytes()) - } - TrieKey::Connection { connection_id } => { - buf.push(TrieKeyWithoutFields::Connection as u8); - buf.extend(connection_id.to_be_bytes()) - } - TrieKey::ChannelEnd { port_id, channel_id } => { - buf.push(TrieKeyWithoutFields::ChannelEnd as u8); - buf.extend(port_id.as_bytes()); - buf.push(TrieKeyWithoutFields::ChannelEnd as u8); - buf.extend(channel_id.to_be_bytes()); - } - TrieKey::NextSequenceSend { port_id, channel_id } => { - buf.push(TrieKeyWithoutFields::NextSequenceSend as u8); - buf.extend(port_id.as_bytes()); - buf.push(TrieKeyWithoutFields::NextSequenceSend as u8); - buf.extend(channel_id.to_be_bytes()); - } - TrieKey::NextSequenceRecv { port_id, channel_id } => { - buf.push(TrieKeyWithoutFields::NextSequenceRecv as u8); - buf.extend(port_id.as_bytes()); - buf.push(TrieKeyWithoutFields::NextSequenceRecv as u8); - buf.extend(channel_id.to_be_bytes()); - } - TrieKey::NextSequenceAck { port_id, channel_id } => { - buf.push(TrieKeyWithoutFields::NextSequenceAck as u8); - buf.extend(port_id.as_bytes()); - buf.push(TrieKeyWithoutFields::NextSequenceAck as u8); - buf.extend(channel_id.to_be_bytes()); - } - TrieKey::Commitment { port_id, channel_id, sequence } => { - buf.push(TrieKeyWithoutFields::Commitment as u8); - buf.extend(port_id.as_bytes()); - buf.push(TrieKeyWithoutFields::Commitment as u8); - buf.extend(channel_id.to_be_bytes()); - buf.push(TrieKeyWithoutFields::Commitment as u8); - buf.extend(sequence.to_be_bytes()); - } - TrieKey::Receipts { port_id, channel_id, sequence } => { - buf.push(TrieKeyWithoutFields::Receipts as u8); - buf.extend(port_id.as_bytes()); - buf.push(TrieKeyWithoutFields::Receipts as u8); - buf.extend(channel_id.to_be_bytes()); - buf.push(TrieKeyWithoutFields::Receipts as u8); - buf.extend(sequence.to_be_bytes()); - } - TrieKey::Acks { port_id, channel_id, sequence } => { - buf.push(TrieKeyWithoutFields::Acks as u8); - buf.extend(port_id.as_bytes()); - buf.push(TrieKeyWithoutFields::Acks as u8); - buf.extend(channel_id.to_be_bytes()); - buf.push(TrieKeyWithoutFields::Acks as u8); - buf.extend(sequence.to_be_bytes()); - } - } - debug_assert_eq!(expected_len, buf.len() - start_len); - } - - pub fn to_vec(&self) -> Vec { - let mut buf = Vec::with_capacity(self.len()); - self.append_into(&mut buf); - buf - } -} - #[event] pub struct EmitIBCEvent { pub ibc_event: Vec, diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index 2bb206d7..0386585d 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -20,8 +20,8 @@ use ibc::Any; use ibc_proto::protobuf::Protobuf; use crate::{ - accounts, instruction, AnyCheck, SolanaIbcStorageTemp, - ID, SOLANA_IBC_STORAGE_SEED, TEST_TRIE_SEED, + accounts, instruction, AnyCheck, SolanaIbcStorageTemp, ID, + SOLANA_IBC_STORAGE_SEED, TEST_TRIE_SEED, }; const TYPE_URL: &str = "/ibc.core.client.v1.MsgCreateClient"; diff --git a/solana/solana-ibc/programs/solana-ibc/src/trie.rs b/solana/solana-ibc/programs/solana-ibc/src/trie.rs index d3577ada..d7598476 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/trie.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/trie.rs @@ -2,14 +2,13 @@ use core::cell::RefMut; use core::mem::ManuallyDrop; use std::result::Result; +#[cfg(test)] +use anchor_lang::solana_program; use lib::hash::CryptoHash; use memory::Ptr; use crate::magic; -#[cfg(test)] -use anchor_lang::solana_program; - type DataRef<'a, 'b> = RefMut<'a, &'b mut [u8]>; const SZ: usize = sealable_trie::nodes::RawNode::SIZE; diff --git a/solana/solana-ibc/programs/solana-ibc/src/trie_key.rs b/solana/solana-ibc/programs/solana-ibc/src/trie_key.rs new file mode 100644 index 00000000..15331af5 --- /dev/null +++ b/solana/solana-ibc/programs/solana-ibc/src/trie_key.rs @@ -0,0 +1,265 @@ +use ibc::core::ics24_host::path::{ + AckPath, ChannelEndPath, CommitmentPath, ConnectionPath, ReceiptPath, + SeqAckPath, SeqRecvPath, SeqSendPath, +}; +use crate::{CHANNEL_ID_PREFIX, CONNECTION_ID_PREFIX}; +use std::mem::size_of; + +pub enum TrieKey { + ClientState { client_id: String }, + ConsensusState { client_id: String, epoch: u64, height: u64 }, + Connection { connection_id: u32 }, + ChannelEnd { port_id: String, channel_id: u32 }, + NextSequenceSend { port_id: String, channel_id: u32 }, + NextSequenceRecv { port_id: String, channel_id: u32 }, + NextSequenceAck { port_id: String, channel_id: u32 }, + Commitment { port_id: String, channel_id: u32, sequence: u64 }, + Receipts { port_id: String, channel_id: u32, sequence: u64 }, + Acks { port_id: String, channel_id: u32, sequence: u64 }, +} + +#[repr(u8)] +pub enum TrieKeyWithoutFields { + ClientState = 1, + ConsensusState = 2, + Connection = 3, + ChannelEnd = 4, + NextSequenceSend = 5, + NextSequenceRecv = 6, + NextSequenceAck = 7, + Commitment = 8, + Receipts = 9, + Acks = 10, +} + +impl From<&ReceiptPath> for TrieKey { + fn from(path: &ReceiptPath) -> Self { + let channel_id = path + .channel_id + .as_str() + .strip_prefix(CHANNEL_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::Receipts { + port_id: path.port_id.to_string(), + channel_id, + sequence: u64::from(path.sequence), + } + } +} + +impl From<&AckPath> for TrieKey { + fn from(path: &AckPath) -> Self { + let channel_id = path + .channel_id + .as_str() + .strip_prefix(CHANNEL_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::Acks { + port_id: path.port_id.to_string(), + channel_id, + sequence: u64::from(path.sequence), + } + } +} + +impl From<&CommitmentPath> for TrieKey { + fn from(path: &CommitmentPath) -> Self { + let channel_id = path + .channel_id + .as_str() + .strip_prefix(CHANNEL_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::Commitment { + port_id: path.port_id.to_string(), + channel_id, + sequence: u64::from(path.sequence), + } + } +} + +impl From<&SeqRecvPath> for TrieKey { + fn from(path: &SeqRecvPath) -> Self { + let channel_id = path + .1 + .as_str() + .strip_prefix(CHANNEL_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::NextSequenceRecv { port_id: path.0.to_string(), channel_id } + } +} + +impl From<&SeqSendPath> for TrieKey { + fn from(path: &SeqSendPath) -> Self { + let channel_id = path + .1 + .as_str() + .strip_prefix(CHANNEL_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::NextSequenceSend { port_id: path.0.to_string(), channel_id } + } +} + +impl From<&SeqAckPath> for TrieKey { + fn from(path: &SeqAckPath) -> Self { + let channel_id = path + .1 + .as_str() + .strip_prefix(CHANNEL_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::NextSequenceAck { port_id: path.0.to_string(), channel_id } + } +} + +impl From<&ChannelEndPath> for TrieKey { + fn from(path: &ChannelEndPath) -> Self { + let channel_id = path + .1 + .as_str() + .strip_prefix(CHANNEL_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::ChannelEnd { port_id: path.0.to_string(), channel_id } + } +} + +impl From<&ConnectionPath> for TrieKey { + fn from(path: &ConnectionPath) -> Self { + let connection_id = path + .0 + .as_str() + .strip_prefix(CONNECTION_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::Connection { connection_id } + } +} + + +impl TrieKey { + fn len(&self) -> usize { + size_of::() + + match self { + TrieKey::ClientState { client_id } => client_id.len(), + TrieKey::ConsensusState { + client_id, + epoch: _u64, + height: _, + } => client_id.len() + size_of::() + size_of::(), + TrieKey::Connection { connection_id: _ } => size_of::(), + TrieKey::ChannelEnd { port_id, channel_id: _ } => { + port_id.len() + size_of::() + } + TrieKey::NextSequenceSend { port_id, channel_id: _ } => { + port_id.len() + size_of::() + } + TrieKey::NextSequenceRecv { port_id, channel_id: _ } => { + port_id.len() + size_of::() + } + TrieKey::NextSequenceAck { port_id, channel_id: _ } => { + port_id.len() + size_of::() + } + TrieKey::Commitment { port_id, channel_id: _, sequence: _ } => { + port_id.len() + size_of::() + size_of::() + } + TrieKey::Receipts { port_id, channel_id: _, sequence: _ } => { + port_id.len() + size_of::() + size_of::() + } + TrieKey::Acks { port_id, channel_id: _, sequence: _ } => { + port_id.len() + size_of::() + size_of::() + } + } + } + + pub fn append_into(&self, buf: &mut Vec) { + let expected_len = self.len(); + let start_len = buf.len(); + buf.reserve(self.len()); + match self { + TrieKey::ClientState { client_id } => { + buf.push(TrieKeyWithoutFields::ClientState as u8); + buf.extend(client_id.as_bytes()); + } + TrieKey::ConsensusState { client_id, epoch, height } => { + buf.push(TrieKeyWithoutFields::ConsensusState as u8); + buf.extend(client_id.as_bytes()); + buf.push(TrieKeyWithoutFields::ConsensusState as u8); + buf.extend(height.to_be_bytes()); + buf.push(TrieKeyWithoutFields::ConsensusState as u8); + buf.extend(epoch.to_be_bytes()) + } + TrieKey::Connection { connection_id } => { + buf.push(TrieKeyWithoutFields::Connection as u8); + buf.extend(connection_id.to_be_bytes()) + } + TrieKey::ChannelEnd { port_id, channel_id } => { + buf.push(TrieKeyWithoutFields::ChannelEnd as u8); + buf.extend(port_id.as_bytes()); + buf.push(TrieKeyWithoutFields::ChannelEnd as u8); + buf.extend(channel_id.to_be_bytes()); + } + TrieKey::NextSequenceSend { port_id, channel_id } => { + buf.push(TrieKeyWithoutFields::NextSequenceSend as u8); + buf.extend(port_id.as_bytes()); + buf.push(TrieKeyWithoutFields::NextSequenceSend as u8); + buf.extend(channel_id.to_be_bytes()); + } + TrieKey::NextSequenceRecv { port_id, channel_id } => { + buf.push(TrieKeyWithoutFields::NextSequenceRecv as u8); + buf.extend(port_id.as_bytes()); + buf.push(TrieKeyWithoutFields::NextSequenceRecv as u8); + buf.extend(channel_id.to_be_bytes()); + } + TrieKey::NextSequenceAck { port_id, channel_id } => { + buf.push(TrieKeyWithoutFields::NextSequenceAck as u8); + buf.extend(port_id.as_bytes()); + buf.push(TrieKeyWithoutFields::NextSequenceAck as u8); + buf.extend(channel_id.to_be_bytes()); + } + TrieKey::Commitment { port_id, channel_id, sequence } => { + buf.push(TrieKeyWithoutFields::Commitment as u8); + buf.extend(port_id.as_bytes()); + buf.push(TrieKeyWithoutFields::Commitment as u8); + buf.extend(channel_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::Commitment as u8); + buf.extend(sequence.to_be_bytes()); + } + TrieKey::Receipts { port_id, channel_id, sequence } => { + buf.push(TrieKeyWithoutFields::Receipts as u8); + buf.extend(port_id.as_bytes()); + buf.push(TrieKeyWithoutFields::Receipts as u8); + buf.extend(channel_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::Receipts as u8); + buf.extend(sequence.to_be_bytes()); + } + TrieKey::Acks { port_id, channel_id, sequence } => { + buf.push(TrieKeyWithoutFields::Acks as u8); + buf.extend(port_id.as_bytes()); + buf.push(TrieKeyWithoutFields::Acks as u8); + buf.extend(channel_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::Acks as u8); + buf.extend(sequence.to_be_bytes()); + } + } + debug_assert_eq!(expected_len, buf.len() - start_len); + } + + pub fn to_vec(&self) -> Vec { + let mut buf = Vec::with_capacity(self.len()); + self.append_into(&mut buf); + buf + } +} \ No newline at end of file From dcb602e99e61f657d7e6da3b0e6fe395afb12595 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Wed, 18 Oct 2023 21:02:12 +0530 Subject: [PATCH 09/12] converting serialized string to bytes without borsh --- .../solana-ibc/src/execution_context.rs | 19 +- .../solana-ibc/programs/solana-ibc/src/lib.rs | 1 - .../programs/solana-ibc/src/trie_key.rs | 454 +++++++++--------- 3 files changed, 236 insertions(+), 238 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index 46104ec4..54a3e476 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -57,11 +57,9 @@ impl ClientExecutionContext for SolanaIbcStorage<'_, '_> { } .to_vec(); let trie = self.trie.as_mut().unwrap(); - let client_state_hash = - borsh::to_vec(&serialized_client_state).unwrap(); trie.set( client_state_trie_key, - &lib::hash::CryptoHash::digest(&client_state_hash), + &lib::hash::CryptoHash::digest(serialized_client_state.as_bytes()), ) .unwrap(); @@ -93,11 +91,11 @@ impl ClientExecutionContext for SolanaIbcStorage<'_, '_> { } .to_vec(); let trie = self.trie.as_mut().unwrap(); - let consensus_state_hash = - borsh::to_vec(&serialized_consensus_state).unwrap(); trie.set( consensus_state_trie_key, - &lib::hash::CryptoHash::digest(&consensus_state_hash), + &lib::hash::CryptoHash::digest( + serialized_consensus_state.as_bytes(), + ), ) .unwrap(); @@ -205,11 +203,11 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { serde_json::to_string(&connection_end).unwrap(); let connection_trie_key = &TrieKey::from(connection_path).to_vec(); let trie = self.trie.as_mut().unwrap(); - let consensus_state_hash = - borsh::to_vec(&serialized_connection_end).unwrap(); trie.set( connection_trie_key, - &lib::hash::CryptoHash::digest(&consensus_state_hash), + &lib::hash::CryptoHash::digest( + serialized_connection_end.as_bytes(), + ), ) .unwrap(); @@ -369,10 +367,9 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { serde_json::to_string(&channel_end).unwrap(); let channel_end_trie_key = &TrieKey::from(channel_end_path).to_vec(); let trie = self.trie.as_mut().unwrap(); - let channel_end_hash = borsh::to_vec(&serialized_channel_end).unwrap(); trie.set( channel_end_trie_key, - &lib::hash::CryptoHash::digest(&channel_end_hash), + &lib::hash::CryptoHash::digest(serialized_channel_end.as_bytes()), ) .unwrap(); diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 221d7b8d..519a0203 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -7,7 +7,6 @@ use std::collections::BTreeMap; use anchor_lang::prelude::*; use borsh::{BorshDeserialize, BorshSerialize}; use ibc::core::ics24_host::identifier::PortId; - use ibc::core::router::{Module, ModuleId, Router}; use module_holder::ModuleHolder; diff --git a/solana/solana-ibc/programs/solana-ibc/src/trie_key.rs b/solana/solana-ibc/programs/solana-ibc/src/trie_key.rs index 15331af5..33cf8a5c 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/trie_key.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/trie_key.rs @@ -1,265 +1,267 @@ +use std::mem::size_of; + use ibc::core::ics24_host::path::{ - AckPath, ChannelEndPath, CommitmentPath, ConnectionPath, ReceiptPath, - SeqAckPath, SeqRecvPath, SeqSendPath, + AckPath, ChannelEndPath, CommitmentPath, ConnectionPath, ReceiptPath, + SeqAckPath, SeqRecvPath, SeqSendPath, }; + use crate::{CHANNEL_ID_PREFIX, CONNECTION_ID_PREFIX}; -use std::mem::size_of; pub enum TrieKey { - ClientState { client_id: String }, - ConsensusState { client_id: String, epoch: u64, height: u64 }, - Connection { connection_id: u32 }, - ChannelEnd { port_id: String, channel_id: u32 }, - NextSequenceSend { port_id: String, channel_id: u32 }, - NextSequenceRecv { port_id: String, channel_id: u32 }, - NextSequenceAck { port_id: String, channel_id: u32 }, - Commitment { port_id: String, channel_id: u32, sequence: u64 }, - Receipts { port_id: String, channel_id: u32, sequence: u64 }, - Acks { port_id: String, channel_id: u32, sequence: u64 }, + ClientState { client_id: String }, + ConsensusState { client_id: String, epoch: u64, height: u64 }, + Connection { connection_id: u32 }, + ChannelEnd { port_id: String, channel_id: u32 }, + NextSequenceSend { port_id: String, channel_id: u32 }, + NextSequenceRecv { port_id: String, channel_id: u32 }, + NextSequenceAck { port_id: String, channel_id: u32 }, + Commitment { port_id: String, channel_id: u32, sequence: u64 }, + Receipts { port_id: String, channel_id: u32, sequence: u64 }, + Acks { port_id: String, channel_id: u32, sequence: u64 }, } #[repr(u8)] pub enum TrieKeyWithoutFields { - ClientState = 1, - ConsensusState = 2, - Connection = 3, - ChannelEnd = 4, - NextSequenceSend = 5, - NextSequenceRecv = 6, - NextSequenceAck = 7, - Commitment = 8, - Receipts = 9, - Acks = 10, + ClientState = 1, + ConsensusState = 2, + Connection = 3, + ChannelEnd = 4, + NextSequenceSend = 5, + NextSequenceRecv = 6, + NextSequenceAck = 7, + Commitment = 8, + Receipts = 9, + Acks = 10, } impl From<&ReceiptPath> for TrieKey { - fn from(path: &ReceiptPath) -> Self { - let channel_id = path - .channel_id - .as_str() - .strip_prefix(CHANNEL_ID_PREFIX) - .unwrap() - .parse() - .unwrap(); - Self::Receipts { - port_id: path.port_id.to_string(), - channel_id, - sequence: u64::from(path.sequence), - } - } + fn from(path: &ReceiptPath) -> Self { + let channel_id = path + .channel_id + .as_str() + .strip_prefix(CHANNEL_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::Receipts { + port_id: path.port_id.to_string(), + channel_id, + sequence: u64::from(path.sequence), + } + } } impl From<&AckPath> for TrieKey { - fn from(path: &AckPath) -> Self { - let channel_id = path - .channel_id - .as_str() - .strip_prefix(CHANNEL_ID_PREFIX) - .unwrap() - .parse() - .unwrap(); - Self::Acks { - port_id: path.port_id.to_string(), - channel_id, - sequence: u64::from(path.sequence), - } - } + fn from(path: &AckPath) -> Self { + let channel_id = path + .channel_id + .as_str() + .strip_prefix(CHANNEL_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::Acks { + port_id: path.port_id.to_string(), + channel_id, + sequence: u64::from(path.sequence), + } + } } impl From<&CommitmentPath> for TrieKey { - fn from(path: &CommitmentPath) -> Self { - let channel_id = path - .channel_id - .as_str() - .strip_prefix(CHANNEL_ID_PREFIX) - .unwrap() - .parse() - .unwrap(); - Self::Commitment { - port_id: path.port_id.to_string(), - channel_id, - sequence: u64::from(path.sequence), - } - } + fn from(path: &CommitmentPath) -> Self { + let channel_id = path + .channel_id + .as_str() + .strip_prefix(CHANNEL_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::Commitment { + port_id: path.port_id.to_string(), + channel_id, + sequence: u64::from(path.sequence), + } + } } impl From<&SeqRecvPath> for TrieKey { - fn from(path: &SeqRecvPath) -> Self { - let channel_id = path - .1 - .as_str() - .strip_prefix(CHANNEL_ID_PREFIX) - .unwrap() - .parse() - .unwrap(); - Self::NextSequenceRecv { port_id: path.0.to_string(), channel_id } - } + fn from(path: &SeqRecvPath) -> Self { + let channel_id = path + .1 + .as_str() + .strip_prefix(CHANNEL_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::NextSequenceRecv { port_id: path.0.to_string(), channel_id } + } } impl From<&SeqSendPath> for TrieKey { - fn from(path: &SeqSendPath) -> Self { - let channel_id = path - .1 - .as_str() - .strip_prefix(CHANNEL_ID_PREFIX) - .unwrap() - .parse() - .unwrap(); - Self::NextSequenceSend { port_id: path.0.to_string(), channel_id } - } + fn from(path: &SeqSendPath) -> Self { + let channel_id = path + .1 + .as_str() + .strip_prefix(CHANNEL_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::NextSequenceSend { port_id: path.0.to_string(), channel_id } + } } impl From<&SeqAckPath> for TrieKey { - fn from(path: &SeqAckPath) -> Self { - let channel_id = path - .1 - .as_str() - .strip_prefix(CHANNEL_ID_PREFIX) - .unwrap() - .parse() - .unwrap(); - Self::NextSequenceAck { port_id: path.0.to_string(), channel_id } - } + fn from(path: &SeqAckPath) -> Self { + let channel_id = path + .1 + .as_str() + .strip_prefix(CHANNEL_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::NextSequenceAck { port_id: path.0.to_string(), channel_id } + } } impl From<&ChannelEndPath> for TrieKey { - fn from(path: &ChannelEndPath) -> Self { - let channel_id = path - .1 - .as_str() - .strip_prefix(CHANNEL_ID_PREFIX) - .unwrap() - .parse() - .unwrap(); - Self::ChannelEnd { port_id: path.0.to_string(), channel_id } - } + fn from(path: &ChannelEndPath) -> Self { + let channel_id = path + .1 + .as_str() + .strip_prefix(CHANNEL_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::ChannelEnd { port_id: path.0.to_string(), channel_id } + } } impl From<&ConnectionPath> for TrieKey { - fn from(path: &ConnectionPath) -> Self { - let connection_id = path - .0 - .as_str() - .strip_prefix(CONNECTION_ID_PREFIX) - .unwrap() - .parse() - .unwrap(); - Self::Connection { connection_id } - } + fn from(path: &ConnectionPath) -> Self { + let connection_id = path + .0 + .as_str() + .strip_prefix(CONNECTION_ID_PREFIX) + .unwrap() + .parse() + .unwrap(); + Self::Connection { connection_id } + } } impl TrieKey { - fn len(&self) -> usize { - size_of::() + - match self { - TrieKey::ClientState { client_id } => client_id.len(), - TrieKey::ConsensusState { - client_id, - epoch: _u64, - height: _, - } => client_id.len() + size_of::() + size_of::(), - TrieKey::Connection { connection_id: _ } => size_of::(), - TrieKey::ChannelEnd { port_id, channel_id: _ } => { - port_id.len() + size_of::() - } - TrieKey::NextSequenceSend { port_id, channel_id: _ } => { - port_id.len() + size_of::() - } - TrieKey::NextSequenceRecv { port_id, channel_id: _ } => { - port_id.len() + size_of::() - } - TrieKey::NextSequenceAck { port_id, channel_id: _ } => { - port_id.len() + size_of::() - } - TrieKey::Commitment { port_id, channel_id: _, sequence: _ } => { - port_id.len() + size_of::() + size_of::() - } - TrieKey::Receipts { port_id, channel_id: _, sequence: _ } => { - port_id.len() + size_of::() + size_of::() - } - TrieKey::Acks { port_id, channel_id: _, sequence: _ } => { - port_id.len() + size_of::() + size_of::() - } - } - } + fn len(&self) -> usize { + size_of::() + + match self { + TrieKey::ClientState { client_id } => client_id.len(), + TrieKey::ConsensusState { + client_id, + epoch: _u64, + height: _, + } => client_id.len() + size_of::() + size_of::(), + TrieKey::Connection { connection_id: _ } => size_of::(), + TrieKey::ChannelEnd { port_id, channel_id: _ } => { + port_id.len() + size_of::() + } + TrieKey::NextSequenceSend { port_id, channel_id: _ } => { + port_id.len() + size_of::() + } + TrieKey::NextSequenceRecv { port_id, channel_id: _ } => { + port_id.len() + size_of::() + } + TrieKey::NextSequenceAck { port_id, channel_id: _ } => { + port_id.len() + size_of::() + } + TrieKey::Commitment { port_id, channel_id: _, sequence: _ } => { + port_id.len() + size_of::() + size_of::() + } + TrieKey::Receipts { port_id, channel_id: _, sequence: _ } => { + port_id.len() + size_of::() + size_of::() + } + TrieKey::Acks { port_id, channel_id: _, sequence: _ } => { + port_id.len() + size_of::() + size_of::() + } + } + } - pub fn append_into(&self, buf: &mut Vec) { - let expected_len = self.len(); - let start_len = buf.len(); - buf.reserve(self.len()); - match self { - TrieKey::ClientState { client_id } => { - buf.push(TrieKeyWithoutFields::ClientState as u8); - buf.extend(client_id.as_bytes()); - } - TrieKey::ConsensusState { client_id, epoch, height } => { - buf.push(TrieKeyWithoutFields::ConsensusState as u8); - buf.extend(client_id.as_bytes()); - buf.push(TrieKeyWithoutFields::ConsensusState as u8); - buf.extend(height.to_be_bytes()); - buf.push(TrieKeyWithoutFields::ConsensusState as u8); - buf.extend(epoch.to_be_bytes()) - } - TrieKey::Connection { connection_id } => { - buf.push(TrieKeyWithoutFields::Connection as u8); - buf.extend(connection_id.to_be_bytes()) - } - TrieKey::ChannelEnd { port_id, channel_id } => { - buf.push(TrieKeyWithoutFields::ChannelEnd as u8); - buf.extend(port_id.as_bytes()); - buf.push(TrieKeyWithoutFields::ChannelEnd as u8); - buf.extend(channel_id.to_be_bytes()); - } - TrieKey::NextSequenceSend { port_id, channel_id } => { - buf.push(TrieKeyWithoutFields::NextSequenceSend as u8); - buf.extend(port_id.as_bytes()); - buf.push(TrieKeyWithoutFields::NextSequenceSend as u8); - buf.extend(channel_id.to_be_bytes()); - } - TrieKey::NextSequenceRecv { port_id, channel_id } => { - buf.push(TrieKeyWithoutFields::NextSequenceRecv as u8); - buf.extend(port_id.as_bytes()); - buf.push(TrieKeyWithoutFields::NextSequenceRecv as u8); - buf.extend(channel_id.to_be_bytes()); - } - TrieKey::NextSequenceAck { port_id, channel_id } => { - buf.push(TrieKeyWithoutFields::NextSequenceAck as u8); - buf.extend(port_id.as_bytes()); - buf.push(TrieKeyWithoutFields::NextSequenceAck as u8); - buf.extend(channel_id.to_be_bytes()); - } - TrieKey::Commitment { port_id, channel_id, sequence } => { - buf.push(TrieKeyWithoutFields::Commitment as u8); - buf.extend(port_id.as_bytes()); - buf.push(TrieKeyWithoutFields::Commitment as u8); - buf.extend(channel_id.to_be_bytes()); - buf.push(TrieKeyWithoutFields::Commitment as u8); - buf.extend(sequence.to_be_bytes()); - } - TrieKey::Receipts { port_id, channel_id, sequence } => { - buf.push(TrieKeyWithoutFields::Receipts as u8); - buf.extend(port_id.as_bytes()); - buf.push(TrieKeyWithoutFields::Receipts as u8); - buf.extend(channel_id.to_be_bytes()); - buf.push(TrieKeyWithoutFields::Receipts as u8); - buf.extend(sequence.to_be_bytes()); - } - TrieKey::Acks { port_id, channel_id, sequence } => { - buf.push(TrieKeyWithoutFields::Acks as u8); - buf.extend(port_id.as_bytes()); - buf.push(TrieKeyWithoutFields::Acks as u8); - buf.extend(channel_id.to_be_bytes()); - buf.push(TrieKeyWithoutFields::Acks as u8); - buf.extend(sequence.to_be_bytes()); - } - } - debug_assert_eq!(expected_len, buf.len() - start_len); - } + pub fn append_into(&self, buf: &mut Vec) { + let expected_len = self.len(); + let start_len = buf.len(); + buf.reserve(self.len()); + match self { + TrieKey::ClientState { client_id } => { + buf.push(TrieKeyWithoutFields::ClientState as u8); + buf.extend(client_id.as_bytes()); + } + TrieKey::ConsensusState { client_id, epoch, height } => { + buf.push(TrieKeyWithoutFields::ConsensusState as u8); + buf.extend(client_id.as_bytes()); + buf.push(TrieKeyWithoutFields::ConsensusState as u8); + buf.extend(height.to_be_bytes()); + buf.push(TrieKeyWithoutFields::ConsensusState as u8); + buf.extend(epoch.to_be_bytes()) + } + TrieKey::Connection { connection_id } => { + buf.push(TrieKeyWithoutFields::Connection as u8); + buf.extend(connection_id.to_be_bytes()) + } + TrieKey::ChannelEnd { port_id, channel_id } => { + buf.push(TrieKeyWithoutFields::ChannelEnd as u8); + buf.extend(port_id.as_bytes()); + buf.push(TrieKeyWithoutFields::ChannelEnd as u8); + buf.extend(channel_id.to_be_bytes()); + } + TrieKey::NextSequenceSend { port_id, channel_id } => { + buf.push(TrieKeyWithoutFields::NextSequenceSend as u8); + buf.extend(port_id.as_bytes()); + buf.push(TrieKeyWithoutFields::NextSequenceSend as u8); + buf.extend(channel_id.to_be_bytes()); + } + TrieKey::NextSequenceRecv { port_id, channel_id } => { + buf.push(TrieKeyWithoutFields::NextSequenceRecv as u8); + buf.extend(port_id.as_bytes()); + buf.push(TrieKeyWithoutFields::NextSequenceRecv as u8); + buf.extend(channel_id.to_be_bytes()); + } + TrieKey::NextSequenceAck { port_id, channel_id } => { + buf.push(TrieKeyWithoutFields::NextSequenceAck as u8); + buf.extend(port_id.as_bytes()); + buf.push(TrieKeyWithoutFields::NextSequenceAck as u8); + buf.extend(channel_id.to_be_bytes()); + } + TrieKey::Commitment { port_id, channel_id, sequence } => { + buf.push(TrieKeyWithoutFields::Commitment as u8); + buf.extend(port_id.as_bytes()); + buf.push(TrieKeyWithoutFields::Commitment as u8); + buf.extend(channel_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::Commitment as u8); + buf.extend(sequence.to_be_bytes()); + } + TrieKey::Receipts { port_id, channel_id, sequence } => { + buf.push(TrieKeyWithoutFields::Receipts as u8); + buf.extend(port_id.as_bytes()); + buf.push(TrieKeyWithoutFields::Receipts as u8); + buf.extend(channel_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::Receipts as u8); + buf.extend(sequence.to_be_bytes()); + } + TrieKey::Acks { port_id, channel_id, sequence } => { + buf.push(TrieKeyWithoutFields::Acks as u8); + buf.extend(port_id.as_bytes()); + buf.push(TrieKeyWithoutFields::Acks as u8); + buf.extend(channel_id.to_be_bytes()); + buf.push(TrieKeyWithoutFields::Acks as u8); + buf.extend(sequence.to_be_bytes()); + } + } + debug_assert_eq!(expected_len, buf.len() - start_len); + } - pub fn to_vec(&self) -> Vec { - let mut buf = Vec::with_capacity(self.len()); - self.append_into(&mut buf); - buf - } -} \ No newline at end of file + pub fn to_vec(&self) -> Vec { + let mut buf = Vec::with_capacity(self.len()); + self.append_into(&mut buf); + buf + } +} From 27adf86e077f459b6fa554dbe663d976588ff7d0 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Wed, 18 Oct 2023 21:12:56 +0530 Subject: [PATCH 10/12] using borsh for channel end ser --- Cargo.toml | 2 +- .../programs/solana-ibc/src/execution_context.rs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 88318e68..425edd12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ base64 = { version = "0.21", default-features = false, features = ["alloc"] } bincode = "1.3.3" borsh = { version = "0.10.3", default-features = false } derive_more = "0.99.17" -ibc = { version = "0.45.0", default-features = false, features = ["serde", "mocks", "std"] } +ibc = { version = "0.45.0", default-features = false, features = ["serde", "mocks", "std", "borsh"] } ibc-proto = { version = "0.35.0", default-features = false, features = ["serde"] } pretty_assertions = "1.4.0" rand = { version = "0.8.5" } diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index 54a3e476..a4e3902d 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -62,7 +62,6 @@ impl ClientExecutionContext for SolanaIbcStorage<'_, '_> { &lib::hash::CryptoHash::digest(serialized_client_state.as_bytes()), ) .unwrap(); - self.clients.insert(client_state_key, serialized_client_state); Ok(()) } @@ -363,13 +362,13 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { channel_end_path.1.clone().to_string(), )); - let serialized_channel_end = - serde_json::to_string(&channel_end).unwrap(); + let serialized_channel_end = + borsh::to_vec(&channel_end).unwrap(); let channel_end_trie_key = &TrieKey::from(channel_end_path).to_vec(); let trie = self.trie.as_mut().unwrap(); trie.set( channel_end_trie_key, - &lib::hash::CryptoHash::digest(serialized_channel_end.as_bytes()), + &lib::hash::CryptoHash::digest(&serialized_channel_end), ) .unwrap(); From 49c79d18291e38e183e6cf2a3d3d8831c5ae0368 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Wed, 18 Oct 2023 21:59:10 +0530 Subject: [PATCH 11/12] fmt --- solana/solana-ibc/programs/solana-ibc/src/execution_context.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index a4e3902d..d632c0a2 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -362,8 +362,7 @@ impl ExecutionContext for SolanaIbcStorage<'_, '_> { channel_end_path.1.clone().to_string(), )); - let serialized_channel_end = - borsh::to_vec(&channel_end).unwrap(); + let serialized_channel_end = borsh::to_vec(&channel_end).unwrap(); let channel_end_trie_key = &TrieKey::from(channel_end_path).to_vec(); let trie = self.trie.as_mut().unwrap(); trie.set( From 7fc7272de9dd4d8dea53bb722b24b91f0fb354d7 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Wed, 18 Oct 2023 23:11:13 +0530 Subject: [PATCH 12/12] fix warnings and fmt code --- .../programs/solana-ibc/src/execution_context.rs | 5 +++++ solana/solana-ibc/programs/solana-ibc/src/lib.rs | 7 +++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index d632c0a2..2bb68fb4 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -57,12 +57,17 @@ impl ClientExecutionContext for SolanaIbcStorage<'_, '_> { } .to_vec(); let trie = self.trie.as_mut().unwrap(); + msg!( + "THis is serialized client state {}", + &lib::hash::CryptoHash::digest(serialized_client_state.as_bytes()) + ); trie.set( client_state_trie_key, &lib::hash::CryptoHash::digest(serialized_client_state.as_bytes()), ) .unwrap(); self.clients.insert(client_state_key, serialized_client_state); + self.client_id_set.push(client_state_path.0.to_string()); Ok(()) } diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 519a0203..17cec871 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -62,9 +62,11 @@ pub mod solana_ibc { msg!("These are messages {:?}", all_messages); let account = &ctx.accounts.trie; - let mut trie = trie::AccountTrie::new(account.try_borrow_mut_data()?) + let trie = trie::AccountTrie::new(account.try_borrow_mut_data()?) .ok_or(ProgramError::InvalidAccountData)?; + msg!("Before trie {:?}", trie.hash()); + let mut solana_real_storage = SolanaIbcStorage { height: solana_ibc_store.height, module_holder: solana_ibc_store.module_holder.clone(), @@ -205,8 +207,6 @@ pub mod solana_ibc { solana_ibc_store.ibc_events_history = solana_real_storage.ibc_events_history.clone(); - trie = solana_real_storage.trie.unwrap(); - msg!("These are errors {:?}", errors); msg!("This is final structure {:?}", solana_ibc_store); @@ -215,7 +215,6 @@ pub mod solana_ibc { Ok(()) } } - #[derive(Accounts)] pub struct Deliver<'info> { #[account(mut)]