From bcbd4eef3c28a2c972f63852199cd998912dd6d8 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sat, 18 Nov 2023 21:07:00 +0100 Subject: [PATCH] wip channellidx --- .../solana-ibc/src/execution_context.rs | 135 ++++----------- .../programs/solana-ibc/src/storage.rs | 22 +-- .../programs/solana-ibc/src/storage/ids.rs | 73 +++++++- .../solana-ibc/src/storage/trie_key.rs | 163 +++++++----------- .../solana-ibc/src/validation_context.rs | 104 +++++------ 5 files changed, 232 insertions(+), 265 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 5f0debc2..7b083ffd 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -200,32 +200,13 @@ impl ExecutionContext for IbcStorage<'_, '_> { commitment: PacketCommitment, ) -> Result { msg!("store_packet_commitment({}, {:?})", path, commitment); - let mut store = self.borrow_mut(); - let trie_key = TrieKey::from(path); - // PacketCommitment is always 32-byte long. - let commitment = <&CryptoHash>::try_from(commitment.as_ref()).unwrap(); - store.provable.set(&trie_key, commitment).unwrap(); - record_packet_sequence( - &mut store.private.packet_commitment_sequence_sets, - &path.port_id, - &path.channel_id, - path.sequence, - ); - Ok(()) + // Note: PacketCommitment is always 32-byte long. + self.store_commitment(TrieKey::try_from(path)?, commitment.as_ref()) } fn delete_packet_commitment(&mut self, path: &CommitmentPath) -> Result { msg!("delete_packet_commitment({})", path); - let mut store = self.borrow_mut(); - let trie_key = TrieKey::from(path); - store.provable.del(&trie_key).unwrap(); - delete_packet_sequence( - &mut store.private.packet_commitment_sequence_sets, - &path.port_id, - &path.channel_id, - path.sequence, - ); - Ok(()) + self.delete_commitment(TrieKey::try_from(path)?) } fn store_packet_receipt( @@ -234,10 +215,7 @@ impl ExecutionContext for IbcStorage<'_, '_> { Receipt::Ok: Receipt, ) -> Result { msg!("store_packet_receipt({}, Ok)", path); - let mut store = self.borrow_mut(); - let trie_key = TrieKey::from(path); - store.provable.set_and_seal(&trie_key, &CryptoHash::DEFAULT).unwrap(); - Ok(()) + self.store_commitment(TrieKey::try_from(path)?, &[0; 32][..]) } fn store_packet_acknowledgement( @@ -246,32 +224,13 @@ impl ExecutionContext for IbcStorage<'_, '_> { commitment: AcknowledgementCommitment, ) -> Result { msg!("store_packet_acknowledgement({}, {:?})", path, commitment); - let mut store = self.borrow_mut(); - let trie_key = TrieKey::from(path); - // AcknowledgementCommitment is always 32-byte long. - let commitment = <&CryptoHash>::try_from(commitment.as_ref()).unwrap(); - store.provable.set(&trie_key, commitment).unwrap(); - record_packet_sequence( - &mut store.private.packet_acknowledgement_sequence_sets, - &path.port_id, - &path.channel_id, - path.sequence, - ); - Ok(()) + // Note: AcknowledgementCommitment is always 32-byte long. + self.store_commitment(TrieKey::try_from(path)?, commitment.as_ref()) } fn delete_packet_acknowledgement(&mut self, path: &AckPath) -> Result { msg!("delete_packet_acknowledgement({})", path); - let mut store = self.borrow_mut(); - let trie_key = TrieKey::from(path); - store.provable.del(&trie_key).unwrap(); - delete_packet_sequence( - &mut store.private.packet_acknowledgement_sequence_sets, - &path.port_id, - &path.channel_id, - path.sequence, - ); - Ok(()) + self.delete_commitment(TrieKey::try_from(path)?) } fn store_channel( @@ -280,10 +239,12 @@ impl ExecutionContext for IbcStorage<'_, '_> { channel_end: ChannelEnd, ) -> Result { msg!("store_channel({}, {:?})", path, channel_end); + let port_channel = ids::PortChannelPK::try_from(&path.0, &path.1)?; + let trie_key = TrieKey::for_channel_end(&port_channel); self.borrow_mut().store_serialised_proof( |private| &mut private.channel_ends, - (path.0.to_string(), path.1.to_string()), - &TrieKey::from(path), + port_channel, + &trie_key, &channel_end, ) } @@ -294,7 +255,7 @@ impl ExecutionContext for IbcStorage<'_, '_> { seq: Sequence, ) -> Result { msg!("store_next_sequence_send: path: {}, seq: {}", path, seq); - self.borrow_mut().store_next_sequence( + self.store_next_sequence( path.into(), storage::SequenceTripleIdx::Send, seq, @@ -307,7 +268,7 @@ impl ExecutionContext for IbcStorage<'_, '_> { seq: Sequence, ) -> Result { msg!("store_next_sequence_recv: path: {}, seq: {}", path, seq); - self.borrow_mut().store_next_sequence( + self.store_next_sequence( path.into(), storage::SequenceTripleIdx::Recv, seq, @@ -320,7 +281,7 @@ impl ExecutionContext for IbcStorage<'_, '_> { seq: Sequence, ) -> Result { msg!("store_next_sequence_ack: path: {}, seq: {}", path, seq); - self.borrow_mut().store_next_sequence( + self.store_next_sequence( path.into(), storage::SequenceTripleIdx::Ack, seq, @@ -349,25 +310,36 @@ impl ExecutionContext for IbcStorage<'_, '_> { fn get_client_execution_context(&mut self) -> &mut Self::E { self } } -impl storage::IbcStorageInner<'_, '_> { +impl storage::IbcStorage<'_, '_> { + fn store_commitment(&mut self, key: TrieKey, commitment: &[u8]) -> Result { + // Caller promises that commitment is always 32 bytes. + let commitment = <&CryptoHash>::try_from(commitment).unwrap(); + self.borrow_mut().provable.set(&key, commitment).map_err(error) + } + + fn delete_commitment(&mut self, key: TrieKey) -> Result { + self.borrow_mut().provable.del(&key).map(|_| ()).map_err(error) + } + fn store_next_sequence( &mut self, path: storage::trie_key::SequencePath<'_>, index: storage::SequenceTripleIdx, seq: Sequence, ) -> Result { - let trie = &mut self.provable; - let next_seq = &mut self.private.next_sequence; - let map_key = (path.port_id.to_string(), path.channel_id.to_string()); - let triple = next_seq.entry(map_key).or_default(); - triple.set(index, seq); - - let trie_key = TrieKey::from(path); - trie.set(&trie_key, &triple.to_hash()).unwrap(); - - Ok(()) + let key = ids::PortChannelPK::try_from(path.port_id, path.channel_id)?; + let trie_key = TrieKey::for_next_sequence(&key); + let mut store = self.borrow_mut(); + let hash = { + let triple = store.private.next_sequence.entry(key).or_default(); + triple.set(index, seq); + triple.to_hash() + }; + store.provable.set(&trie_key, &hash).map_err(error) } +} +impl storage::IbcStorageInner<'_, '_> { /// Serialises `value` and stores it in private storage along with its /// commitment in provable storage. /// @@ -391,41 +363,6 @@ impl storage::IbcStorageInner<'_, '_> { } } -type SequencesMap = - BTreeMap<(storage::InnerPortId, storage::InnerChannelId), Vec>; - -/// Adds sequence to given per-channel set. -fn record_packet_sequence( - map: &mut SequencesMap, - port_id: &ibc::core::ics24_host::identifier::PortId, - channel_id: &ibc::core::ics24_host::identifier::ChannelId, - sequence: Sequence, -) { - let key = (port_id.to_string(), channel_id.to_string()); - map.entry(key).or_default().push(sequence); -} - -/// Removes sequence from given per-channel set. -fn delete_packet_sequence( - map: &mut SequencesMap, - port_id: &ibc::core::ics24_host::identifier::PortId, - channel_id: &ibc::core::ics24_host::identifier::ChannelId, - sequence: Sequence, -) { - use alloc::collections::btree_map::Entry; - - let key = (port_id.to_string(), channel_id.to_string()); - if let Entry::Occupied(mut entry) = map.entry(key) { - let set = entry.get_mut(); - if let Some(pos) = set.iter().position(|s| *s == sequence) { - set.swap_remove(pos); - if set.is_empty() { - entry.remove(); - } - } - } -} - fn error(description: impl ToString) -> ContextError { ClientError::Other { description: description.to_string() }.into() } diff --git a/solana/solana-ibc/programs/solana-ibc/src/storage.rs b/solana/solana-ibc/programs/solana-ibc/src/storage.rs index b0041814..7af06971 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/storage.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/storage.rs @@ -16,9 +16,13 @@ mod ibc { pub use ibc::core::ics03_connection::connection::ConnectionEnd; pub use ibc::core::ics03_connection::error::ConnectionError; pub use ibc::core::ics04_channel::channel::ChannelEnd; + pub use ibc::core::ics04_channel::error::ChannelError; pub use ibc::core::ics04_channel::msgs::PacketMsg; pub use ibc::core::ics04_channel::packet::Sequence; - pub use ibc::core::ics24_host::identifier::{ClientId, ConnectionId}; + pub use ibc::core::ics24_host::identifier::{ + ChannelId, ClientId, ConnectionId, PortId, + }; + pub use ibc::core::ics24_host::path; pub use ibc::Height; } @@ -26,8 +30,6 @@ pub(crate) mod ids; pub(crate) mod trie_key; pub(crate) type SolanaTimestamp = u64; -pub(crate) type InnerPortId = String; -pub(crate) type InnerChannelId = String; /// A triple of send, receive and acknowledge sequences. #[derive( @@ -155,23 +157,15 @@ pub(crate) struct PrivateStorage { /// `connection-`. pub connections: Vec>, - pub channel_ends: - BTreeMap<(InnerPortId, InnerChannelId), Serialised>, - pub channel_counter: u64, - - /// The sequence numbers of the packet commitments. - pub packet_commitment_sequence_sets: - BTreeMap<(InnerPortId, InnerChannelId), Vec>, - /// The sequence numbers of the packet acknowledgements. - pub packet_acknowledgement_sequence_sets: - BTreeMap<(InnerPortId, InnerChannelId), Vec>, + pub channel_ends: BTreeMap>, + pub channel_counter: u32, /// Next send, receive and ack sequence for given (port, channel). /// /// We’re storing all three sequences in a single object to reduce amount of /// different maps we need to maintain. This saves us on the amount of /// trie nodes we need to maintain. - pub next_sequence: BTreeMap<(InnerPortId, InnerChannelId), SequenceTriple>, + pub next_sequence: BTreeMap, } impl PrivateStorage { diff --git a/solana/solana-ibc/programs/solana-ibc/src/storage/ids.rs b/solana/solana-ibc/programs/solana-ibc/src/storage/ids.rs index 9eb557c7..1b285cc0 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/storage/ids.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/storage/ids.rs @@ -5,14 +5,6 @@ use super::ibc; type Result = core::result::Result; -/// Prefix of IBC channel ids. -/// -/// Note: We’re not using ChannelId::prefix() because it returns the prefix -/// without trailing `-` which we want included to simplify stripping of the -/// prefix. -pub(super) const CHANNEL_ID_PREFIX: &str = "channel-"; - - /// An index used as unique identifier for a client. /// /// IBC client id uses `-` format. This index is @@ -113,6 +105,71 @@ impl TryFrom<&ibc::ConnectionId> for ConnectionIdx { } +/// An internal port-channel identifier; that is, it combines IBC port and +/// channel identifier into a single primary key type. +/// +/// Currently port identifier is represented as a string. +/// +/// Meanwhile, the channel identifier is build from IBC identifiers which are of +/// the form `channel-`. Rather than treating the identifier as +/// a string, we’re parsing the number out and keep only that. +#[derive( + Clone, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + borsh::BorshSerialize, + borsh::BorshDeserialize, +)] +pub struct PortChannelPK { + pub(super) port_id: ibc::PortId, + pub(super) channel_idx: u32, +} + +impl PortChannelPK { + /// Prefix of IBC channel ids. + /// + /// Note: We’re not using ChannelId::prefix() because it returns the + /// prefix without trailing `-` which we want included to simplify stripping + /// of the prefix. + const CHANNEL_IBC_PREFIX: &'static str = "channel-"; + + pub fn try_from( + port_id: impl MaybeOwned, + channel_id: impl MaybeOwned, + ) -> Result { + let channel_str = channel_id.as_ref().as_str(); + match parse_sans_prefix(Self::CHANNEL_IBC_PREFIX, channel_str) { + Some(channel_idx) => { + Ok(Self { port_id: port_id.into_owned(), channel_idx }) + } + None => Err(ibc::ChannelError::ChannelNotFound { + port_id: port_id.into_owned(), + channel_id: channel_id.into_owned(), + }), + } + } +} + +pub trait MaybeOwned { + fn as_ref(&self) -> &T; + fn into_owned(self) -> T; +} + +impl MaybeOwned for &T { + fn as_ref(&self) -> &T { *self } + fn into_owned(self) -> T { (*self).clone() } +} + +impl MaybeOwned for T { + fn as_ref(&self) -> &T { self } + fn into_owned(self) -> T { self } +} + + /// Strips `prefix` from `data` and parses it to get `u32`. Panics if data /// doesn’t start with the prefix or parsing fails. fn parse_sans_prefix(prefix: &'static str, data: &str) -> Option { diff --git a/solana/solana-ibc/programs/solana-ibc/src/storage/trie_key.rs b/solana/solana-ibc/programs/solana-ibc/src/storage/trie_key.rs index cd7bbcb2..61bf707f 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/storage/trie_key.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/storage/trie_key.rs @@ -1,11 +1,9 @@ -use ibc::core::ics04_channel::packet::Sequence; -use ibc::core::ics24_host::identifier::{ChannelId, PortId}; -use ibc::core::ics24_host::path::{ - AckPath, ChannelEndPath, CommitmentPath, ReceiptPath, SeqAckPath, - SeqRecvPath, SeqSendPath, +use ibc::path::{ + AckPath, CommitmentPath, ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; -use crate::storage::ids; +use crate::storage::{ibc, ids}; + /// A key used for indexing entries in the provable storage. /// @@ -38,8 +36,8 @@ pub struct TrieKey(Vec); /// A path for next send, receive and ack sequence paths. pub struct SequencePath<'a> { - pub port_id: &'a PortId, - pub channel_id: &'a ChannelId, + pub port_id: &'a ibc::PortId, + pub channel_id: &'a ibc::ChannelId, } /// Constructs a new [`TrieKey`] by concatenating key components. @@ -85,27 +83,33 @@ impl TrieKey { new_key_impl!(Tag::Connection, connection) } + /// Constructs a new key for a channel end path. + pub fn for_channel_end(port_channel: &ids::PortChannelPK) -> Self { + Self::for_channel_path(Tag::ChannelEnd, port_channel) + } + + pub fn for_next_sequence(port_channel: &ids::PortChannelPK) -> Self { + Self::for_channel_path(Tag::NextSequence, port_channel) + } + /// Constructs a new key for a `(port_id, channel_id)` path. /// /// Panics if `channel_id` is invalid. - fn from_channel_path( - tag: Tag, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Self { - new_key_impl!(tag, port_id, channel_id) + fn for_channel_path(tag: Tag, port_channel: &ids::PortChannelPK) -> Self { + new_key_impl!(tag, port_channel) } /// Constructs a new key for a `(port_id, channel_id, sequence)` path. /// /// Panics if `channel_id` is invalid. - fn from_sequence_path( + fn try_for_sequence_path( tag: Tag, - port_id: &PortId, - channel_id: &ChannelId, - sequence: Sequence, - ) -> Self { - new_key_impl!(tag, port_id, channel_id, sequence) + port_id: &ibc::PortId, + channel_id: &ibc::ChannelId, + sequence: ibc::Sequence, + ) -> Result { + let port_channel = ids::PortChannelPK::try_from(port_id, channel_id)?; + Ok(new_key_impl!(tag, port_channel, sequence)) } } @@ -114,12 +118,6 @@ impl core::ops::Deref for TrieKey { fn deref(&self) -> &[u8] { self.0.as_slice() } } -impl From<&ChannelEndPath> for TrieKey { - fn from(path: &ChannelEndPath) -> Self { - Self::from_channel_path(Tag::ChannelEnd, &path.0, &path.1) - } -} - impl<'a> From<&'a SeqSendPath> for SequencePath<'a> { fn from(path: &'a SeqSendPath) -> Self { Self { port_id: &path.0, channel_id: &path.1 } @@ -138,19 +136,19 @@ impl<'a> From<&'a SeqAckPath> for SequencePath<'a> { } } -impl From> for TrieKey { - fn from(path: SequencePath<'_>) -> Self { - Self::from_channel_path( - Tag::NextSequence, - path.port_id, - path.channel_id, - ) +impl TryFrom> for TrieKey { + type Error = ibc::ChannelError; + fn try_from(path: SequencePath<'_>) -> Result { + let port_channel = + ids::PortChannelPK::try_from(path.port_id, path.channel_id)?; + Ok(Self::for_channel_path(Tag::NextSequence, &port_channel)) } } -impl From<&CommitmentPath> for TrieKey { - fn from(path: &CommitmentPath) -> Self { - Self::from_sequence_path( +impl TryFrom<&CommitmentPath> for TrieKey { + type Error = ibc::ChannelError; + fn try_from(path: &CommitmentPath) -> Result { + Self::try_for_sequence_path( Tag::Commitment, &path.port_id, &path.channel_id, @@ -159,9 +157,10 @@ impl From<&CommitmentPath> for TrieKey { } } -impl From<&ReceiptPath> for TrieKey { - fn from(path: &ReceiptPath) -> Self { - Self::from_sequence_path( +impl TryFrom<&ReceiptPath> for TrieKey { + type Error = ibc::ChannelError; + fn try_from(path: &ReceiptPath) -> Result { + Self::try_for_sequence_path( Tag::Receipt, &path.port_id, &path.channel_id, @@ -170,9 +169,10 @@ impl From<&ReceiptPath> for TrieKey { } } -impl From<&AckPath> for TrieKey { - fn from(path: &AckPath) -> Self { - Self::from_sequence_path( +impl TryFrom<&AckPath> for TrieKey { + type Error = ibc::ChannelError; + fn try_from(path: &AckPath) -> Result { + Self::try_for_sequence_path( Tag::Ack, &path.port_id, &path.channel_id, @@ -206,34 +206,36 @@ trait AsComponent { fn append_into(&self, dest: &mut Vec); } -impl AsComponent for ids::ClientIdx { - fn key_len(&self) -> usize { 0_u32.key_len() } - fn append_into(&self, dest: &mut Vec) { - u32::from(*self).append_into(dest) - } +/// Implements [`AsComponent`] for types which are `Copy` and `Into` for type +/// `T` which implements `AsComponent`. +macro_rules! cast_component { + ($component:ty as $ty:ty) => { + impl AsComponent for $component { + fn key_len(&self) -> usize { <$ty>::from(*self).key_len() } + fn append_into(&self, dest: &mut Vec) { + <$ty>::from(*self).append_into(dest) + } + } + }; } -impl AsComponent for ids::ConnectionIdx { - fn key_len(&self) -> usize { 0_u32.key_len() } - fn append_into(&self, dest: &mut Vec) { - u32::from(*self).append_into(dest) - } -} +cast_component!(ids::ClientIdx as u32); +cast_component!(ids::ConnectionIdx as u32); +cast_component!(ibc::Sequence as u64); -// TODO(#35): Investigate weather we can impose restrictions on port -// identifiers, e.g. `port-`. -impl AsComponent for ibc::core::ics24_host::identifier::PortId { - fn key_len(&self) -> usize { self.as_str().key_len() } - fn append_into(&self, dest: &mut Vec) { - self.as_str().append_into(dest) +// TODO(#35): Investigate more compact ways of representing port identifier or +// enforcing restrictions on it +impl AsComponent for ids::PortChannelPK { + fn key_len(&self) -> usize { + let port_id_len = self.port_id.as_bytes().len(); + assert!(port_id_len <= usize::from(u8::MAX)); + 1 + port_id_len + u32::from(self.channel_idx).key_len() } -} - -impl AsComponent for ibc::core::ics24_host::identifier::ChannelId { - fn key_len(&self) -> usize { 0_u32.key_len() } fn append_into(&self, dest: &mut Vec) { - parse_sans_prefix(ids::CHANNEL_ID_PREFIX, self.as_str()) - .append_into(dest) + let port_id = self.port_id.as_bytes(); + dest.push(port_id.len() as u8); + dest.extend(port_id); + u32::from(self.channel_idx).append_into(dest); } } @@ -245,29 +247,6 @@ impl AsComponent for ibc::Height { } } -impl AsComponent for ibc::core::ics04_channel::packet::Sequence { - fn key_len(&self) -> usize { 0_u64.key_len() } - fn append_into(&self, dest: &mut Vec) { - u64::from(*self).append_into(dest) - } -} - -impl AsComponent for str { - fn key_len(&self) -> usize { - assert!(self.len() <= usize::from(u8::MAX)); - 1 + self.len() - } - fn append_into(&self, dest: &mut Vec) { - // TODO(#35): Perhaps it would be worth to compress the value. For - // identifiers longer than 32 bytes we could hash them to limit the - // length of the encoding to 33 bytes. And since we can assume the - // string is ASCII for shorter values we could pack each 8 bytes into 7 - // bytes (though this is probably not really worth it). - dest.push(self.len() as u8); - dest.extend(self.as_bytes()); - } -} - impl AsComponent for u32 { fn key_len(&self) -> usize { core::mem::size_of_val(self) } fn append_into(&self, dest: &mut Vec) { @@ -281,11 +260,3 @@ impl AsComponent for u64 { dest.extend(&self.to_be_bytes()[..]); } } - -/// Strips `prefix` from `data` and parses it to get `u32`. Panics if data -/// doesn’t start with the prefix or parsing fails. -fn parse_sans_prefix(prefix: &'static str, data: &str) -> u32 { - data.strip_prefix(prefix) - .and_then(|id| id.parse().ok()) - .unwrap_or_else(|| panic!("invalid identifier: {data}")) -} 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 ab3916c5..e3bc30cd 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs @@ -127,59 +127,58 @@ impl ValidationContext for IbcStorage<'_, '_> { }) } - fn channel_end( - &self, - channel_end_path: &ChannelEndPath, - ) -> Result { - let key = - (channel_end_path.0.to_string(), channel_end_path.1.to_string()); + fn channel_end(&self, path: &ChannelEndPath) -> Result { + let key = ids::PortChannelPK::try_from(&path.0, &path.1)?; self.borrow() .private .channel_ends .get(&key) .ok_or_else(|| ChannelError::ChannelNotFound { - port_id: channel_end_path.0.clone(), - channel_id: channel_end_path.1.clone(), + port_id: path.0.clone(), + channel_id: path.1.clone(), })? .get() .map_err(Into::into) } fn get_next_sequence_send(&self, path: &SeqSendPath) -> Result { - self.get_next_sequence(path.into(), storage::SequenceTripleIdx::Send) - .map_err(|(port_id, channel_id)| { - ContextError::PacketError(PacketError::MissingNextSendSeq { - port_id, - channel_id, - }) - }) + self.get_next_sequence( + path, + storage::SequenceTripleIdx::Send, + |port_id, channel_id| PacketError::MissingNextSendSeq { + port_id, + channel_id, + }, + ) } fn get_next_sequence_recv(&self, path: &SeqRecvPath) -> Result { - self.get_next_sequence(path.into(), storage::SequenceTripleIdx::Recv) - .map_err(|(port_id, channel_id)| { - ContextError::PacketError(PacketError::MissingNextRecvSeq { - port_id, - channel_id, - }) - }) + self.get_next_sequence( + path, + storage::SequenceTripleIdx::Recv, + |port_id, channel_id| PacketError::MissingNextRecvSeq { + port_id, + channel_id, + }, + ) } fn get_next_sequence_ack(&self, path: &SeqAckPath) -> Result { - self.get_next_sequence(path.into(), storage::SequenceTripleIdx::Ack) - .map_err(|(port_id, channel_id)| { - ContextError::PacketError(PacketError::MissingNextAckSeq { - port_id, - channel_id, - }) - }) + self.get_next_sequence( + path, + storage::SequenceTripleIdx::Ack, + |port_id, channel_id| PacketError::MissingNextAckSeq { + port_id, + channel_id, + }, + ) } fn get_packet_commitment( &self, path: &CommitmentPath, ) -> Result { - let trie_key = TrieKey::from(path); + let trie_key = TrieKey::try_from(path)?; match self.borrow().provable.get(&trie_key).ok().flatten() { Some(hash) => Ok(hash.as_slice().to_vec().into()), None => Err(ContextError::PacketError( @@ -189,7 +188,7 @@ impl ValidationContext for IbcStorage<'_, '_> { } fn get_packet_receipt(&self, path: &ReceiptPath) -> Result { - let trie_key = TrieKey::from(path); + let trie_key = TrieKey::try_from(path)?; match self.borrow().provable.get(&trie_key).ok().flatten() { Some(hash) if hash == CryptoHash::DEFAULT => Ok(Receipt::Ok), _ => Err(ContextError::PacketError( @@ -202,7 +201,7 @@ impl ValidationContext for IbcStorage<'_, '_> { &self, path: &AckPath, ) -> Result { - let trie_key = TrieKey::from(path); + let trie_key = TrieKey::try_from(path)?; match self.borrow().provable.get(&trie_key).ok().flatten() { Some(hash) => Ok(hash.as_slice().to_vec().into()), None => Err(ContextError::PacketError( @@ -214,8 +213,7 @@ impl ValidationContext for IbcStorage<'_, '_> { } fn channel_counter(&self) -> Result { - let store = self.borrow(); - Ok(store.private.channel_counter) + Ok(u64::from(self.borrow().private.channel_counter)) } fn max_expected_time_per_block(&self) -> Duration { @@ -309,24 +307,34 @@ impl ibc::core::ics02_client::ClientValidationContext for IbcStorage<'_, '_> { } impl IbcStorage<'_, '_> { - fn get_next_sequence( + fn get_next_sequence<'a>( &self, - path: crate::storage::trie_key::SequencePath<'_>, + path: impl Into>, index: storage::SequenceTripleIdx, - ) -> core::result::Result< - Sequence, - ( + make_err: impl FnOnce( ibc::core::ics24_host::identifier::PortId, ibc::core::ics24_host::identifier::ChannelId, - ), - > { - let store = self.borrow(); - store - .private - .next_sequence - .get(&(path.port_id.to_string(), path.channel_id.to_string())) - .and_then(|triple| triple.get(index)) - .ok_or_else(|| (path.port_id.clone(), path.channel_id.clone())) + ) -> PacketError, + ) -> Result { + fn get( + this: &IbcStorage<'_, '_>, + port_channel: &ids::PortChannelPK, + index: storage::SequenceTripleIdx, + ) -> Option { + this.borrow() + .private + .next_sequence + .get(&port_channel) + .and_then(|triple| triple.get(index)) + } + + let path = path.into(); + let key = ids::PortChannelPK::try_from(path.port_id, path.channel_id)?; + get(self, &key, index) + .ok_or_else(|| { + make_err(path.port_id.clone(), path.channel_id.clone()) + }) + .map_err(ContextError::from) } }