Skip to content

Commit

Permalink
feat: add support for MsgChannelUpgradeTimeout and integration test (
Browse files Browse the repository at this point in the history
…#3773)

* feat: add support for msgchannelupgradetimeout and integration test

* fix build errors

* Update nix flake

* Update CLI templates

* cargo fmt

* Fix clippy warnings/errors

* Fix extracting upgrade_timeout attribute

* WIP

* Fix channel upgrade logic

* Change Height to QueryHeight for restore_from_state method

---------

Co-authored-by: Luca Joss <luca@informal.systems>
  • Loading branch information
crodriguezvega and ljoss17 authored Jan 18, 2024
1 parent 96802be commit ee971f3
Show file tree
Hide file tree
Showing 21 changed files with 1,259 additions and 53 deletions.
3 changes: 3 additions & 0 deletions crates/relayer-cli/src/commands/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ pub enum TxCmd {
/// Relay the channel upgrade cancellation (ChannelUpgradeCancel)
ChanUpgradeCancel(channel::TxChanUpgradeCancelCmd),

/// Relay the channel upgrade timeout (ChannelUpgradeTimeout)
ChanUpgradeTimeout(channel::TxChanUpgradeTimeoutCmd),

/// Send a fungible token transfer test transaction (ICS20 MsgTransfer)
FtTransfer(transfer::TxIcs20MsgTransferCmd),

Expand Down
130 changes: 130 additions & 0 deletions crates/relayer-cli/src/commands/tx/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,136 @@ impl Runnable for TxChanUpgradeCancelCmd {
}
}

/// Relay channel upgrade timeout when counterparty has not flushed packets before upgrade timeout (ChannelUpgradeTimeout)
///
/// Build and send a `ChannelUpgradeTimeout` message to timeout
/// the channel upgrade handshake given that the counterparty has not flushed packets before upgrade timeout.
#[derive(Clone, Command, Debug, Parser, PartialEq, Eq)]
pub struct TxChanUpgradeTimeoutCmd {
#[clap(
long = "dst-chain",
required = true,
value_name = "DST_CHAIN_ID",
help_heading = "REQUIRED",
help = "Identifier of the destination chain"
)]
dst_chain_id: ChainId,

#[clap(
long = "src-chain",
required = true,
value_name = "SRC_CHAIN_ID",
help_heading = "REQUIRED",
help = "Identifier of the source chain"
)]
src_chain_id: ChainId,

#[clap(
long = "dst-connection",
visible_alias = "dst-conn",
required = true,
value_name = "DST_CONNECTION_ID",
help_heading = "REQUIRED",
help = "Identifier of the destination connection"
)]
dst_conn_id: ConnectionId,

#[clap(
long = "dst-port",
required = true,
value_name = "DST_PORT_ID",
help_heading = "REQUIRED",
help = "Identifier of the destination port"
)]
dst_port_id: PortId,

#[clap(
long = "src-port",
required = true,
value_name = "SRC_PORT_ID",
help_heading = "REQUIRED",
help = "Identifier of the source port"
)]
src_port_id: PortId,

#[clap(
long = "src-channel",
visible_alias = "src-chan",
required = true,
value_name = "SRC_CHANNEL_ID",
help_heading = "REQUIRED",
help = "Identifier of the source channel (required)"
)]
src_chan_id: ChannelId,

#[clap(
long = "dst-channel",
visible_alias = "dst-chan",
required = true,
help_heading = "REQUIRED",
value_name = "DST_CHANNEL_ID",
help = "Identifier of the destination channel (optional)"
)]
dst_chan_id: Option<ChannelId>,
}

impl Runnable for TxChanUpgradeTimeoutCmd {
fn run(&self) {
let config = app_config();

let chains = match ChainHandlePair::spawn(&config, &self.src_chain_id, &self.dst_chain_id) {
Ok(chains) => chains,
Err(e) => Output::error(format!("{}", e)).exit(),
};

// Retrieve the connection
let dst_connection = match chains.dst.query_connection(
QueryConnectionRequest {
connection_id: self.dst_conn_id.clone(),
height: QueryHeight::Latest,
},
IncludeProof::No,
) {
Ok((connection, _)) => connection,
Err(e) => Output::error(format!("{}", e)).exit(),
};

// Fetch the Channel that will facilitate the communication between the channel ends
// being upgraded. This channel is assumed to already exist on the destination chain.
let channel = Channel {
connection_delay: Default::default(),
ordering: Ordering::default(),
a_side: ChannelSide::new(
chains.src,
ClientId::default(),
ConnectionId::default(),
self.src_port_id.clone(),
Some(self.src_chan_id.clone()),
None,
),
b_side: ChannelSide::new(
chains.dst,
dst_connection.client_id().clone(),
self.dst_conn_id.clone(),
self.dst_port_id.clone(),
self.dst_chan_id.clone(),
None,
),
};

info!("message ChanUpgradeTimeout: {}", channel);

let res: Result<IbcEvent, Error> = channel
.build_chan_upgrade_timeout_and_send()
.map_err(Error::channel);

match res {
Ok(receipt) => Output::success(receipt).exit(),
Err(e) => Output::error(e).exit(),
}
}
}

#[cfg(test)]
mod tests {
use abscissa_core::clap::Parser;
Expand Down
117 changes: 117 additions & 0 deletions crates/relayer-types/src/core/ics04_channel/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ use crate::core::ics04_channel::channel::Ordering;
use crate::core::ics04_channel::error::Error;
use crate::core::ics04_channel::packet::Packet;
use crate::core::ics04_channel::packet::Sequence;
use crate::core::ics04_channel::timeout::Timeout;
use crate::core::ics04_channel::version::Version;
use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId};
use crate::events::{Error as EventError, IbcEvent, IbcEventType};
use crate::timestamp::Timestamp;
use crate::utils::pretty::PrettySlice;

/// Channel event attribute keys
Expand Down Expand Up @@ -145,6 +147,7 @@ pub struct UpgradeAttributes {
pub upgrade_version: Version,
pub upgrade_sequence: Sequence,
pub upgrade_ordering: Ordering,
pub upgrade_timeout: Option<Timeout>,
}

impl UpgradeAttributes {
Expand Down Expand Up @@ -609,6 +612,7 @@ impl From<UpgradeInit> for UpgradeAttributes {
upgrade_version: ev.upgrade_version,
upgrade_sequence: ev.upgrade_sequence,
upgrade_ordering: ev.upgrade_ordering,
upgrade_timeout: None,
}
}
}
Expand Down Expand Up @@ -711,6 +715,7 @@ impl From<UpgradeTry> for UpgradeAttributes {
upgrade_version: ev.upgrade_version,
upgrade_sequence: ev.upgrade_sequence,
upgrade_ordering: ev.upgrade_ordering,
upgrade_timeout: None,
}
}
}
Expand Down Expand Up @@ -813,6 +818,7 @@ impl From<UpgradeAck> for UpgradeAttributes {
upgrade_version: ev.upgrade_version,
upgrade_sequence: ev.upgrade_sequence,
upgrade_ordering: ev.upgrade_ordering,
upgrade_timeout: None,
}
}
}
Expand Down Expand Up @@ -915,6 +921,7 @@ impl From<UpgradeConfirm> for UpgradeAttributes {
upgrade_version: ev.upgrade_version,
upgrade_sequence: ev.upgrade_sequence,
upgrade_ordering: ev.upgrade_ordering,
upgrade_timeout: None,
}
}
}
Expand Down Expand Up @@ -1017,6 +1024,7 @@ impl From<UpgradeOpen> for UpgradeAttributes {
upgrade_version: ev.upgrade_version,
upgrade_sequence: ev.upgrade_sequence,
upgrade_ordering: ev.upgrade_ordering,
upgrade_timeout: None,
}
}
}
Expand Down Expand Up @@ -1119,6 +1127,7 @@ impl From<UpgradeCancel> for UpgradeAttributes {
upgrade_version: ev.upgrade_version,
upgrade_sequence: ev.upgrade_sequence,
upgrade_ordering: ev.upgrade_ordering,
upgrade_timeout: None,
}
}
}
Expand Down Expand Up @@ -1180,6 +1189,114 @@ impl EventType for UpgradeCancel {
}
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct UpgradeTimeout {
pub port_id: PortId,
pub channel_id: ChannelId,
pub counterparty_port_id: PortId,
pub counterparty_channel_id: Option<ChannelId>,
pub upgrade_connection_hops: Vec<ConnectionId>,
pub upgrade_version: Version,
pub upgrade_sequence: Sequence,
pub upgrade_ordering: Ordering,
pub upgrade_timeout: Timeout,
}

impl Display for UpgradeTimeout {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
if let Some(counterparty_channel_id) = &self.counterparty_channel_id {
write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: {counterparty_channel_id}, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?;
} else {
write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: None, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?;
}
for hop in self.upgrade_connection_hops.iter() {
write!(f, " {} ", hop)?;
}
write!(
f,
"], upgrade_version: {}, upgrade_sequence: {}, upgrade_ordering: {}, upgrade_timeout: {} }}",
self.upgrade_version, self.upgrade_sequence, self.upgrade_ordering, self.upgrade_timeout,
)
}
}

impl From<UpgradeTimeout> for UpgradeAttributes {
fn from(ev: UpgradeTimeout) -> Self {
Self {
port_id: ev.port_id,
channel_id: ev.channel_id,
counterparty_port_id: ev.counterparty_port_id,
counterparty_channel_id: ev.counterparty_channel_id,
upgrade_connection_hops: ev.upgrade_connection_hops,
upgrade_version: ev.upgrade_version,
upgrade_sequence: ev.upgrade_sequence,
upgrade_ordering: ev.upgrade_ordering,
upgrade_timeout: Some(ev.upgrade_timeout),
}
}
}

impl From<UpgradeTimeout> for abci::Event {
fn from(value: UpgradeTimeout) -> Self {
let kind = UpgradeTimeout::event_type().as_str().to_owned();
Self {
kind,
attributes: UpgradeAttributes::from(value).into(),
}
}
}

impl UpgradeTimeout {
pub fn channel_id(&self) -> &ChannelId {
&self.channel_id
}

pub fn port_id(&self) -> &PortId {
&self.port_id
}

pub fn counterparty_port_id(&self) -> &PortId {
&self.counterparty_port_id
}

pub fn counterparty_channel_id(&self) -> Option<&ChannelId> {
self.counterparty_channel_id.as_ref()
}
}

impl TryFrom<UpgradeAttributes> for UpgradeTimeout {
type Error = EventError;

fn try_from(attrs: UpgradeAttributes) -> Result<Self, Self::Error> {
Ok(Self {
port_id: attrs.port_id,
channel_id: attrs.channel_id,
counterparty_port_id: attrs.counterparty_port_id,
counterparty_channel_id: attrs.counterparty_channel_id,
upgrade_connection_hops: attrs.upgrade_connection_hops,
upgrade_version: attrs.upgrade_version,
upgrade_sequence: attrs.upgrade_sequence,
upgrade_ordering: attrs.upgrade_ordering,
upgrade_timeout: attrs.upgrade_timeout.map_or_else(
|| Timeout::Timestamp(Timestamp::default()),
|timeout| timeout,
),
})
}
}

impl From<UpgradeTimeout> for IbcEvent {
fn from(v: UpgradeTimeout) -> Self {
IbcEvent::UpgradeTimeoutChannel(v)
}
}

impl EventType for UpgradeTimeout {
fn event_type() -> IbcEventType {
IbcEventType::UpgradeTimeoutChannel
}
}

macro_rules! impl_try_from_attribute_for_event {
($($event:ty),+) => {
$(impl TryFrom<Attributes> for $event {
Expand Down
1 change: 1 addition & 0 deletions crates/relayer-types/src/core/ics04_channel/msgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub mod chan_upgrade_cancel;
pub mod chan_upgrade_confirm;
pub mod chan_upgrade_init;
pub mod chan_upgrade_open;
pub mod chan_upgrade_timeout;
pub mod chan_upgrade_try;

// Packet specific messages.
Expand Down
Loading

0 comments on commit ee971f3

Please sign in to comment.