Skip to content

Commit

Permalink
Handle begin & end block channel events (#1801)
Browse files Browse the repository at this point in the history
* Implement conversions for channel events

* Implement conversions for packets

* Resurrect code (from PR #1172) to extract begin/end-block events from a tendermint NewBlock event

* Add channel events in the right order

* Remove redundant clones

* Minor refactoring

* Fix failing CI tests

* Extract block events without depending on message.action

* Cleanup

* Add .changelog entry

* Document event extraction
  • Loading branch information
hu55a1n1 authored Feb 3, 2022
1 parent a6c8faf commit 02f2594
Show file tree
Hide file tree
Showing 5 changed files with 335 additions and 96 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Handle channel events originating from Tendermint ABCI's BeginBlock and EndBlock methods
([#1793](https://github.com/informalsystems/ibc-rs/issues/1793))
207 changes: 146 additions & 61 deletions modules/src/core/ics04_channel/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ use crate::core::ics02_client::height::Height;
use crate::core::ics04_channel::error::Error;
use crate::core::ics04_channel::packet::Packet;
use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId};
use crate::events::{extract_attribute, Error as EventError, IbcEvent, IbcEventType, RawObject};
use crate::events::{
extract_attribute, maybe_extract_attribute, Error as EventError, IbcEvent, IbcEventType,
RawObject,
};
use crate::prelude::*;

/// Channel event attribute keys
Expand All @@ -28,7 +31,6 @@ const PKT_DST_PORT_ATTRIBUTE_KEY: &str = "packet_dst_port";
const PKT_DST_CHANNEL_ATTRIBUTE_KEY: &str = "packet_dst_channel";
const PKT_TIMEOUT_HEIGHT_ATTRIBUTE_KEY: &str = "packet_timeout_height";
const PKT_TIMEOUT_TIMESTAMP_ATTRIBUTE_KEY: &str = "packet_timeout_timestamp";

const PKT_ACK_ATTRIBUTE_KEY: &str = "packet_ack";

pub fn try_from_tx(event: &tendermint::abci::Event) -> Option<IbcEvent> {
Expand Down Expand Up @@ -180,6 +182,31 @@ fn extract_packet_and_write_ack_from_tx(
Ok((packet, write_ack))
}

fn extract_attributes(object: &RawObject<'_>, namespace: &str) -> Result<Attributes, EventError> {
Ok(Attributes {
height: object.height,
port_id: extract_attribute(object, &format!("{}.port_id", namespace))?
.parse()
.map_err(EventError::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(EventError::parse)?,
counterparty_port_id: extract_attribute(
object,
&format!("{}.counterparty_port_id", namespace),
)?
.parse()
.map_err(EventError::parse)?,
counterparty_channel_id: maybe_extract_attribute(
object,
&format!("{}.counterparty_channel_id", namespace),
)
.and_then(|v| v.parse().ok()),
})
}

#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Attributes {
pub height: Height,
Expand Down Expand Up @@ -316,6 +343,10 @@ impl TryFrom<Packet> for Vec<Tag> {
}
}

trait EventType {
fn event_type() -> IbcEventType;
}

#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
pub struct OpenInit(pub Attributes);

Expand Down Expand Up @@ -349,13 +380,9 @@ impl From<OpenInit> for IbcEvent {
}
}

impl From<OpenInit> for AbciEvent {
fn from(v: OpenInit) -> Self {
let attributes = Vec::<Tag>::from(v.0);
AbciEvent {
type_str: IbcEventType::OpenInitChannel.as_str().to_string(),
attributes,
}
impl EventType for OpenInit {
fn event_type() -> IbcEventType {
IbcEventType::OpenInitChannel
}
}

Expand Down Expand Up @@ -392,13 +419,9 @@ impl From<OpenTry> for IbcEvent {
}
}

impl From<OpenTry> for AbciEvent {
fn from(v: OpenTry) -> Self {
let attributes = Vec::<Tag>::from(v.0);
AbciEvent {
type_str: IbcEventType::OpenTryChannel.as_str().to_string(),
attributes,
}
impl EventType for OpenTry {
fn event_type() -> IbcEventType {
IbcEventType::OpenTryChannel
}
}

Expand Down Expand Up @@ -439,13 +462,9 @@ impl From<OpenAck> for IbcEvent {
}
}

impl From<OpenAck> for AbciEvent {
fn from(v: OpenAck) -> Self {
let attributes = Vec::<Tag>::from(v.0);
AbciEvent {
type_str: IbcEventType::OpenAckChannel.as_str().to_string(),
attributes,
}
impl EventType for OpenAck {
fn event_type() -> IbcEventType {
IbcEventType::OpenAckChannel
}
}

Expand Down Expand Up @@ -482,13 +501,9 @@ impl From<OpenConfirm> for IbcEvent {
}
}

impl From<OpenConfirm> for AbciEvent {
fn from(v: OpenConfirm) -> Self {
let attributes = Vec::<Tag>::from(v.0);
AbciEvent {
type_str: IbcEventType::OpenConfirmChannel.as_str().to_string(),
attributes,
}
impl EventType for OpenConfirm {
fn event_type() -> IbcEventType {
IbcEventType::OpenConfirmChannel
}
}

Expand Down Expand Up @@ -537,16 +552,6 @@ impl From<CloseInit> for IbcEvent {
}
}

impl From<CloseInit> for AbciEvent {
fn from(v: CloseInit) -> Self {
let attributes = Vec::<Tag>::from(v.0);
AbciEvent {
type_str: IbcEventType::CloseInitChannel.as_str().to_string(),
attributes,
}
}
}

impl core::fmt::Display for CloseInit {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
write!(
Expand All @@ -559,6 +564,12 @@ impl core::fmt::Display for CloseInit {
}
}

impl EventType for CloseInit {
fn event_type() -> IbcEventType {
IbcEventType::CloseInitChannel
}
}

#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
pub struct CloseConfirm(pub Attributes);

Expand Down Expand Up @@ -586,16 +597,57 @@ impl From<CloseConfirm> for IbcEvent {
}
}

impl From<CloseConfirm> for AbciEvent {
fn from(v: CloseConfirm) -> Self {
let attributes = Vec::<Tag>::from(v.0);
AbciEvent {
type_str: IbcEventType::CloseConfirmChannel.as_str().to_string(),
attributes,
}
impl EventType for CloseConfirm {
fn event_type() -> IbcEventType {
IbcEventType::CloseConfirmChannel
}
}

macro_rules! impl_from_ibc_to_abci_event {
($($event:ty),+) => {
$(impl From<$event> for AbciEvent {
fn from(v: $event) -> Self {
let attributes = Vec::<Tag>::from(v.0);
let type_str = <$event>::event_type().as_str().to_string();
AbciEvent {
type_str,
attributes,
}
}
})+
};
}

impl_from_ibc_to_abci_event!(
OpenInit,
OpenTry,
OpenAck,
OpenConfirm,
CloseInit,
CloseConfirm
);

macro_rules! impl_try_from_raw_obj_for_event {
($($event:ty),+) => {
$(impl TryFrom<RawObject<'_>> for $event {
type Error = EventError;

fn try_from(obj: RawObject<'_>) -> Result<Self, Self::Error> {
Ok(Self(extract_attributes(&obj, Self::event_type().as_str())?))
}
})+
};
}

impl_try_from_raw_obj_for_event!(
OpenInit,
OpenTry,
OpenAck,
OpenConfirm,
CloseInit,
CloseConfirm
);

#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
pub struct SendPacket {
pub height: Height,
Expand Down Expand Up @@ -623,20 +675,6 @@ impl SendPacket {
}
}

impl TryFrom<RawObject> for SendPacket {
type Error = EventError;

fn try_from(obj: RawObject) -> Result<Self, Self::Error> {
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<SendPacket> for IbcEvent {
fn from(v: SendPacket) -> Self {
IbcEvent::SendPacket(v)
Expand Down Expand Up @@ -904,6 +942,53 @@ impl core::fmt::Display for TimeoutOnClosePacket {
}
}

macro_rules! impl_try_from_raw_obj_for_packet {
($($packet:ty),+) => {
$(impl TryFrom<RawObject<'_>> for $packet {
type Error = EventError;

fn try_from(obj: RawObject<'_>) -> Result<Self, Self::Error> {
let height = obj.height;
let data_str: String = extract_attribute(&obj, &format!("{}.{}", obj.action, PKT_DATA_ATTRIBUTE_KEY))?;

let mut packet = Packet::try_from(obj)?;
packet.data = Vec::from(data_str.as_str().as_bytes());

Ok(Self { height, packet })
}
})+
};
}

impl_try_from_raw_obj_for_packet!(
SendPacket,
ReceivePacket,
AcknowledgePacket,
TimeoutPacket,
TimeoutOnClosePacket
);

impl TryFrom<RawObject<'_>> for WriteAcknowledgement {
type Error = EventError;

fn try_from(obj: RawObject<'_>) -> Result<Self, Self::Error> {
let height = obj.height;
let data_str: String =
extract_attribute(&obj, &format!("{}.{}", obj.action, PKT_DATA_ATTRIBUTE_KEY))?;
let ack = extract_attribute(&obj, &format!("{}.{}", obj.action, PKT_ACK_ATTRIBUTE_KEY))?
.into_bytes();

let mut packet = Packet::try_from(obj)?;
packet.data = Vec::from(data_str.as_str().as_bytes());

Ok(Self {
height,
packet,
ack,
})
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
4 changes: 2 additions & 2 deletions modules/src/core/ics04_channel/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,9 @@ impl TryFrom<RawPacket> for Packet {
}
}

impl TryFrom<RawObject> for Packet {
impl TryFrom<RawObject<'_>> for Packet {
type Error = EventError;
fn try_from(obj: RawObject) -> Result<Self, Self::Error> {
fn try_from(obj: RawObject<'_>) -> Result<Self, Self::Error> {
Ok(Packet {
sequence: extract_attribute(&obj, &format!("{}.packet_sequence", obj.action))?
.parse()
Expand Down
16 changes: 8 additions & 8 deletions modules/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -463,21 +463,21 @@ impl IbcEvent {
}
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RawObject {
#[derive(Debug, Clone, Serialize)]
pub struct RawObject<'a> {
pub height: Height,
pub action: String,
pub idx: usize,
pub events: HashMap<String, Vec<String>>,
pub events: &'a HashMap<String, Vec<String>>,
}

impl RawObject {
impl<'a> RawObject<'a> {
pub fn new(
height: Height,
action: String,
idx: usize,
events: HashMap<String, Vec<String>>,
) -> RawObject {
events: &'a HashMap<String, Vec<String>>,
) -> RawObject<'a> {
RawObject {
height,
action,
Expand All @@ -500,7 +500,7 @@ pub fn extract_events(
Err(Error::incorrect_event_type(action_string.to_string()))
}

pub fn extract_attribute(object: &RawObject, key: &str) -> Result<String, Error> {
pub fn extract_attribute(object: &RawObject<'_>, key: &str) -> Result<String, Error> {
let value = object
.events
.get(key)
Expand All @@ -510,6 +510,6 @@ pub fn extract_attribute(object: &RawObject, key: &str) -> Result<String, Error>
Ok(value)
}

pub fn maybe_extract_attribute(object: &RawObject, key: &str) -> Option<String> {
pub fn maybe_extract_attribute(object: &RawObject<'_>, key: &str) -> Option<String> {
object.events.get(key).map(|tags| tags[object.idx].clone())
}
Loading

0 comments on commit 02f2594

Please sign in to comment.