Skip to content

Commit

Permalink
solana-ibc: refactor module structure (#103)
Browse files Browse the repository at this point in the history
Move trie_key inside of storage module and add storage::ids module with
ClientIndex type and other identifier related code.  The new module will
house other code related to converting IBC identifiers into compact
internal ones.
  • Loading branch information
mina86 authored Nov 18, 2023
1 parent a91c4f2 commit 932836c
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ use lib::hash::CryptoHash;

use crate::client_state::AnyClientState;
use crate::consensus_state::AnyConsensusState;
use crate::storage::trie_key::TrieKey;
use crate::storage::{self, IbcStorage};
use crate::trie_key::TrieKey;

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

Expand Down Expand Up @@ -339,7 +339,7 @@ impl ExecutionContext for IbcStorage<'_, '_> {
impl storage::IbcStorageInner<'_, '_> {
fn store_next_sequence(
&mut self,
path: crate::trie_key::SequencePath<'_>,
path: storage::trie_key::SequencePath<'_>,
index: storage::SequenceTripleIdx,
seq: Sequence,
) -> Result {
Expand Down
4 changes: 0 additions & 4 deletions solana/solana-ibc/programs/solana-ibc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ const PACKET_SEED: &[u8] = b"packet";
const SOLANA_IBC_STORAGE_SEED: &[u8] = b"private";
const TRIE_SEED: &[u8] = b"trie";

const CONNECTION_ID_PREFIX: &str = "connection-";
const CHANNEL_ID_PREFIX: &str = "channel-";

declare_id!("EnfDJsAK7BGgetnmKzBx86CsgC5kfSPcsktFCQ4YLC81");

mod chain;
Expand All @@ -33,7 +30,6 @@ mod storage;
#[cfg(test)]
mod tests;
mod transfer;
mod trie_key;
mod validation_context;
// mod client_context;

Expand Down
55 changes: 10 additions & 45 deletions solana/solana-ibc/programs/solana-ibc/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ mod ibc {
pub use ibc::Height;
}

pub(crate) mod ids;
pub(crate) mod trie_key;

pub(crate) type SolanaTimestamp = u64;
pub(crate) type InnerConnectionId = String;
pub(crate) type InnerPortId = String;
Expand Down Expand Up @@ -79,47 +82,6 @@ impl SequenceTriple {
}
}

/// An index used as unique identifier for a client.
///
/// IBC client id uses `<client-type>-<counter>` format. This index is
/// constructed from a client id by stripping the client type. Since counter is
/// unique within an IBC module, the index is enough to identify a known client.
///
/// To avoid confusing identifiers with the same counter but different client
/// type (which may be crafted by an attacker), we always check that client type
/// matches one we know. Because of this check, to get `ClientIdx`
/// [`PrivateStorage::client`] needs to be used.
///
/// The index is guaranteed to fit `u32` and `usize`.
#[derive(Clone, Copy, PartialEq, Eq, derive_more::From, derive_more::Into)]
pub struct ClientIdx(u32);

impl From<ClientIdx> for usize {
#[inline]
fn from(index: ClientIdx) -> usize { index.0 as usize }
}

impl core::str::FromStr for ClientIdx {
type Err = core::num::ParseIntError;

#[inline]
fn from_str(value: &str) -> Result<Self, Self::Err> {
if core::mem::size_of::<usize>() < 4 {
usize::from_str(value).map(|index| Self(index as u32))
} else {
u32::from_str(value).map(Self)
}
}
}

impl PartialEq<usize> for ClientIdx {
#[inline]
fn eq(&self, rhs: &usize) -> bool {
u32::try_from(*rhs).ok().filter(|rhs| self.0 == *rhs).is_some()
}
}


/// Per-client private storage.
#[derive(Clone, Debug, borsh::BorshSerialize, borsh::BorshDeserialize)]
pub(crate) struct ClientStore {
Expand Down Expand Up @@ -192,7 +154,7 @@ impl PrivateStorage {
pub fn client(
&self,
client_id: &ibc::ClientId,
) -> Result<(ClientIdx, &ClientStore), ibc::ClientError> {
) -> Result<(ids::ClientIdx, &ClientStore), ibc::ClientError> {
self.client_index(client_id)
.and_then(|idx| {
self.clients
Expand All @@ -218,7 +180,7 @@ impl PrivateStorage {
&mut self,
client_id: &ibc::ClientId,
create: bool,
) -> Result<(ClientIdx, &mut ClientStore), ibc::ClientError> {
) -> Result<(ids::ClientIdx, &mut ClientStore), ibc::ClientError> {
self.client_mut_impl(client_id, create).ok_or_else(|| {
ibc::ClientError::ClientStateNotFound {
client_id: client_id.clone(),
Expand All @@ -230,7 +192,7 @@ impl PrivateStorage {
&mut self,
client_id: &ibc::ClientId,
create: bool,
) -> Option<(ClientIdx, &mut ClientStore)> {
) -> Option<(ids::ClientIdx, &mut ClientStore)> {
use core::cmp::Ordering;

let idx = self.client_index(client_id)?;
Expand All @@ -245,7 +207,10 @@ impl PrivateStorage {
}
}

fn client_index(&self, client_id: &ibc::ClientId) -> Option<ClientIdx> {
fn client_index(
&self,
client_id: &ibc::ClientId,
) -> Option<ids::ClientIdx> {
client_id
.as_str()
.rsplit_once('-')
Expand Down
53 changes: 53 additions & 0 deletions solana/solana-ibc/programs/solana-ibc/src/storage/ids.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/// Prefix of IBC connection ids.
///
/// Note: We’re not using ConnectionId::prefix() because it returns the prefix
/// without trailing `-` which we want included to simplify stripping of the
/// prefix.
pub(super) const CONNECTION_ID_PREFIX: &str = "connection-";

/// 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 `<client-type>-<counter>` format. This index is
/// constructed from a client id by stripping the client type. Since counter is
/// unique within an IBC module, the index is enough to identify a known client.
///
/// To avoid confusing identifiers with the same counter but different client
/// type (which may be crafted by an attacker), we always check that client type
/// matches one we know. Because of this check, to get `ClientIdx`
/// [`PrivateStorage::client`] needs to be used.
///
/// The index is guaranteed to fit `u32` and `usize`.
#[derive(Clone, Copy, PartialEq, Eq, derive_more::From, derive_more::Into)]
pub struct ClientIdx(u32);

impl From<ClientIdx> for usize {
#[inline]
fn from(index: ClientIdx) -> usize { index.0 as usize }
}

impl core::str::FromStr for ClientIdx {
type Err = core::num::ParseIntError;

#[inline]
fn from_str(value: &str) -> Result<Self, Self::Err> {
if core::mem::size_of::<usize>() < 4 {
usize::from_str(value).map(|index| Self(index as u32))
} else {
u32::from_str(value).map(Self)
}
}
}

impl PartialEq<usize> for ClientIdx {
#[inline]
fn eq(&self, rhs: &usize) -> bool {
u32::try_from(*rhs).ok().filter(|rhs| self.0 == *rhs).is_some()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@ use ibc::core::ics24_host::path::{
SeqAckPath, SeqRecvPath, SeqSendPath,
};

// Note: We’re not using ChannelId::prefix() and ConnectionId::prefix() because
// those return the prefix without trailing `-` and we want constants which also
// include that hyphen.
use super::{CHANNEL_ID_PREFIX, CONNECTION_ID_PREFIX};
use crate::storage::ClientIdx;
use crate::storage::ids::{ClientIdx, CHANNEL_ID_PREFIX, CONNECTION_ID_PREFIX};

/// A key used for indexing entries in the provable storage.
///
Expand Down
53 changes: 22 additions & 31 deletions solana/solana-ibc/programs/solana-ibc/src/validation_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ use lib::hash::CryptoHash;

use crate::client_state::AnyClientState;
use crate::consensus_state::AnyConsensusState;
use crate::storage::IbcStorage;
use crate::trie_key::TrieKey;
use crate::storage::trie_key::TrieKey;
use crate::storage::{self, IbcStorage};

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

Expand Down Expand Up @@ -145,42 +145,33 @@ impl ValidationContext for IbcStorage<'_, '_> {
}

fn get_next_sequence_send(&self, path: &SeqSendPath) -> Result<Sequence> {
self.get_next_sequence(
path.into(),
crate::storage::SequenceTripleIdx::Send,
)
.map_err(|(port_id, channel_id)| {
ContextError::PacketError(PacketError::MissingNextSendSeq {
port_id,
channel_id,
self.get_next_sequence(path.into(), storage::SequenceTripleIdx::Send)
.map_err(|(port_id, channel_id)| {
ContextError::PacketError(PacketError::MissingNextSendSeq {
port_id,
channel_id,
})
})
})
}

fn get_next_sequence_recv(&self, path: &SeqRecvPath) -> Result<Sequence> {
self.get_next_sequence(
path.into(),
crate::storage::SequenceTripleIdx::Recv,
)
.map_err(|(port_id, channel_id)| {
ContextError::PacketError(PacketError::MissingNextRecvSeq {
port_id,
channel_id,
self.get_next_sequence(path.into(), storage::SequenceTripleIdx::Recv)
.map_err(|(port_id, channel_id)| {
ContextError::PacketError(PacketError::MissingNextRecvSeq {
port_id,
channel_id,
})
})
})
}

fn get_next_sequence_ack(&self, path: &SeqAckPath) -> Result<Sequence> {
self.get_next_sequence(
path.into(),
crate::storage::SequenceTripleIdx::Ack,
)
.map_err(|(port_id, channel_id)| {
ContextError::PacketError(PacketError::MissingNextAckSeq {
port_id,
channel_id,
self.get_next_sequence(path.into(), storage::SequenceTripleIdx::Ack)
.map_err(|(port_id, channel_id)| {
ContextError::PacketError(PacketError::MissingNextAckSeq {
port_id,
channel_id,
})
})
})
}

fn get_packet_commitment(
Expand Down Expand Up @@ -321,8 +312,8 @@ impl ibc::core::ics02_client::ClientValidationContext for IbcStorage<'_, '_> {
impl IbcStorage<'_, '_> {
fn get_next_sequence(
&self,
path: crate::trie_key::SequencePath<'_>,
index: crate::storage::SequenceTripleIdx,
path: crate::storage::trie_key::SequencePath<'_>,
index: storage::SequenceTripleIdx,
) -> core::result::Result<
Sequence,
(
Expand Down

0 comments on commit 932836c

Please sign in to comment.