Skip to content

Commit

Permalink
solana-ibc: remember sequence numbers of commitments in private stora…
Browse files Browse the repository at this point in the history
…ge (#78)

For the sake of relayer, remember sequence numbers of packet and
acknowledgement commitments in the private storage.

This isn’t strictly necessary since the data can be read from the
trie, but that requires iterator interface which isn’t yet
implemented.  For the time being, use sets in the private storage.
  • Loading branch information
mina86 authored Nov 3, 2023
1 parent e08efba commit 9534c74
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 9 deletions.
81 changes: 72 additions & 9 deletions solana/solana-ibc/programs/solana-ibc/src/execution_context.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use alloc::collections::BTreeMap;

use anchor_lang::emit;
use anchor_lang::prelude::borsh;
use anchor_lang::solana_program::msg;
Expand All @@ -23,7 +25,7 @@ use lib::hash::CryptoHash;

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

Expand Down Expand Up @@ -238,17 +240,31 @@ 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();
self.borrow_mut().provable.set(&trie_key, commitment).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(())
}

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);
self.borrow_mut().provable.del(&trie_key).unwrap();
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(())
}

Expand All @@ -258,11 +274,9 @@ impl ExecutionContext for IbcStorage<'_, '_> {
Receipt::Ok: Receipt,
) -> Result {
msg!("store_packet_receipt({path}, Ok)");
let mut store = self.borrow_mut();
let trie_key = TrieKey::from(path);
self.borrow_mut()
.provable
.set_and_seal(&trie_key, &CryptoHash::DEFAULT)
.unwrap();
store.provable.set_and_seal(&trie_key, &CryptoHash::DEFAULT).unwrap();
Ok(())
}

Expand All @@ -272,17 +286,31 @@ 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();
self.borrow_mut().provable.set(&trie_key, commitment).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(())
}

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);
self.borrow_mut().provable.del(&trie_key).unwrap();
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(())
}

Expand Down Expand Up @@ -425,3 +453,38 @@ fn store_serialised_proof(
}
store_impl(trie, key, borsh::to_vec(value))
}

type SequencesMap =
BTreeMap<(storage::InnerPortId, storage::InnerChannelId), Vec<Sequence>>;

/// 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();
}
}
}
}
7 changes: 7 additions & 0 deletions solana/solana-ibc/programs/solana-ibc/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ pub(crate) struct PrivateStorage {
pub port_channel_id_set: Vec<(InnerPortId, InnerChannelId)>,
pub channel_counter: u64,

/// The sequence numbers of the packet commitments.
pub packet_commitment_sequence_sets:
BTreeMap<(InnerPortId, InnerChannelId), Vec<Sequence>>,
/// The sequence numbers of the packet acknowledgements.
pub packet_acknowledgement_sequence_sets:
BTreeMap<(InnerPortId, InnerChannelId), Vec<Sequence>>,

/// Next send, receive and ack sequence for given (port, channel).
///
/// We’re storing all three sequences in a single object to reduce amount of
Expand Down

0 comments on commit 9534c74

Please sign in to comment.