diff --git a/.changelog/unreleased/improvements/1191-ica-compat.md b/.changelog/unreleased/improvements/1191-ica-compat.md new file mode 100644 index 0000000000..b189173405 --- /dev/null +++ b/.changelog/unreleased/improvements/1191-ica-compat.md @@ -0,0 +1,4 @@ +- Improve support for Interchain Accounts (ICS 027) ([#1191]) + +[#1191]: https://github.com/informalsystems/ibc-rs/issues/1191 + diff --git a/modules/src/events.rs b/modules/src/events.rs index b25fccbb1b..000f2c63f8 100644 --- a/modules/src/events.rs +++ b/modules/src/events.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use serde_derive::{Deserialize, Serialize}; use crate::ics02_client::error as client_error; @@ -259,74 +257,3 @@ impl IbcEvent { } } } - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct RawObject { - pub height: Height, - pub action: String, - pub idx: usize, - pub events: HashMap>, -} - -impl RawObject { - pub fn new( - height: Height, - action: String, - idx: usize, - events: HashMap>, - ) -> RawObject { - RawObject { - height, - action, - idx, - events, - } - } -} - -pub fn extract_events( - events: &HashMap, S>, - action_string: &str, -) -> Result<(), Error> { - if let Some(message_action) = events.get("message.action") { - if message_action.contains(&action_string.to_owned()) { - return Ok(()); - } - return Err(Error::missing_action_string()); - } - Err(Error::incorrect_event_type(action_string.to_string())) -} - -pub fn extract_attribute(object: &RawObject, key: &str) -> Result { - let value = object - .events - .get(key) - .ok_or_else(|| Error::missing_key(key.to_string()))?[object.idx] - .clone(); - - Ok(value) -} - -pub fn maybe_extract_attribute(object: &RawObject, key: &str) -> Option { - object.events.get(key).map(|tags| tags[object.idx].clone()) -} - -#[macro_export] -macro_rules! make_event { - ($a:ident, $b:literal) => { - #[derive(Debug, Deserialize, Serialize, Clone)] - pub struct $a { - pub data: ::std::collections::HashMap>, - } - impl ::std::convert::TryFrom<$crate::events::RawObject> for $a { - type Error = $crate::event::Error; - - fn try_from(result: $crate::events::RawObject) -> Result { - $crate::events::extract_events(&result.events, $b)?; - Ok($a { - data: result.events.clone(), - }) - } - } - }; -} diff --git a/modules/src/ics02_client/events.rs b/modules/src/ics02_client/events.rs index 5082e55c2d..26e33b41b4 100644 --- a/modules/src/ics02_client/events.rs +++ b/modules/src/ics02_client/events.rs @@ -1,12 +1,10 @@ //! Types for the IBC events emitted from Tendermint Websocket by the client module. -use std::convert::{TryFrom, TryInto}; -use prost::Message; use serde_derive::{Deserialize, Serialize}; use subtle_encoding::hex; use tendermint_proto::Protobuf; -use crate::events::{extract_attribute, Error, IbcEvent, RawObject}; +use crate::events::IbcEvent; use crate::ics02_client::client_type::ClientType; use crate::ics02_client::header::AnyHeader; use crate::ics02_client::height::Height; @@ -134,25 +132,6 @@ impl std::fmt::Display for Attributes { } } -fn extract_attributes(object: &RawObject, namespace: &str) -> Result { - Ok(Attributes { - height: object.height, - - client_id: extract_attribute(object, &format!("{}.client_id", namespace))? - .parse() - .map_err(Error::parse)?, - - client_type: extract_attribute(object, &format!("{}.client_type", namespace))? - .parse() - .map_err(Error::client)?, - - consensus_height: extract_attribute(object, &format!("{}.consensus_height", namespace))? - .as_str() - .try_into() - .map_err(Error::height)?, - }) -} - /// CreateClient event signals the creation of a new on-chain client (IBC client). #[derive(Debug, Deserialize, Serialize, Clone)] pub struct CreateClient(pub Attributes); @@ -175,13 +154,6 @@ impl From for CreateClient { } } -impl TryFrom for CreateClient { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - Ok(CreateClient(extract_attributes(&obj, "create_client")?)) - } -} - impl From for IbcEvent { fn from(v: CreateClient) -> Self { IbcEvent::CreateClient(v) @@ -231,36 +203,6 @@ impl From for UpdateClient { } } -impl TryFrom for UpdateClient { - type Error = Error; - - fn try_from(obj: RawObject) -> Result { - let header_str: Option = obj - .events - .get("update_client.header") - .and_then(|tags| tags[obj.idx].parse().ok()); - - let header: Option = match header_str { - Some(str) => { - let header_bytes = hex::decode(str).map_err(Error::subtle_encoding)?; - - let decoded = prost_types::Any::decode(header_bytes.as_ref()) - .map_err(Error::decode)? - .try_into() - .map_err(Error::client)?; - - Some(decoded) - } - None => None, - }; - - Ok(UpdateClient { - common: extract_attributes(&obj, "update_client")?, - header, - }) - } -} - impl From for IbcEvent { fn from(v: UpdateClient) -> Self { IbcEvent::UpdateClient(v) @@ -290,16 +232,6 @@ impl ClientMisbehaviour { } } -impl TryFrom for ClientMisbehaviour { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - Ok(ClientMisbehaviour(extract_attributes( - &obj, - "client_misbehaviour", - )?)) - } -} - impl From for IbcEvent { fn from(v: ClientMisbehaviour) -> Self { IbcEvent::ClientMisbehaviour(v) diff --git a/modules/src/ics03_connection/events.rs b/modules/src/ics03_connection/events.rs index 2380ce2155..5908207d4c 100644 --- a/modules/src/ics03_connection/events.rs +++ b/modules/src/ics03_connection/events.rs @@ -1,9 +1,8 @@ //! Types for the IBC events emitted from Tendermint Websocket by the connection module. -use crate::events::{extract_attribute, maybe_extract_attribute, Error, IbcEvent, RawObject}; +use crate::events::IbcEvent; use crate::ics02_client::height::Height; use crate::ics24_host::identifier::{ClientId, ConnectionId}; use serde_derive::{Deserialize, Serialize}; -use std::convert::TryFrom; /// The content of the `type` field for the event that a chain produces upon executing a connection handshake transaction. const INIT_EVENT_TYPE: &str = "connection_open_init"; @@ -67,32 +66,6 @@ pub struct Attributes { pub counterparty_client_id: ClientId, } -fn extract_attributes(object: &RawObject, namespace: &str) -> Result { - Ok(Attributes { - height: object.height, - - connection_id: maybe_extract_attribute(object, &format!("{}.connection_id", namespace)) - .and_then(|val| val.parse().ok()), - - client_id: extract_attribute(object, &format!("{}.client_id", namespace))? - .parse() - .map_err(Error::parse)?, - - counterparty_connection_id: maybe_extract_attribute( - object, - &format!("{}.counterparty_connection_id", namespace), - ) - .and_then(|val| val.parse().ok()), - - counterparty_client_id: extract_attribute( - object, - &format!("{}.counterparty_client_id", namespace), - )? - .parse() - .map_err(Error::parse)?, - }) -} - impl Default for Attributes { fn default() -> Self { Attributes { @@ -129,13 +102,6 @@ impl From for OpenInit { } } -impl TryFrom for OpenInit { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - Ok(OpenInit(extract_attributes(&obj, "connection_open_init")?)) - } -} - impl From for IbcEvent { fn from(v: OpenInit) -> Self { IbcEvent::OpenInitConnection(v) @@ -166,13 +132,6 @@ impl From for OpenTry { } } -impl TryFrom for OpenTry { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - Ok(OpenTry(extract_attributes(&obj, "connection_open_try")?)) - } -} - impl From for IbcEvent { fn from(v: OpenTry) -> Self { IbcEvent::OpenTryConnection(v) @@ -203,13 +162,6 @@ impl From for OpenAck { } } -impl TryFrom for OpenAck { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - Ok(OpenAck(extract_attributes(&obj, "connection_open_ack")?)) - } -} - impl From for IbcEvent { fn from(v: OpenAck) -> Self { IbcEvent::OpenAckConnection(v) @@ -240,16 +192,6 @@ impl From for OpenConfirm { } } -impl TryFrom for OpenConfirm { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - Ok(OpenConfirm(extract_attributes( - &obj, - "connection_open_confirm", - )?)) - } -} - impl From for IbcEvent { fn from(v: OpenConfirm) -> Self { IbcEvent::OpenConfirmConnection(v) diff --git a/modules/src/ics04_channel/events.rs b/modules/src/ics04_channel/events.rs index f5f9e9aa45..5877f277d6 100644 --- a/modules/src/ics04_channel/events.rs +++ b/modules/src/ics04_channel/events.rs @@ -1,10 +1,9 @@ //! Types for the IBC events emitted from Tendermint Websocket by the channels module. -use crate::events::{extract_attribute, maybe_extract_attribute, Error, IbcEvent, RawObject}; +use crate::events::IbcEvent; use crate::ics02_client::height::Height; use crate::ics04_channel::packet::Packet; use crate::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; use serde_derive::{Deserialize, Serialize}; -use std::convert::TryFrom; /// Channel event types const OPEN_INIT_EVENT_TYPE: &str = "channel_open_init"; @@ -62,7 +61,7 @@ pub fn try_from_tx(event: &tendermint::abci::Event) -> Option { SEND_PACKET => { let (packet, write_ack) = extract_packet_and_write_ack_from_tx(event); // This event should not have a write ack. - assert!(write_ack.is_none()); + assert_eq!(write_ack.len(), 0); Some(IbcEvent::SendPacket(SendPacket { height: Default::default(), packet, @@ -70,8 +69,6 @@ pub fn try_from_tx(event: &tendermint::abci::Event) -> Option { } WRITE_ACK => { let (packet, write_ack) = extract_packet_and_write_ack_from_tx(event); - // This event should have a write ack. - let write_ack = write_ack.unwrap(); Some(IbcEvent::WriteAcknowledgement(WriteAcknowledgement { height: Default::default(), packet, @@ -81,7 +78,7 @@ pub fn try_from_tx(event: &tendermint::abci::Event) -> Option { ACK_PACKET => { let (packet, write_ack) = extract_packet_and_write_ack_from_tx(event); // This event should not have a write ack. - assert!(write_ack.is_none()); + assert_eq!(write_ack.len(), 0); Some(IbcEvent::AcknowledgePacket(AcknowledgePacket { height: Default::default(), packet, @@ -90,7 +87,7 @@ pub fn try_from_tx(event: &tendermint::abci::Event) -> Option { TIMEOUT => { let (packet, write_ack) = extract_packet_and_write_ack_from_tx(event); // This event should not have a write ack. - assert!(write_ack.is_none()); + assert_eq!(write_ack.len(), 0); Some(IbcEvent::TimeoutPacket(TimeoutPacket { height: Default::default(), packet, @@ -123,11 +120,9 @@ fn extract_attributes_from_tx(event: &tendermint::abci::Event) -> Attributes { attr } -fn extract_packet_and_write_ack_from_tx( - event: &tendermint::abci::Event, -) -> (Packet, Option>) { +fn extract_packet_and_write_ack_from_tx(event: &tendermint::abci::Event) -> (Packet, Vec) { let mut packet = Packet::default(); - let mut write_ack = None; + let mut write_ack: Vec = vec![]; for tag in &event.attributes { let key = tag.key.as_ref(); let value = tag.value.as_ref(); @@ -142,7 +137,7 @@ fn extract_packet_and_write_ack_from_tx( packet.timeout_timestamp = value.parse().unwrap() } PKT_DATA_ATTRIBUTE_KEY => packet.data = Vec::from(value.as_bytes()), - PKT_ACK_ATTRIBUTE_KEY => write_ack = Some(Vec::from(value.as_bytes())), + PKT_ACK_ATTRIBUTE_KEY => write_ack = Vec::from(value.as_bytes()), _ => {} }; } @@ -160,31 +155,6 @@ pub struct Attributes { pub counterparty_channel_id: Option, } -fn extract_attributes(object: &RawObject, namespace: &str) -> Result { - Ok(Attributes { - height: object.height, - port_id: extract_attribute(object, &format!("{}.port_id", namespace))? - .parse() - .map_err(Error::parse)?, - channel_id: maybe_extract_attribute(object, &format!("{}.channel_id", namespace)) - .and_then(|v| v.parse().ok()), - connection_id: extract_attribute(object, &format!("{}.connection_id", namespace))? - .parse() - .map_err(Error::parse)?, - counterparty_port_id: extract_attribute( - object, - &format!("{}.counterparty_port_id", namespace), - )? - .parse() - .map_err(Error::parse)?, - counterparty_channel_id: maybe_extract_attribute( - object, - &format!("{}.counterparty_channel_id", namespace), - ) - .and_then(|v| v.parse().ok()), - }) -} - impl Attributes { pub fn port_id(&self) -> &PortId { &self.port_id @@ -234,13 +204,6 @@ impl From for OpenInit { } } -impl TryFrom for OpenInit { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - Ok(OpenInit(extract_attributes(&obj, "channel_open_init")?)) - } -} - impl From for IbcEvent { fn from(v: OpenInit) -> Self { IbcEvent::OpenInitChannel(v) @@ -274,13 +237,6 @@ impl From for OpenTry { } } -impl TryFrom for OpenTry { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - Ok(OpenTry(extract_attributes(&obj, "channel_open_try")?)) - } -} - impl From for IbcEvent { fn from(v: OpenTry) -> Self { IbcEvent::OpenTryChannel(v) @@ -318,13 +274,6 @@ impl From for OpenAck { } } -impl TryFrom for OpenAck { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - Ok(OpenAck(extract_attributes(&obj, "channel_open_ack")?)) - } -} - impl From for IbcEvent { fn from(v: OpenAck) -> Self { IbcEvent::OpenAckChannel(v) @@ -358,16 +307,6 @@ impl From for OpenConfirm { } } -impl TryFrom for OpenConfirm { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - Ok(OpenConfirm(extract_attributes( - &obj, - "channel_open_confirm", - )?)) - } -} - impl From for IbcEvent { fn from(v: OpenConfirm) -> Self { IbcEvent::OpenConfirmChannel(v) @@ -413,13 +352,6 @@ impl From for CloseInit { } } -impl TryFrom for CloseInit { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - Ok(CloseInit(extract_attributes(&obj, "channel_close_init")?)) - } -} - impl From for IbcEvent { fn from(v: CloseInit) -> Self { IbcEvent::CloseInitChannel(v) @@ -459,61 +391,12 @@ impl From for CloseConfirm { } } -impl TryFrom for CloseConfirm { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - Ok(CloseConfirm(extract_attributes( - &obj, - "channel_close_confirm", - )?)) - } -} - impl From for IbcEvent { fn from(v: CloseConfirm) -> Self { IbcEvent::CloseConfirmChannel(v) } } -impl TryFrom for Packet { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - Ok(Packet { - sequence: extract_attribute(&obj, &format!("{}.packet_sequence", obj.action))? - .parse() - .map_err(Error::channel)?, - source_port: extract_attribute(&obj, &format!("{}.packet_src_port", obj.action))? - .parse() - .map_err(Error::parse)?, - source_channel: extract_attribute(&obj, &format!("{}.packet_src_channel", obj.action))? - .parse() - .map_err(Error::parse)?, - destination_port: extract_attribute(&obj, &format!("{}.packet_dst_port", obj.action))? - .parse() - .map_err(Error::parse)?, - destination_channel: extract_attribute( - &obj, - &format!("{}.packet_dst_channel", obj.action), - )? - .parse() - .map_err(Error::parse)?, - data: vec![], - timeout_height: extract_attribute( - &obj, - &format!("{}.packet_timeout_height", obj.action), - )? - .parse() - .map_err(Error::height)?, - timeout_timestamp: extract_attribute( - &obj, - &format!("{}.packet_timeout_timestamp", obj.action), - )? - .parse() - .map_err(Error::timestamp)?, - }) - } -} - #[derive(Debug, Deserialize, Serialize, Clone)] pub struct SendPacket { pub height: Height, @@ -541,19 +424,6 @@ impl SendPacket { } } -impl TryFrom for SendPacket { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - let height = obj.height; - let data_str: String = extract_attribute(&obj, &format!("{}.packet_data", obj.action))?; - - let mut packet = Packet::try_from(obj)?; - packet.data = Vec::from(data_str.as_str().as_bytes()); - - Ok(SendPacket { height, packet }) - } -} - impl From for IbcEvent { fn from(v: SendPacket) -> Self { IbcEvent::SendPacket(v) @@ -593,19 +463,6 @@ impl ReceivePacket { } } -impl TryFrom for ReceivePacket { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - let height = obj.height; - let data_str: String = extract_attribute(&obj, &format!("{}.packet_data", obj.action))?; - - let mut packet = Packet::try_from(obj)?; - packet.data = Vec::from(data_str.as_str().as_bytes()); - - Ok(ReceivePacket { height, packet }) - } -} - impl From for IbcEvent { fn from(v: ReceivePacket) -> Self { IbcEvent::ReceivePacket(v) @@ -647,26 +504,6 @@ impl WriteAcknowledgement { } } -impl TryFrom for WriteAcknowledgement { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - let height = obj.height; - - let data_str: String = extract_attribute(&obj, &format!("{}.packet_data", obj.action))?; - - let ack_str: String = extract_attribute(&obj, &format!("{}.packet_ack", obj.action))?; - - let mut packet = Packet::try_from(obj)?; - packet.data = Vec::from(data_str.as_str().as_bytes()); - - Ok(WriteAcknowledgement { - height, - packet, - ack: Vec::from(ack_str.as_str().as_bytes()), - }) - } -} - impl From for IbcEvent { fn from(v: WriteAcknowledgement) -> Self { IbcEvent::WriteAcknowledgement(v) @@ -704,15 +541,6 @@ impl AcknowledgePacket { } } -impl TryFrom for AcknowledgePacket { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - let height = obj.height; - let packet = Packet::try_from(obj)?; - Ok(AcknowledgePacket { height, packet }) - } -} - impl From for IbcEvent { fn from(v: AcknowledgePacket) -> Self { IbcEvent::AcknowledgePacket(v) @@ -752,16 +580,6 @@ impl TimeoutPacket { } } -impl TryFrom for TimeoutPacket { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - Ok(TimeoutPacket { - height: obj.height, - packet: Packet::try_from(obj)?, - }) - } -} - impl From for IbcEvent { fn from(v: TimeoutPacket) -> Self { IbcEvent::TimeoutPacket(v) @@ -801,16 +619,6 @@ impl TimeoutOnClosePacket { } } -impl TryFrom for TimeoutOnClosePacket { - type Error = Error; - fn try_from(obj: RawObject) -> Result { - Ok(TimeoutOnClosePacket { - height: obj.height, - packet: Packet::try_from(obj)?, - }) - } -} - impl From for IbcEvent { fn from(v: TimeoutOnClosePacket) -> Self { IbcEvent::TimeoutOnClosePacket(v) diff --git a/modules/src/ics04_channel/msgs/timeout_on_close.rs b/modules/src/ics04_channel/msgs/timeout_on_close.rs index c181ab0772..3f38b67793 100644 --- a/modules/src/ics04_channel/msgs/timeout_on_close.rs +++ b/modules/src/ics04_channel/msgs/timeout_on_close.rs @@ -91,7 +91,7 @@ impl From for RawMsgTimeoutOnClose { proof_unreceived: domain_msg.proofs.object_proof().clone().into(), proof_close: domain_msg .proofs - .other_proof + .other_proof() .clone() .map_or_else(Vec::new, |v| v.into()), proof_height: Some(domain_msg.proofs.height().into()), diff --git a/modules/src/ics23_commitment/commitment.rs b/modules/src/ics23_commitment/commitment.rs index 05dd099914..64badebadc 100644 --- a/modules/src/ics23_commitment/commitment.rs +++ b/modules/src/ics23_commitment/commitment.rs @@ -43,13 +43,20 @@ impl From> for CommitmentRoot { #[derive(Clone, Debug, PartialEq)] pub struct CommitmentPath; -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +#[derive(Clone, PartialEq, Eq, Serialize)] #[serde(transparent)] pub struct CommitmentProofBytes { #[serde(serialize_with = "crate::serializers::ser_hex_upper")] bytes: Vec, } +impl fmt::Debug for CommitmentProofBytes { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let hex = Hex::upper_case().encode_to_string(&self.bytes).unwrap(); + f.debug_tuple("CommitmentProof").field(&hex).finish() + } +} + impl CommitmentProofBytes { pub fn is_empty(&self) -> bool { self.bytes.len() == 0 diff --git a/modules/src/proofs.rs b/modules/src/proofs.rs index 5163f9cc85..91ec56969e 100644 --- a/modules/src/proofs.rs +++ b/modules/src/proofs.rs @@ -23,7 +23,7 @@ pub struct Proofs { client_proof: Option, consensus_proof: Option, /// Currently used for proof_close for MsgTimeoutOnCLose where object_proof is proof_unreceived - pub(crate) other_proof: Option, + other_proof: Option, /// Height for the commitment root for proving the proofs above. /// When creating these proofs, the chain is queried at `height-1`. height: Height, @@ -75,6 +75,11 @@ impl Proofs { pub fn client_proof(&self) -> &Option { &self.client_proof } + + /// Getter for the other_proof. + pub fn other_proof(&self) -> &Option { + &self.other_proof + } } #[derive(Clone, Debug, PartialEq, Eq, Serialize)] diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 27de7ed4e3..e3ce1ead76 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -826,7 +826,7 @@ impl Channel { *src_channel.ordering(), counterparty, vec![self.dst_connection_id().clone()], - self.dst_version()?, + src_channel.version(), ); // Get signer @@ -845,7 +845,7 @@ impl Channel { let new_msg = MsgChannelOpenTry { port_id: self.dst_port_id().clone(), previous_channel_id, - counterparty_version: self.src_version()?, + counterparty_version: src_channel.version(), channel, proofs, signer, @@ -894,7 +894,8 @@ impl Channel { self.validated_expected_channel(ChannelMsgType::OpenAck)?; // Channel must exist on source - self.src_chain() + let src_channel = self + .src_chain() .query_channel(self.src_port_id(), src_channel_id, Height::zero()) .map_err(|e| ChannelError::query(self.src_chain().id(), e))?; @@ -927,7 +928,7 @@ impl Channel { port_id: self.dst_port_id().clone(), channel_id: dst_channel_id.clone(), counterparty_channel_id: src_channel_id.clone(), - counterparty_version: self.src_version()?, + counterparty_version: src_channel.version(), proofs, signer, }; diff --git a/relayer/src/event/rpc.rs b/relayer/src/event/rpc.rs index bcfe85c693..043a9fddb0 100644 --- a/relayer/src/event/rpc.rs +++ b/relayer/src/event/rpc.rs @@ -1,16 +1,9 @@ -use std::{collections::HashMap, convert::TryFrom}; - -use tendermint_rpc::event::{Event as RpcEvent, EventData as RpcEventData}; +use tendermint_rpc::event::{Event as RpcEvent, EventData as RpcEventData, EventData}; +use ibc::events::{from_tx_response_event, IbcEvent}; use ibc::ics02_client::events::NewBlock; use ibc::ics02_client::height::Height; use ibc::ics24_host::identifier::ChainId; -use ibc::{ - events::{Error as EventError, IbcEvent, RawObject}, - ics02_client::events as ClientEvents, - ics03_connection::events as ConnectionEvents, - ics04_channel::events as ChannelEvents, -}; pub fn get_all_events( chain_id: &ChainId, @@ -27,26 +20,16 @@ pub fn get_all_events( vals.push((height, NewBlock::new(height).into())); } - - RpcEventData::Tx { .. } => { - let events = &result.events.ok_or("missing events")?; - let height_raw = events.get("tx.height").ok_or("tx.height")?[0] - .parse::() - .map_err(|e| e.to_string())?; + EventData::Tx { tx_result } => { let height = Height::new( ChainId::chain_version(chain_id.to_string().as_str()), - height_raw, + tx_result.height as u64, ); - let actions_and_indices = extract_helper(events)?; - for action in actions_and_indices { - if let Ok(event) = build_event(RawObject::new( - height, - action.0, - action.1 as usize, - events.clone(), - )) { - vals.push((height, event)); + for abci_event in &tx_result.result.events { + if let Some(ibc_event) = from_tx_response_event(height, abci_event) { + tracing::trace!("Extracted ibc_event {:?}", ibc_event); + vals.push((height, ibc_event)); } } } @@ -55,192 +38,3 @@ pub fn get_all_events( Ok(vals) } - -pub fn build_event(mut object: RawObject) -> Result { - match object.action.as_str() { - // Client events - "create_client" | ibc::ics02_client::msgs::create_client::TYPE_URL => Ok(IbcEvent::from( - ClientEvents::CreateClient::try_from(object)?, - )), - "update_client" | ibc::ics02_client::msgs::update_client::TYPE_URL => Ok(IbcEvent::from( - ClientEvents::UpdateClient::try_from(object)?, - )), - "submit_misbehaviour" | ibc::ics02_client::msgs::misbehavior::TYPE_URL => Ok( - IbcEvent::from(ClientEvents::ClientMisbehaviour::try_from(object)?), - ), - - // Connection events - "connection_open_init" | ibc::ics03_connection::msgs::conn_open_init::TYPE_URL => Ok( - IbcEvent::from(ConnectionEvents::OpenInit::try_from(object)?), - ), - "connection_open_try" | ibc::ics03_connection::msgs::conn_open_try::TYPE_URL => { - Ok(IbcEvent::from(ConnectionEvents::OpenTry::try_from(object)?)) - } - "connection_open_ack" | ibc::ics03_connection::msgs::conn_open_ack::TYPE_URL => { - Ok(IbcEvent::from(ConnectionEvents::OpenAck::try_from(object)?)) - } - "connection_open_confirm" | ibc::ics03_connection::msgs::conn_open_confirm::TYPE_URL => Ok( - IbcEvent::from(ConnectionEvents::OpenConfirm::try_from(object)?), - ), - - // Channel events - "channel_open_init" | ibc::ics04_channel::msgs::chan_open_init::TYPE_URL => { - Ok(IbcEvent::from(ChannelEvents::OpenInit::try_from(object)?)) - } - "channel_open_try" | ibc::ics04_channel::msgs::chan_open_try::TYPE_URL => { - Ok(IbcEvent::from(ChannelEvents::OpenTry::try_from(object)?)) - } - "channel_open_ack" | ibc::ics04_channel::msgs::chan_open_ack::TYPE_URL => { - Ok(IbcEvent::from(ChannelEvents::OpenAck::try_from(object)?)) - } - "channel_open_confirm" | ibc::ics04_channel::msgs::chan_open_confirm::TYPE_URL => Ok( - IbcEvent::from(ChannelEvents::OpenConfirm::try_from(object)?), - ), - "channel_close_init" | ibc::ics04_channel::msgs::chan_close_init::TYPE_URL => { - Ok(IbcEvent::from(ChannelEvents::CloseInit::try_from(object)?)) - } - "channel_close_confirm" | ibc::ics04_channel::msgs::chan_close_confirm::TYPE_URL => Ok( - IbcEvent::from(ChannelEvents::CloseConfirm::try_from(object)?), - ), - - // Packet events - // Note: There is no message.action "send_packet", the only one we can hook into is the - // module's action: - // - "transfer" for ICS20 - // - "MsgSend" and "MsgRegister" for ICS27 - // However the attributes are all prefixed with "send_packet" therefore the overwrite here - // TODO: This need to be sorted out - "transfer" - | ibc::application::ics20_fungible_token_transfer::msgs::transfer::TYPE_URL - | ibc::application::ICS27_BANK_SEND_TYPE_URL - | ibc::application::ICS27_SEND_TYPE_URL - | ibc::application::ICS27_REGISTER_TYPE_URL => { - object.action = "send_packet".to_string(); - Ok(IbcEvent::from(ChannelEvents::SendPacket::try_from(object)?)) - } - // Same here - // TODO: sort this out - "recv_packet" | ibc::ics04_channel::msgs::recv_packet::TYPE_URL => { - object.action = "write_acknowledgement".to_string(); - Ok(IbcEvent::from( - ChannelEvents::WriteAcknowledgement::try_from(object)?, - )) - } - "write_acknowledgement" => Ok(IbcEvent::from( - ChannelEvents::WriteAcknowledgement::try_from(object)?, - )), - "acknowledge_packet" | ibc::ics04_channel::msgs::acknowledgement::TYPE_URL => { - object.action = "acknowledge_packet".to_string(); - Ok(IbcEvent::from(ChannelEvents::AcknowledgePacket::try_from( - object, - )?)) - } - "timeout_packet" | ibc::ics04_channel::msgs::timeout::TYPE_URL => { - object.action = "timeout_packet".to_string(); - Ok(IbcEvent::from(ChannelEvents::TimeoutPacket::try_from( - object, - )?)) - } - "timeout_on_close_packet" | ibc::ics04_channel::msgs::timeout_on_close::TYPE_URL => { - object.action = "timeout_packet".to_string(); - Ok(IbcEvent::from( - ChannelEvents::TimeoutOnClosePacket::try_from(object)?, - )) - } - - event_type => Err(EventError::incorrect_event_type(event_type.to_string())), - } -} - -/// Takes events in the form -/// -/// ```json -/// { -/// "events": { -/// "connection_open_init.client_id": [ -/// "testclient", -/// "testclientsec" -/// ], -/// "connection_open_init.connection_id": [ -/// "ancaconnonetest", -/// "ancaconnonetestsec" -/// ], -/// "connection_open_init.counterparty_client_id": [ -/// "testclientsec", -/// "testclientsecsec" -/// ], -/// "create_client.client_id": [ -/// "testclientthird" -/// ], -/// "create_client.client_type": [ -/// "tendermint" -/// ], -/// "message.action": [ -/// "connection_open_init", -/// "create_client", -/// "connection_open_init" -/// ], -/// "message.module": [ -/// "ibc_connection", -/// "ibc_client", -/// "ibc_connection" -/// ], -/// "message.sender": [ -/// "cosmos187xxg4yfkypl05cqylucezpjvycj24nurvm8p9", -/// "cosmos187xxg4yfkypl05cqylucezpjvycj24nurvm8p9", -/// "cosmos187xxg4yfkypl05cqylucezpjvycj24nurvm8p9", -/// "cosmos187xxg4yfkypl05cqylucezpjvycj24nurvm8p9" -/// ], -/// "tm.event": [ -/// "Tx" -/// ], -/// "transfer.amount": [ -/// "5000stake" -/// ], -/// "transfer.recipient": [ -/// "cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta" -/// ], -/// "tx.hash": [ -/// "A9E18AE3909F22232F8DBDB1C48F2FECB260A308A2D157E8832E901D45950605" -/// ], -/// "tx.height": [ -/// "35" -/// ] -/// } -/// } -/// ``` -/// -/// and returns: -/// -/// ```rust -/// vec![ -/// ("connection_open_init", 0), -/// ("create_client", 0), -/// ("connection_open_init", 1), -/// ]; -/// ``` -/// -/// where the number in each entry is the index in the matching events that should be used to build the event. -/// -/// e.g. for the last "connection_open_init" in the result -/// -/// ```text -/// "connection_open_init.client_id" -> "testclientsec" -/// "connection_open_init.connection_id" -> "ancaconnonetestsec", -/// "connection_open_init.counterparty_client_id" -> "testclientsec", "testclientsecsec", -/// ``` -fn extract_helper(events: &HashMap>) -> Result, String> { - let actions = events.get("message.action").ok_or("Incorrect Event Type")?; - - let mut val_indices = HashMap::new(); - let mut result = Vec::with_capacity(actions.len()); - - for action in actions { - let idx = val_indices.entry(action.clone()).or_insert_with(|| 0); - result.push((action.clone(), *idx)); - - *val_indices.get_mut(action.as_str()).unwrap() += 1; - } - - Ok(result) -}