Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle begin & end block channel events #1801

Merged
merged 12 commits into from
Feb 3, 2022
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