penumbra_sdk_ibc/component/
connection.rs

1use anyhow::Result;
2use async_trait::async_trait;
3use cnidarium::{StateRead, StateWrite};
4use ibc_types::{
5    core::{
6        client::ClientId,
7        connection::ConnectionId,
8        connection::{ClientPaths, ConnectionEnd},
9    },
10    path::{ClientConnectionPath, ConnectionPath},
11};
12use penumbra_sdk_proto::{StateReadProto, StateWriteProto};
13
14use crate::{prefix::MerklePrefixExt, IBC_COMMITMENT_PREFIX};
15
16use super::{connection_counter::ConnectionCounter, state_key};
17
18#[async_trait]
19pub trait StateWriteExt: StateWrite {
20    fn put_connection_counter(&mut self, counter: ConnectionCounter) {
21        self.put(state_key::counter().into(), counter);
22    }
23    fn put_client_connection(&mut self, client_id: &ClientId, paths: ClientPaths) {
24        self.put(
25            IBC_COMMITMENT_PREFIX.apply_string(ClientConnectionPath::new(client_id).to_string()),
26            paths.clone(),
27        );
28    }
29
30    // puts a new connection into the state, updating the connections associated with the client,
31    // and incrementing the client counter.
32    async fn put_new_connection(
33        &mut self,
34        connection_id: &ConnectionId,
35        connection: ConnectionEnd,
36    ) -> Result<()> {
37        self.put(
38            IBC_COMMITMENT_PREFIX.apply_string(ConnectionPath::new(connection_id).to_string()),
39            connection.clone(),
40        );
41
42        let mut client_paths = self.get_client_connections(&connection.client_id).await?;
43        client_paths.paths.push(connection_id.clone());
44        self.put_client_connection(&connection.client_id, client_paths);
45
46        let counter = self
47            .get_connection_counter()
48            .await
49            .unwrap_or(ConnectionCounter(0));
50        self.put_connection_counter(ConnectionCounter(counter.0 + 1));
51
52        return Ok(());
53    }
54
55    fn update_connection(&mut self, connection_id: &ConnectionId, connection: ConnectionEnd) {
56        self.put(
57            IBC_COMMITMENT_PREFIX.apply_string(ConnectionPath::new(connection_id).to_string()),
58            connection.clone(),
59        );
60    }
61}
62
63impl<T: StateWrite + ?Sized> StateWriteExt for T {}
64
65#[async_trait]
66pub trait StateReadExt: StateRead {
67    async fn get_connection_counter(&self) -> Result<ConnectionCounter> {
68        self.get(state_key::counter())
69            .await
70            .map(|counter| counter.unwrap_or(ConnectionCounter(0)))
71    }
72
73    async fn get_connection(&self, connection_id: &ConnectionId) -> Result<Option<ConnectionEnd>> {
74        self.get(
75            &IBC_COMMITMENT_PREFIX.apply_string(ConnectionPath::new(connection_id).to_string()),
76        )
77        .await
78    }
79
80    async fn get_client_connections(&self, client_id: &ClientId) -> Result<ClientPaths> {
81        self.get(
82            &IBC_COMMITMENT_PREFIX.apply_string(ClientConnectionPath::new(client_id).to_string()),
83        )
84        .await
85        .map(|paths| paths.unwrap_or(ClientPaths { paths: vec![] }))
86    }
87}
88
89impl<T: StateRead + ?Sized> StateReadExt for T {}