penumbra_sdk_ibc/
ibc_action.rs

1use ibc_proto::ibc::core::{
2    channel::v1::{
3        MsgAcknowledgement as RawMsgAcknowledgement,
4        MsgChannelCloseConfirm as RawMsgChannelCloseConfirm,
5        MsgChannelCloseInit as RawMsgChannelCloseInit, MsgChannelOpenAck as RawMsgChannelOpenAck,
6        MsgChannelOpenConfirm as RawMsgChannelOpenConfirm,
7        MsgChannelOpenInit as RawMsgChannelOpenInit, MsgChannelOpenTry as RawMsgChannelOpenTry,
8        MsgRecvPacket as RawMsgRecvPacket, MsgTimeout as RawMsgTimeout,
9    },
10    client::v1::{
11        MsgCreateClient as RawMsgCreateClient, MsgSubmitMisbehaviour as RawMsgSubmitMisbehaviour,
12        MsgUpdateClient as RawMsgUpdateClient, MsgUpgradeClient as RawMsgUpgradeClient,
13    },
14    connection::v1::{
15        MsgConnectionOpenAck as RawMsgConnectionOpenAck,
16        MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm,
17        MsgConnectionOpenInit as RawMsgConnectionOpenInit,
18        MsgConnectionOpenTry as RawMsgConnectionOpenTry,
19    },
20};
21use ibc_types::core::{
22    channel::msgs::{
23        MsgAcknowledgement, MsgChannelCloseConfirm, MsgChannelCloseInit, MsgChannelOpenAck,
24        MsgChannelOpenConfirm, MsgChannelOpenInit, MsgChannelOpenTry, MsgRecvPacket, MsgTimeout,
25    },
26    client::msgs::{MsgCreateClient, MsgSubmitMisbehaviour, MsgUpdateClient, MsgUpgradeClient},
27    connection::msgs::{
28        MsgConnectionOpenAck, MsgConnectionOpenConfirm, MsgConnectionOpenInit, MsgConnectionOpenTry,
29    },
30};
31
32use ibc_types::DomainType as IbcTypesDomainType;
33
34use penumbra_sdk_proto::penumbra::core::component::ibc::v1::{self as pb};
35use penumbra_sdk_proto::{DomainType, Name};
36use penumbra_sdk_txhash::{EffectHash, EffectingData};
37use serde::{Deserialize, Serialize};
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
40#[serde(try_from = "pb::IbcRelay", into = "pb::IbcRelay")]
41pub enum IbcRelay {
42    CreateClient(MsgCreateClient),
43    UpdateClient(MsgUpdateClient),
44    UpgradeClient(MsgUpgradeClient),
45    SubmitMisbehavior(MsgSubmitMisbehaviour),
46    ConnectionOpenInit(MsgConnectionOpenInit),
47    ConnectionOpenTry(MsgConnectionOpenTry),
48    ConnectionOpenAck(MsgConnectionOpenAck),
49    ConnectionOpenConfirm(MsgConnectionOpenConfirm),
50    ChannelOpenInit(MsgChannelOpenInit),
51    ChannelOpenTry(MsgChannelOpenTry),
52    ChannelOpenAck(MsgChannelOpenAck),
53    ChannelOpenConfirm(MsgChannelOpenConfirm),
54    ChannelCloseInit(MsgChannelCloseInit),
55    ChannelCloseConfirm(MsgChannelCloseConfirm),
56    RecvPacket(MsgRecvPacket),
57    Acknowledgement(MsgAcknowledgement),
58    Timeout(MsgTimeout),
59    Unknown(pbjson_types::Any),
60}
61
62impl IbcRelay {
63    /// Create a tracing span to track execution related to this action.
64    ///
65    /// The parent span is provided explicitly, so that this span can be constructed
66    /// nested under an `Action` span.
67    pub fn create_span(&self, parent: &tracing::Span) -> tracing::Span {
68        match self {
69            IbcRelay::CreateClient(msg) => {
70                // HACK: not a better way to get tm light client data
71                match ibc_types::lightclients::tendermint::client_state::ClientState::try_from(
72                    msg.client_state.clone(),
73                ) {
74                    Ok(tm_client) => {
75                        tracing::info_span!(parent: parent, "CreateClient", chain_id = %tm_client.chain_id)
76                    }
77                    Err(_) => tracing::info_span!(parent: parent, "CreateClient"),
78                }
79            }
80            IbcRelay::UpdateClient(msg) => {
81                tracing::info_span!(parent: parent, "UpdateClient", client_id = %msg.client_id)
82            }
83            IbcRelay::UpgradeClient(msg) => {
84                tracing::info_span!(parent: parent, "UpgradeClient", client_id = %msg.client_id)
85            }
86            IbcRelay::SubmitMisbehavior(msg) => {
87                tracing::info_span!(parent: parent, "SubmitMisbehavior", client_id = %msg.client_id)
88            }
89            IbcRelay::ConnectionOpenInit(msg) => {
90                tracing::info_span!(parent: parent, "ConnectionOpenInit", client_id = %msg.client_id_on_a)
91            }
92            IbcRelay::ConnectionOpenTry(msg) => {
93                tracing::info_span!(parent: parent, "ConnectionOpenTry", client_id = %msg.client_id_on_b)
94            }
95            IbcRelay::ConnectionOpenAck(msg) => {
96                tracing::info_span!(parent: parent, "ConnectionOpenAck", connection_id = %msg.conn_id_on_a)
97            }
98            IbcRelay::ConnectionOpenConfirm(msg) => {
99                tracing::info_span!(parent: parent, "ConnectionOpenConfirm", connection_id = %msg.conn_id_on_b)
100            }
101            IbcRelay::ChannelOpenInit(msg) => {
102                tracing::info_span!(parent: parent, "ChannelOpenInit", port_id = %msg.port_id_on_a)
103            }
104            IbcRelay::ChannelOpenTry(msg) => {
105                tracing::info_span!(parent: parent, "ChannelOpenTry", port_id = %msg.port_id_on_b)
106            }
107            IbcRelay::ChannelOpenAck(msg) => {
108                tracing::info_span!(parent: parent, "ChannelOpenAck", chan_id = %msg.chan_id_on_a)
109            }
110            IbcRelay::ChannelOpenConfirm(msg) => {
111                tracing::info_span!(parent: parent, "ChannelOpenConfirm", chan_id = %msg.chan_id_on_b)
112            }
113            IbcRelay::ChannelCloseInit(msg) => {
114                tracing::info_span!(parent: parent, "ChannelCloseInit", chan_id = %msg.chan_id_on_a)
115            }
116            IbcRelay::ChannelCloseConfirm(msg) => {
117                tracing::info_span!(parent: parent, "ChannelCloseConfirm", chan_id = %msg.chan_id_on_b)
118            }
119            IbcRelay::RecvPacket(msg) => {
120                tracing::info_span!(parent: parent, "RecvPacket", chan_id = %msg.packet.chan_on_b, seq = %msg.packet.sequence)
121            }
122            IbcRelay::Acknowledgement(msg) => {
123                tracing::info_span!(parent: parent, "Acknowledgement", chan_id = %msg.packet.chan_on_a, seq = %msg.packet.sequence)
124            }
125            IbcRelay::Timeout(msg) => {
126                tracing::info_span!(parent: parent, "Timeout", chan_id = %msg.packet.chan_on_a, seq = %msg.packet.sequence)
127            }
128            IbcRelay::Unknown(_) => {
129                tracing::info_span!(parent: parent, "Unknown")
130            }
131        }
132    }
133}
134
135impl EffectingData for IbcRelay {
136    fn effect_hash(&self) -> EffectHash {
137        EffectHash::from_proto_effecting_data(&self.to_proto())
138    }
139}
140
141impl DomainType for IbcRelay {
142    type Proto = pb::IbcRelay;
143}
144
145impl TryFrom<pb::IbcRelay> for IbcRelay {
146    type Error = anyhow::Error;
147    fn try_from(value: pb::IbcRelay) -> Result<Self, Self::Error> {
148        let raw_action = value
149            .raw_action
150            .ok_or_else(|| anyhow::anyhow!("empty IBC transaction is not allowed"))?;
151
152        let action_type = raw_action.type_url.as_str();
153        let raw_action_bytes = raw_action.value.clone();
154
155        // fn calls not allowed in match patterns, so we have a huge if else block
156        let outer_msg = if action_type == RawMsgCreateClient::type_url() {
157            let msg = MsgCreateClient::decode(raw_action_bytes)?;
158            IbcRelay::CreateClient(msg)
159        } else if action_type == RawMsgUpdateClient::type_url() {
160            let msg = MsgUpdateClient::decode(raw_action_bytes)?;
161            IbcRelay::UpdateClient(msg)
162        } else if action_type == RawMsgUpgradeClient::type_url() {
163            let msg = MsgUpgradeClient::decode(raw_action_bytes)?;
164            IbcRelay::UpgradeClient(msg)
165        } else if action_type == RawMsgSubmitMisbehaviour::type_url() {
166            let msg = MsgSubmitMisbehaviour::decode(raw_action_bytes)?;
167            IbcRelay::SubmitMisbehavior(msg)
168        } else if action_type == RawMsgConnectionOpenInit::type_url() {
169            let msg = MsgConnectionOpenInit::decode(raw_action_bytes)?;
170            IbcRelay::ConnectionOpenInit(msg)
171        } else if action_type == RawMsgConnectionOpenTry::type_url() {
172            let msg = MsgConnectionOpenTry::decode(raw_action_bytes)?;
173            IbcRelay::ConnectionOpenTry(msg)
174        } else if action_type == RawMsgConnectionOpenAck::type_url() {
175            let msg = MsgConnectionOpenAck::decode(raw_action_bytes)?;
176            IbcRelay::ConnectionOpenAck(msg)
177        } else if action_type == RawMsgConnectionOpenConfirm::type_url() {
178            let msg = MsgConnectionOpenConfirm::decode(raw_action_bytes)?;
179            IbcRelay::ConnectionOpenConfirm(msg)
180        } else if action_type == RawMsgAcknowledgement::type_url() {
181            let msg = MsgAcknowledgement::decode(raw_action_bytes)?;
182            IbcRelay::Acknowledgement(msg)
183        } else if action_type == RawMsgChannelOpenInit::type_url() {
184            let msg = MsgChannelOpenInit::decode(raw_action_bytes)?;
185            IbcRelay::ChannelOpenInit(msg)
186        } else if action_type == RawMsgChannelOpenTry::type_url() {
187            let msg = MsgChannelOpenTry::decode(raw_action_bytes)?;
188            IbcRelay::ChannelOpenTry(msg)
189        } else if action_type == RawMsgChannelOpenAck::type_url() {
190            let msg = MsgChannelOpenAck::decode(raw_action_bytes)?;
191            IbcRelay::ChannelOpenAck(msg)
192        } else if action_type == RawMsgChannelOpenConfirm::type_url() {
193            let msg = MsgChannelOpenConfirm::decode(raw_action_bytes)?;
194            IbcRelay::ChannelOpenConfirm(msg)
195        } else if action_type == RawMsgChannelCloseInit::type_url() {
196            let msg = MsgChannelCloseInit::decode(raw_action_bytes)?;
197            IbcRelay::ChannelCloseInit(msg)
198        } else if action_type == RawMsgChannelCloseConfirm::type_url() {
199            let msg = MsgChannelCloseConfirm::decode(raw_action_bytes)?;
200            IbcRelay::ChannelCloseConfirm(msg)
201        } else if action_type == RawMsgRecvPacket::type_url() {
202            let msg = MsgRecvPacket::decode(raw_action_bytes)?;
203            IbcRelay::RecvPacket(msg)
204        } else if action_type == RawMsgTimeout::type_url() {
205            let msg = MsgTimeout::decode(raw_action_bytes)?;
206            IbcRelay::Timeout(msg)
207        } else {
208            IbcRelay::Unknown(raw_action)
209        };
210
211        Ok(outer_msg)
212    }
213}
214
215impl From<IbcRelay> for pb::IbcRelay {
216    fn from(value: IbcRelay) -> Self {
217        let raw_action = match value {
218            IbcRelay::CreateClient(msg) => pbjson_types::Any {
219                type_url: RawMsgCreateClient::type_url(),
220                value: msg.encode_to_vec().into(),
221            },
222            IbcRelay::UpdateClient(msg) => pbjson_types::Any {
223                type_url: RawMsgUpdateClient::type_url(),
224                value: msg.encode_to_vec().into(),
225            },
226            IbcRelay::UpgradeClient(msg) => pbjson_types::Any {
227                type_url: RawMsgUpgradeClient::type_url(),
228                value: msg.encode_to_vec().into(),
229            },
230            IbcRelay::SubmitMisbehavior(msg) => pbjson_types::Any {
231                type_url: RawMsgSubmitMisbehaviour::type_url(),
232                value: msg.encode_to_vec().into(),
233            },
234            IbcRelay::ConnectionOpenInit(msg) => pbjson_types::Any {
235                type_url: RawMsgConnectionOpenInit::type_url(),
236                value: msg.encode_to_vec().into(),
237            },
238            IbcRelay::ConnectionOpenTry(msg) => pbjson_types::Any {
239                type_url: RawMsgConnectionOpenTry::type_url(),
240                value: msg.encode_to_vec().into(),
241            },
242            IbcRelay::ConnectionOpenAck(msg) => pbjson_types::Any {
243                type_url: RawMsgConnectionOpenAck::type_url(),
244                value: msg.encode_to_vec().into(),
245            },
246            IbcRelay::ConnectionOpenConfirm(msg) => pbjson_types::Any {
247                type_url: RawMsgConnectionOpenConfirm::type_url(),
248                value: msg.encode_to_vec().into(),
249            },
250            IbcRelay::Acknowledgement(msg) => pbjson_types::Any {
251                type_url: RawMsgAcknowledgement::type_url(),
252                value: msg.encode_to_vec().into(),
253            },
254            IbcRelay::ChannelOpenInit(msg) => pbjson_types::Any {
255                type_url: RawMsgChannelOpenInit::type_url(),
256                value: msg.encode_to_vec().into(),
257            },
258            IbcRelay::ChannelOpenTry(msg) => pbjson_types::Any {
259                type_url: RawMsgChannelOpenTry::type_url(),
260                value: msg.encode_to_vec().into(),
261            },
262            IbcRelay::ChannelOpenAck(msg) => pbjson_types::Any {
263                type_url: RawMsgChannelOpenAck::type_url(),
264                value: msg.encode_to_vec().into(),
265            },
266            IbcRelay::ChannelOpenConfirm(msg) => pbjson_types::Any {
267                type_url: RawMsgChannelOpenConfirm::type_url(),
268                value: msg.encode_to_vec().into(),
269            },
270            IbcRelay::ChannelCloseInit(msg) => pbjson_types::Any {
271                type_url: RawMsgChannelCloseInit::type_url(),
272                value: msg.encode_to_vec().into(),
273            },
274            IbcRelay::ChannelCloseConfirm(msg) => pbjson_types::Any {
275                type_url: RawMsgChannelCloseConfirm::type_url(),
276                value: msg.encode_to_vec().into(),
277            },
278            IbcRelay::RecvPacket(msg) => pbjson_types::Any {
279                type_url: RawMsgRecvPacket::type_url(),
280                value: msg.encode_to_vec().into(),
281            },
282            IbcRelay::Timeout(msg) => pbjson_types::Any {
283                type_url: RawMsgTimeout::type_url(),
284                value: msg.encode_to_vec().into(),
285            },
286            IbcRelay::Unknown(raw_action) => raw_action,
287        };
288        pb::IbcRelay {
289            raw_action: Some(raw_action),
290        }
291    }
292}