From e7dbcc82ae4003af99f32cd3db066135c003a470 Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Mon, 10 May 2021 11:06:01 +0200 Subject: [PATCH 01/52] update --- modules/src/ics04_channel/events.rs | 7 + relayer/src/chain/counterparty.rs | 29 +++ relayer/src/channel.rs | 2 +- relayer/src/supervisor.rs | 370 +++++++++++++++++++++++++++- 4 files changed, 405 insertions(+), 3 deletions(-) diff --git a/modules/src/ics04_channel/events.rs b/modules/src/ics04_channel/events.rs index 4d424fd2c7..cd7a8cdf43 100644 --- a/modules/src/ics04_channel/events.rs +++ b/modules/src/ics04_channel/events.rs @@ -232,6 +232,9 @@ impl OpenTry { pub fn channel_id(&self) -> &Option { &self.0.channel_id } + pub fn port_id(&self) -> &PortId { + &self.0.port_id + } pub fn height(&self) -> Height { self.0.height } @@ -285,6 +288,10 @@ impl OpenAck { pub fn set_height(&mut self, height: Height) { self.0.height = height; } + + pub fn counterparty_channel_id(&self) -> &Option { + &self.0.counterparty_channel_id + } } impl From for OpenAck { diff --git a/relayer/src/chain/counterparty.rs b/relayer/src/chain/counterparty.rs index c1ed1e8dd4..ed3035dd1c 100644 --- a/relayer/src/chain/counterparty.rs +++ b/relayer/src/chain/counterparty.rs @@ -96,3 +96,32 @@ pub fn get_counterparty_chain( channel_connection_client(src_chain, src_port_id, src_channel_id) .map(|c| c.client.client_state.chain_id()) } + +pub fn get_counterparty_chain_for_channel( + chain: &dyn ChainHandle, + channel: IdentifiedChannelEnd, +) -> Result { + let connection_id = channel + .channel_end + .connection_hops() + .first() + .ok_or_else(|| Error::MissingConnectionHops(channel.channel_id.clone(), chain.id()))?; + + let connection_end = chain + .query_connection(&connection_id, Height::zero()) + .map_err(|e| Error::QueryFailed(format!("{}", e)))?; + let client_id = connection_end.client_id(); + let client_state = chain + .query_client_state(&client_id, Height::zero()) + .map_err(|e| Error::QueryFailed(format!("{}", e)))?; + + // trace!( + // chain_id=%chain.id(), port_id=%port_id, channel_id=%channel_id, + // "counterparty chain: {}", client_state.chain_id() + // ); + //let counterparty_chain_id = client_state.chain_id(); + // let counterparty_chain = self.registry + // .get_or_spawn(&client_state.chain_id())?; + + Ok(client_state.chain_id()) +} diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index abb0f3a505..611dd86b83 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -45,7 +45,7 @@ pub struct ChannelSide { client_id: ClientId, connection_id: ConnectionId, port_id: PortId, - channel_id: ChannelId, + pub channel_id: ChannelId, } impl ChannelSide { diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index f7b5db3049..6707964c69 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -18,7 +18,7 @@ use ibc::{ }, ics04_channel::{ channel::IdentifiedChannelEnd, - events::{Attributes, CloseInit, SendPacket, TimeoutPacket, WriteAcknowledgement}, + events::{Attributes, CloseInit, SendPacket, TimeoutPacket, WriteAcknowledgement,OpenTry}, }, ics24_host::identifier::{ChainId, ChannelId, ClientId, PortId}, Height, @@ -26,9 +26,14 @@ use ibc::{ use ibc_proto::ibc::core::channel::v1::QueryChannelsRequest; +use crate::channel::Channel as RelayChannel; +use crate::channel::ChannelSide; + use crate::{ chain::{ - counterparty::{channel_connection_client, get_counterparty_chain}, + counterparty::{ + channel_connection_client, get_counterparty_chain, get_counterparty_chain_for_channel, + }, handle::ChainHandle, }, config::Config, @@ -164,6 +169,12 @@ impl Supervisor { } } } + IbcEvent::OpenTryChannel(ref open_try) => { + if let Ok(object) = Object::for_open_try_channel(open_try, src_chain) { + collected.per_object.entry(object).or_default().push(event); + } + } + IbcEvent::OpenAckChannel(ref open_ack) => { // Create client worker here as channel end must be opened if let Ok(object) = @@ -266,6 +277,28 @@ impl Supervisor { chain.id() ); + //start spawning channel worker + let counterparty_chain_id = + get_counterparty_chain_for_channel(chain.as_ref(), channel.clone()).unwrap(); + + let counterparty_chain = self.registry.get_or_spawn(&counterparty_chain_id)?; + + let channel_object = Object::Channel(Channel { + dst_chain_id: counterparty_chain_id, + src_chain_id: chain.id(), + src_channel_id: channel.channel_id.clone(), + src_port_id: channel.port_id.clone(), + // connection_id: connection_id.clone(), + }); + + debug!( + "create workers: creating a worker for object {:?}", + channel_object + ); + + self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); + //end the spawning channel worker + let client_res = channel_connection_client(chain.as_ref(), &channel.port_id, &channel.channel_id); @@ -481,6 +514,7 @@ impl Worker { let result = match object { Object::UnidirectionalChannelPath(path) => self.run_uni_chan_path(path), Object::Client(client) => self.run_client(client), + Object::Channel(channel) => self.run_channel(channel), }; if let Err(e) = result { @@ -611,6 +645,303 @@ impl Worker { } } } + + /// Run the event loop for events associated with a [`Channel`]. + fn run_channel(self, channel: Channel) -> Result<(), BoxError> { + let done = '🥳'; + + let a_chain = self.chains.a.clone(); + let b_chain = self.chains.b.clone(); + + let a_channel = self.chains.a.query_channel( + &channel.src_port_id, + &channel.src_channel_id, + Height::zero(), + )?; + + let connection_id = a_channel.connection_hops().first().ok_or_else(|| { + Error::MissingConnectionHops(channel.src_channel_id.clone(), a_chain.id()) + })?; + + let connection = self + .chains + .a + .query_connection(&connection_id, Height::zero())?; + + let mut state = &ibc::ics04_channel::channel::State::Uninitialized; + + let mut b_channel = Default::default(); + + let counterparty_channel_id = if a_channel.remote.channel_id.is_none() { + Default::default() + } else { + b_channel = self.chains.b.query_channel( + &a_channel.remote.port_id.clone(), + &a_channel.remote.channel_id.clone().unwrap(), + Height::zero(), + )?; + state = &b_channel.state; + a_channel.remote.channel_id.clone().unwrap() + }; + + let mut handshake_channel = RelayChannel { + ordering: a_channel.ordering().clone(), + a_side: ChannelSide::new( + a_chain.clone(), + connection.client_id().clone(), + connection_id.clone(), + channel.src_port_id.clone(), + channel.src_channel_id.clone(), + ), + b_side: ChannelSide::new( + b_chain.clone(), + connection.counterparty().client_id().clone(), + connection.counterparty().connection_id().unwrap().clone(), + a_channel.remote.port_id.clone(), + counterparty_channel_id.clone(), + ), + connection_delay: connection.delay_period(), + version: Some(a_channel.version.clone()), + }; + + let mut stage = 0; //Nothing started + let mut found = false; + + debug!( + "\n [{}] initial handshake_channel is {:?} \n ", + channel.short_name(), + handshake_channel + ); + + if a_channel.state_matches(&ibc::ics04_channel::channel::State::Init) { + if a_channel.remote.channel_id.is_none() { + let req = QueryChannelsRequest { + pagination: ibc_proto::cosmos::base::query::pagination::all(), + }; + + let channels: Vec = b_chain.query_channels(req.clone())?; + for chan in channels.iter() { + if chan.channel_end.remote.channel_id.is_some() + && chan.channel_end.remote.channel_id.clone().unwrap() + == channel.src_channel_id.clone() + { + debug!( + "[{}] found a pair channel {} on chain {}", + channel.short_name(), + chan.channel_id, + handshake_channel.b_side.chain_id() + ); + found = true; + handshake_channel.b_side.channel_id = chan.channel_id.clone(); + + break; + } + } + stage = 1; // channel in Init + + if !found { + println!( + "\n [{}] sends build_chan_open_try_and_send \n on handshake_channel {:?} channel in state Init \n", + channel.short_name(), + handshake_channel + ); + + match handshake_channel.build_chan_open_try_and_send() { + Err(e) => { + debug!("Failed ChanTry {:?}: {:?}", handshake_channel.b_side, e); + } + Ok(event) => { + println!("{} {} => {:#?}\n", done, b_chain.id(), event); + } + } + } + } + } else { + if a_channel.state_matches(&ibc::ics04_channel::channel::State::TryOpen) { + stage = 2; //channel is in Try Open + + if a_channel.remote.channel_id.is_some() { + //Try chanOpenTry on b_chain + debug!("[{}] chain {} has channel {} in state TryOpen with counterparty {} in state {} \n", channel.short_name(), a_chain.id(), channel.src_channel_id.clone(), counterparty_channel_id.clone(), state); + + if !b_channel.state_matches(&ibc::ics04_channel::channel::State::Open) { + debug!( + "\n [{}] sends build_chan_open_ack_and_send \n on handshake_channel {:?}", + channel.short_name(),handshake_channel); + + match handshake_channel.build_chan_open_ack_and_send() { + Err(e) => { + debug!("Failed ChanAck {:?}: {:?}", handshake_channel.b_side, e); + } + Ok(event) => { + // handshake_channel.b_side.channel_id = extract_channel_id(&event)?.clone(); + println!("{} {} => {:#?}\n", done, b_chain.id(), event); + } + } + } //TODO else either counter party channel is more advanced or another channel closed the hanshake + } //TODO else error + } else { + match (a_channel.state().clone(), state) { + ( + ibc::ics04_channel::channel::State::Open, + ibc::ics04_channel::channel::State::TryOpen, + ) => { + stage = 3; // channel is Open + debug!( + "[{}] chain {} has channel {} in state Open counterparty TryOpen \n", + channel.short_name(), + a_chain.id(), + channel.src_channel_id.clone() + ); + + // Confirm to b_chain + debug!( + "[{}] sends build_chan_open_confirm_and_send \n on handshake_channel {:?}", + channel.short_name(), + handshake_channel + ); + + match handshake_channel.build_chan_open_confirm_and_send() { + Err(e) => { + debug!( + "Failed OpenConfirm {:?}: {:?}", + handshake_channel.b_side, e + ); + } + Ok(event) => { + println!("{} {} => {:#?}\n", done, b_chain.id(), event); + } + } + } + ( + ibc::ics04_channel::channel::State::Open, + ibc::ics04_channel::channel::State::Open, + ) => { + // stage = 3; //Channel is Open + println!( + "[{}]{} {} {} Channel handshake finished for {:#?}\n", + channel.short_name(), + done, + done, + done, + &channel.src_channel_id, + ); + return Ok(()); + } + _ => { + debug!( + "[{}] \n Error Unimplemented handshake case \n", + channel.short_name() + ) + } + } + } + }; + + loop { + if let Ok(WorkerCmd::IbcEvents { batch }) = self.rx.try_recv() { + // Ok(cmd) + // match cmd { + // WorkerCmd::IbcEvents { batch } => { + for event in batch.events { + match event { + IbcEvent::OpenInitChannel(_open_init) => {} + + IbcEvent::OpenTryChannel(_open_try) => {} + + IbcEvent::OpenAckChannel(open_ack) => { + debug!(" \n [{}] {} channel handshake OpenAck from {:?} {} channel from event OpenAck \n", + channel.short_name(), + handshake_channel.a_side.channel_id(), + handshake_channel.a_side.chain_id(), + open_ack.channel_id().clone().unwrap() + ); + + if stage == 1 && !found { + debug!( + "[{}] writting b_side before open_confirm {} ", + channel.short_name(), + handshake_channel.b_side.channel_id + ); + + handshake_channel.b_side.channel_id = + open_ack.counterparty_channel_id().clone().unwrap(); + + debug!( + "[{}] writting b_side after open_confirm {} ", + channel.short_name(), + handshake_channel.b_side.channel_id + ); + } + + debug!( + "[{}] hanshake_channel b_side channel id is {}", + channel.short_name(), + handshake_channel.b_side.channel_id() + ); + + let event = handshake_channel.build_chan_open_confirm_and_send()?; + println!("{} {} => {:#?}\n", done, b_chain.id(), event); + } + IbcEvent::OpenConfirmChannel(open_confirm) => { + debug!("[{}] {} channel handshake OpenConfirm [{}] channel from event OpenConfirm {} ", + channel.short_name(), + handshake_channel.a_side.channel_id(), + handshake_channel.a_side.chain_id(), + open_confirm.channel_id().clone().unwrap() + ); + + println!( + "{} {} {} Channel handshake finished for {:#?}\n", + done, done, done, &channel.src_channel_id, + ); + + return Ok(()); + } + IbcEvent::CloseInitChannel(_) => {} + IbcEvent::CloseConfirmChannel(_) => {} + _ => {} + } + } + // } + + // WorkerCmd::NewBlock { + // height: _, + // new_block: _, + // } => { + // debug!("\n new block \n "); + // } //link.a_to_b.clear_packets(height)?, + + // _ => {} + // } + } + } + } +} + +//Channel +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Channel { + /// Destination chain identifier. + pub dst_chain_id: ChainId, + + /// Source chain identifier. + pub src_chain_id: ChainId, + + /// Source channel identiier. + pub src_channel_id: ChannelId, + + /// Source port identiier. + pub src_port_id: PortId, +} + +impl Channel { + pub fn short_name(&self) -> String { + format!( + "{}/{}:{} -> {}", + self.src_channel_id, self.src_port_id, self.src_chain_id, self.dst_chain_id, + ) + } } /// Client @@ -668,6 +999,7 @@ impl UnidirectionalChannelPath { /// for processing. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum Object { + Channel(Channel), /// See [`Client`]. Client(Client), /// See [`UnidirectionalChannelPath`]. @@ -682,10 +1014,17 @@ impl Object { match self { Object::UnidirectionalChannelPath(p) => p.src_chain_id == *src_chain_id, Object::Client(_) => false, + Object::Channel(_) => false, } } } +impl From for Object { + fn from(c: Channel) -> Self { + Self::Channel(c) + } +} + impl From for Object { fn from(c: Client) -> Self { Self::Client(c) @@ -701,6 +1040,7 @@ impl From for Object { impl Object { pub fn src_chain_id(&self) -> &ChainId { match self { + Self::Channel(ref channel) => &channel.src_chain_id, Self::Client(ref client) => &client.src_chain_id, Self::UnidirectionalChannelPath(ref path) => &path.src_chain_id, } @@ -708,6 +1048,7 @@ impl Object { pub fn dst_chain_id(&self) -> &ChainId { match self { + Self::Channel(ref channel) => &channel.dst_chain_id, Self::Client(ref client) => &client.dst_chain_id, Self::UnidirectionalChannelPath(ref path) => &path.dst_chain_id, } @@ -715,6 +1056,7 @@ impl Object { pub fn short_name(&self) -> String { match self { + Self::Channel(ref channel) => channel.short_name(), Self::Client(ref client) => client.short_name(), Self::UnidirectionalChannelPath(ref path) => path.short_name(), } @@ -745,6 +1087,30 @@ impl Object { .into()) } + /// Build the object associated with the given [`OpenTry`] event. + pub fn for_open_try_channel( + e: &OpenTry, + src_chain: &dyn ChainHandle, + ) -> Result { + let dst_chain_id = + get_counterparty_chain(src_chain, &e.channel_id().clone().unwrap(), &e.port_id())?; + + debug!( + " in for_open_try_channel dst_chain_id {} src_chain_id {} with event {:?} ", + dst_chain_id, + src_chain.id(), + e + ); + + Ok(Channel { + dst_chain_id, + src_chain_id: src_chain.id(), + src_channel_id: e.channel_id().clone().unwrap(), + src_port_id: e.port_id().clone(), + } + .into()) + } + /// Build the client object associated with the given channel event attributes. pub fn for_chan_open_events( e: &Attributes, From 9f9e56309b3952d536503095653579d9f4b3b3a7 Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Mon, 10 May 2021 15:49:33 +0200 Subject: [PATCH 02/52] add behavior for chan not open --- modules/src/ics04_channel/events.rs | 15 ++ relayer/src/chain/counterparty.rs | 7 +- relayer/src/supervisor.rs | 394 ++++++++++++++++++++-------- 3 files changed, 308 insertions(+), 108 deletions(-) diff --git a/modules/src/ics04_channel/events.rs b/modules/src/ics04_channel/events.rs index cd7a8cdf43..b6e98cb0fe 100644 --- a/modules/src/ics04_channel/events.rs +++ b/modules/src/ics04_channel/events.rs @@ -185,9 +185,15 @@ impl Default for Attributes { pub struct OpenInit(Attributes); impl OpenInit { + pub fn attributes(&self) -> &Attributes { + &self.0 + } pub fn channel_id(&self) -> &Option { &self.0.channel_id } + pub fn port_id(&self) -> &PortId { + &self.0.port_id + } pub fn height(&self) -> Height { self.0.height } @@ -229,6 +235,9 @@ impl From for IbcEvent { pub struct OpenTry(Attributes); impl OpenTry { + pub fn attributes(&self) -> &Attributes { + &self.0 + } pub fn channel_id(&self) -> &Option { &self.0.channel_id } @@ -282,6 +291,9 @@ impl OpenAck { pub fn channel_id(&self) -> &Option { &self.0.channel_id } + pub fn port_id(&self) -> &PortId { + &self.0.port_id + } pub fn height(&self) -> Height { self.0.height } @@ -333,6 +345,9 @@ impl OpenConfirm { pub fn channel_id(&self) -> &Option { &self.0.channel_id } + pub fn port_id(&self) -> &PortId { + &self.0.port_id + } pub fn height(&self) -> Height { self.0.height } diff --git a/relayer/src/chain/counterparty.rs b/relayer/src/chain/counterparty.rs index ed3035dd1c..ce44ea287d 100644 --- a/relayer/src/chain/counterparty.rs +++ b/relayer/src/chain/counterparty.rs @@ -50,9 +50,10 @@ pub fn channel_connection_client( .query_channel(port_id, channel_id, Height::zero()) .map_err(|e| Error::QueryFailed(format!("{}", e)))?; - if !channel_end.is_open() { - return Err(Error::ChannelNotOpen(channel_id.clone(), chain.id())); - } + //change to Unintialized + // if !channel_end.is_open() { + // return Err(Error::ChannelNotOpen(channel_id.clone(), chain.id())); + // } let connection_id = channel_end .connection_hops() diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index 6707964c69..1538a22c3c 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -18,7 +18,10 @@ use ibc::{ }, ics04_channel::{ channel::IdentifiedChannelEnd, - events::{Attributes, CloseInit, SendPacket, TimeoutPacket, WriteAcknowledgement,OpenTry}, + events::{ + Attributes, CloseInit, SendPacket, + TimeoutPacket, WriteAcknowledgement, + }, }, ics24_host::identifier::{ChainId, ChannelId, ClientId, PortId}, Height, @@ -169,9 +172,24 @@ impl Supervisor { } } } + + IbcEvent::OpenInitChannel(ref open_init) => { + debug!("\n !!!! Init in \n "); + if let Ok(object) = + Object::for_open_init_channel(open_init.attributes(), src_chain) + { + collected.per_object.entry(object).or_default().push(event); + } else { + debug!("\n !!!! ups object malformed Init in \n "); + } + } + IbcEvent::OpenTryChannel(ref open_try) => { - if let Ok(object) = Object::for_open_try_channel(open_try, src_chain) { + debug!("\n !!!! OpenTry in \n "); + if let Ok(object) = Object::for_open_try_channel(open_try.attributes(), src_chain) { collected.per_object.entry(object).or_default().push(event); + } else { + debug!("\n !!!! ups object malformed Try in \n "); } } @@ -180,7 +198,17 @@ impl Supervisor { if let Ok(object) = Object::for_chan_open_events(open_ack.attributes(), src_chain) { - collected.per_object.entry(object).or_default().push(event); + collected + .per_object + .entry(object) + .or_default() + .push(event.clone()); + } + + if let Ok(object2) = Object::for_open_ack_channel(open_ack.attributes(), src_chain) { + collected.per_object.entry(object2).or_default().push(event); + } else { + debug!("\n !!!! ups object malformed Ack in \n "); } } IbcEvent::OpenConfirmChannel(ref open_confirm) => { @@ -188,7 +216,18 @@ impl Supervisor { if let Ok(object) = Object::for_chan_open_events(open_confirm.attributes(), src_chain) { - collected.per_object.entry(object).or_default().push(event); + collected + .per_object + .entry(object) + .or_default() + .push(event.clone()); + } + if let Ok(object2) = Object::for_open_confirm_channel(open_confirm.attributes(), src_chain) { + collected + .per_object + .entry(object2) + .or_default() + .push(event.clone()); } } IbcEvent::SendPacket(ref packet) => { @@ -277,33 +316,38 @@ impl Supervisor { chain.id() ); - //start spawning channel worker - let counterparty_chain_id = - get_counterparty_chain_for_channel(chain.as_ref(), channel.clone()).unwrap(); + //channel object + // self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); - let counterparty_chain = self.registry.get_or_spawn(&counterparty_chain_id)?; + // } end if channel not open - let channel_object = Object::Channel(Channel { - dst_chain_id: counterparty_chain_id, - src_chain_id: chain.id(), - src_channel_id: channel.channel_id.clone(), - src_port_id: channel.port_id.clone(), - // connection_id: connection_id.clone(), - }); + ////start spawning channel worker + // let counterparty_chain_id = + // get_counterparty_chain_for_channel(chain.as_ref(), channel.clone()).unwrap(); - debug!( - "create workers: creating a worker for object {:?}", - channel_object - ); + // let counterparty_chain = self.registry.get_or_spawn(&counterparty_chain_id)?; + + // let channel_object = Object::Channel(Channel { + // dst_chain_id: counterparty_chain_id, + // src_chain_id: chain.id(), + // src_channel_id: channel.channel_id.clone(), + // src_port_id: channel.port_id.clone(), + // // connection_id: connection_id.clone(), + // }); - self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); - //end the spawning channel worker + // debug!( + // "create workers: creating a worker for object {:?}", + // channel_object + // ); + + // self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); + // //end the spawning channel worker let client_res = channel_connection_client(chain.as_ref(), &channel.port_id, &channel.channel_id); - let client = match client_res { - Ok(conn_client) => conn_client.client, + let (client, channel) = match client_res { + Ok(conn_client) => (conn_client.client, conn_client.channel), Err(Error::ConnectionNotOpen(..)) | Err(Error::ChannelNotOpen(..)) => { // These errors are silent. // Simply ignore the channel and return without spawning the workers. @@ -337,30 +381,60 @@ impl Supervisor { return Ok(()); } - let counterparty_chain = self - .registry - .get_or_spawn(&client.client_state.chain_id())?; - - // create the client object and spawn worker - let client_object = Object::Client(Client { - dst_client_id: client.client_id.clone(), - dst_chain_id: chain.id(), - src_chain_id: client.client_state.chain_id(), - }); - - self.worker_for_object(client_object, chain.clone(), counterparty_chain.clone()); + if channel.channel_end.is_open() { + //if channel open { + let counterparty_chain = self + .registry + .get_or_spawn(&client.client_state.chain_id())?; + + // create the client object and spawn worker + let client_object = Object::Client(Client { + dst_client_id: client.client_id.clone(), + dst_chain_id: chain.id(), + src_chain_id: client.client_state.chain_id(), + }); + + //if channel open + self.worker_for_object(client_object, chain.clone(), counterparty_chain.clone()); + + // TODO: Only start the Uni worker if there are outstanding packets or ACKs. + // https://github.com/informalsystems/ibc-rs/issues/901 + // create the path object and spawn worker + let path_object = Object::UnidirectionalChannelPath(UnidirectionalChannelPath { + dst_chain_id: counterparty_chain.id(), + src_chain_id: chain.id(), + src_channel_id: channel.channel_id.clone(), + src_port_id: channel.port_id, + }); + + self.worker_for_object(path_object, chain.clone(), counterparty_chain.clone()); + //channel object + // self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); + } + // end if channel not open + else { + // //start spawning channel worker + let counterparty_chain_id = + get_counterparty_chain_for_channel(chain.as_ref(), channel.clone()).unwrap(); + + let counterparty_chain = self.registry.get_or_spawn(&counterparty_chain_id)?; + + let channel_object = Object::Channel(Channel { + dst_chain_id: counterparty_chain_id, + src_chain_id: chain.id(), + src_channel_id: channel.channel_id.clone(), + src_port_id: channel.port_id.clone(), + // connection_id: connection_id.clone(), + }); - // TODO: Only start the Uni worker if there are outstanding packets or ACKs. - // https://github.com/informalsystems/ibc-rs/issues/901 - // create the path object and spawn worker - let path_object = Object::UnidirectionalChannelPath(UnidirectionalChannelPath { - dst_chain_id: counterparty_chain.id(), - src_chain_id: chain.id(), - src_channel_id: channel.channel_id.clone(), - src_port_id: channel.port_id, - }); + debug!( + "create workers: creating a worker for object {:?}", + channel_object + ); - self.worker_for_object(path_object, chain.clone(), counterparty_chain.clone()); + self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); + //end the spawning channel worker + } Ok(()) } @@ -656,7 +730,7 @@ impl Worker { let a_channel = self.chains.a.query_channel( &channel.src_port_id, &channel.src_channel_id, - Height::zero(), + Height::zero(), //height - 1 de la newBlock )?; let connection_id = a_channel.connection_hops().first().ok_or_else(|| { @@ -713,6 +787,11 @@ impl Worker { handshake_channel ); + //c0 ibc0 Init ? // -> OpenTry ibc1 -> create c1 ibc1 -->> + + //chan_open_init ibc1 => c1 + //c0 ibc0 OpenTry ? <- chan_open_try c1 ibc-1 dest c0 ibc 0 --> new channel + if a_channel.state_matches(&ibc::ics04_channel::channel::State::Init) { if a_channel.remote.channel_id.is_none() { let req = QueryChannelsRequest { @@ -839,81 +918,95 @@ impl Worker { }; loop { - if let Ok(WorkerCmd::IbcEvents { batch }) = self.rx.try_recv() { + if let Ok(cmd) = self.rx.try_recv() { + //Ok(WorkerCmd::IbcEvents { batch }) // Ok(cmd) - // match cmd { - // WorkerCmd::IbcEvents { batch } => { - for event in batch.events { - match event { - IbcEvent::OpenInitChannel(_open_init) => {} - - IbcEvent::OpenTryChannel(_open_try) => {} - - IbcEvent::OpenAckChannel(open_ack) => { - debug!(" \n [{}] {} channel handshake OpenAck from {:?} {} channel from event OpenAck \n", + match cmd { + WorkerCmd::IbcEvents { batch } => { + for event in batch.events { + match event { + IbcEvent::OpenInitChannel(open_init) => { + debug!( + "\n [{}] Calling Open Init from the loop {:?}\n ", + channel.short_name(), + open_init + ); + } + + IbcEvent::OpenTryChannel(open_try) => { + debug!( + "\n [{}] Calling Open Try from the loop {:?} \n ", + channel.short_name(), + open_try + ); + } + + IbcEvent::OpenAckChannel(open_ack) => { + debug!(" \n [{}] {} channel handshake OpenAck from {:?} {} channel from event OpenAck \n", channel.short_name(), handshake_channel.a_side.channel_id(), handshake_channel.a_side.chain_id(), open_ack.channel_id().clone().unwrap() ); - if stage == 1 && !found { - debug!( - "[{}] writting b_side before open_confirm {} ", - channel.short_name(), - handshake_channel.b_side.channel_id - ); - - handshake_channel.b_side.channel_id = - open_ack.counterparty_channel_id().clone().unwrap(); - - debug!( - "[{}] writting b_side after open_confirm {} ", - channel.short_name(), - handshake_channel.b_side.channel_id - ); - } - - debug!( - "[{}] hanshake_channel b_side channel id is {}", - channel.short_name(), - handshake_channel.b_side.channel_id() - ); - - let event = handshake_channel.build_chan_open_confirm_and_send()?; - println!("{} {} => {:#?}\n", done, b_chain.id(), event); - } - IbcEvent::OpenConfirmChannel(open_confirm) => { - debug!("[{}] {} channel handshake OpenConfirm [{}] channel from event OpenConfirm {} ", + if stage == 1 && !found { + debug!( + "[{}] writting b_side before open_confirm {} ", + channel.short_name(), + handshake_channel.b_side.channel_id + ); + + handshake_channel.b_side.channel_id = + open_ack.counterparty_channel_id().clone().unwrap(); + + debug!( + "[{}] writting b_side after open_confirm {} ", + channel.short_name(), + handshake_channel.b_side.channel_id + ); + } + + debug!( + "[{}] hanshake_channel b_side channel id is {}", + channel.short_name(), + handshake_channel.b_side.channel_id() + ); + + let event = + handshake_channel.build_chan_open_confirm_and_send()?; + println!("{} {} => {:#?}\n", done, b_chain.id(), event); + } + IbcEvent::OpenConfirmChannel(open_confirm) => { + debug!("[{}] {} channel handshake OpenConfirm [{}] channel from event OpenConfirm {} ", channel.short_name(), handshake_channel.a_side.channel_id(), handshake_channel.a_side.chain_id(), open_confirm.channel_id().clone().unwrap() ); - println!( - "{} {} {} Channel handshake finished for {:#?}\n", - done, done, done, &channel.src_channel_id, - ); + println!( + "{} {} {} Channel handshake finished for {:#?}\n", + done, done, done, &channel.src_channel_id, + ); - return Ok(()); + return Ok(()); + } + IbcEvent::CloseInitChannel(_) => {} + IbcEvent::CloseConfirmChannel(_) => {} + _ => {} + } } - IbcEvent::CloseInitChannel(_) => {} - IbcEvent::CloseConfirmChannel(_) => {} - _ => {} } - } - // } - // WorkerCmd::NewBlock { - // height: _, - // new_block: _, - // } => { - // debug!("\n new block \n "); - // } //link.a_to_b.clear_packets(height)?, + WorkerCmd::NewBlock { + height: _, + new_block: _, + } => { + debug!("\n new block \n "); + } //link.a_to_b.clear_packets(height)?, - // _ => {} - // } + // _ => {} + } } } } @@ -1087,16 +1180,106 @@ impl Object { .into()) } + /// Build the object associated with the given [`OpenInit`] event. + pub fn for_open_init_channel( + e: &Attributes, + src_chain: &dyn ChainHandle, + ) -> Result { + let channel_id = e + .channel_id() + .as_ref() + .ok_or_else(|| format!("channel_id missing in OpenInit event '{:?}'", e))?; + + let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id()); + + if dst_chain_id.is_err() { + debug!("\n err dest_chan_id in init\n "); + return Err(format!("dest chain missing in init").into()); + } + + debug!( + " in for_open_init_channel dst_chain_id {} src_chain_id {} with event {:?} ", + dst_chain_id.clone().unwrap(), + src_chain.id(), + e + ); + + Ok(Channel { + dst_chain_id: dst_chain_id.clone().unwrap(), + src_chain_id: src_chain.id(), + src_channel_id: channel_id.clone(), + src_port_id: e.port_id().clone(), + // connection_id: e.connection_id().clone(), + } + .into()) + } + /// Build the object associated with the given [`OpenTry`] event. pub fn for_open_try_channel( - e: &OpenTry, + e: &Attributes, + src_chain: &dyn ChainHandle, + ) -> Result { + let channel_id = e + .channel_id() + .as_ref() + .ok_or_else(|| format!("channel_id missing in OpenInit event '{:?}'", e))?; + + let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id()); + + if dst_chain_id.is_err() { + debug!("\n err dest_chan_id in try\n "); + return Err(format!("dest chain missing in OpenTry").into()); + } + + debug!( + " in for_open_try_channel dst_chain_id {} src_chain_id {} with event {:?} ", + dst_chain_id.clone().unwrap(), + src_chain.id(), + e + ); + + Ok(Channel { + dst_chain_id: dst_chain_id.clone().unwrap(), + src_chain_id: src_chain.id(), + src_channel_id: e.channel_id().clone().unwrap(), + src_port_id: e.port_id().clone(), + } + .into()) + } + + pub fn for_open_ack_channel( + e: &Attributes, src_chain: &dyn ChainHandle, ) -> Result { let dst_chain_id = get_counterparty_chain(src_chain, &e.channel_id().clone().unwrap(), &e.port_id())?; debug!( - " in for_open_try_channel dst_chain_id {} src_chain_id {} with event {:?} ", + " in for_open_ack_channel dst_chain_id {} src_chain_id {} with event {:?} ", + dst_chain_id, + src_chain.id(), + e + ); + + Ok(Channel { + dst_chain_id, + src_chain_id: src_chain.id(), + src_channel_id: e.channel_id().clone().unwrap(), + src_port_id: e.port_id().clone(), + //connection_id: e.connection_id().clone(), + } + .into()) + } + + pub fn for_open_confirm_channel( + e: &Attributes, + src_chain: &dyn ChainHandle, + ) -> Result { + let dst_chain_id = + get_counterparty_chain(src_chain, &e.channel_id().clone().unwrap(), &e.port_id())?; + + debug!( + " in for_open_confirm_channel dst_chain_id {} src_chain_id {} with event {:?} ", dst_chain_id, src_chain.id(), e @@ -1107,6 +1290,7 @@ impl Object { src_chain_id: src_chain.id(), src_channel_id: e.channel_id().clone().unwrap(), src_port_id: e.port_id().clone(), + //connection_id: e.connection_id().clone(), } .into()) } From 70c5d8b69c5d1fc9374df2654323f328061d942b Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Mon, 10 May 2021 15:52:35 +0200 Subject: [PATCH 03/52] allow dst channel id to be specified --- relayer-cli/src/commands/tx/channel.rs | 9 ++++++++- relayer/src/channel.rs | 8 +++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/relayer-cli/src/commands/tx/channel.rs b/relayer-cli/src/commands/tx/channel.rs index 7a3d60fe1d..8eef6d585b 100644 --- a/relayer-cli/src/commands/tx/channel.rs +++ b/relayer-cli/src/commands/tx/channel.rs @@ -120,6 +120,13 @@ pub struct TxRawChanOpenTryCmd { meta = "ID" )] src_chan_id: ChannelId, + + #[options( + help = "identifier of the destination channel (optional)", + short = "d", + meta = "ID" + )] + dst_chan_id: ChannelId, } impl Runnable for TxRawChanOpenTryCmd { @@ -144,7 +151,7 @@ impl Runnable for TxRawChanOpenTryCmd { dst_connection.client_id().clone(), self.dst_conn_id.clone(), self.dst_port_id.clone(), - ChannelId::default(), + self.dst_chan_id.clone(), ), version: None, } diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 611dd86b83..452b5c0040 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -505,10 +505,16 @@ impl Channel { )) })?; + let previous_channel_id = if src_channel.counterparty().channel_id.is_none() { + Some(self.b_side.channel_id.clone()) + } else { + src_channel.counterparty().channel_id.clone() + }; + // Build the domain type message let new_msg = MsgChannelOpenTry { port_id: self.dst_port_id().clone(), - previous_channel_id: src_channel.counterparty().channel_id.clone(), + previous_channel_id, counterparty_version: self.src_version()?, channel, proofs, From c5cffae7f560cd10df07e06bc2787e73170a84e9 Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Mon, 10 May 2021 17:47:30 +0200 Subject: [PATCH 04/52] intermiate. --- relayer/src/channel.rs | 2 +- relayer/src/supervisor.rs | 606 ++++++++++++++++++++++---------------- 2 files changed, 357 insertions(+), 251 deletions(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 452b5c0040..c4491b69e1 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -846,7 +846,7 @@ impl Channel { } } -fn extract_channel_id(event: &IbcEvent) -> Result<&ChannelId, ChannelError> { +pub fn extract_channel_id(event: &IbcEvent) -> Result<&ChannelId, ChannelError> { match event { IbcEvent::OpenInitChannel(ev) => ev.channel_id().as_ref(), IbcEvent::OpenTryChannel(ev) => ev.channel_id().as_ref(), diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index 1538a22c3c..9993c5e13e 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -18,12 +18,9 @@ use ibc::{ }, ics04_channel::{ channel::IdentifiedChannelEnd, - events::{ - Attributes, CloseInit, SendPacket, - TimeoutPacket, WriteAcknowledgement, - }, + events::{Attributes, CloseInit, SendPacket, TimeoutPacket, WriteAcknowledgement}, }, - ics24_host::identifier::{ChainId, ChannelId, ClientId, PortId}, + ics24_host::identifier::{ChainId, ChannelId, ClientId, PortId, ConnectionId}, Height, }; @@ -31,6 +28,7 @@ use ibc_proto::ibc::core::channel::v1::QueryChannelsRequest; use crate::channel::Channel as RelayChannel; use crate::channel::ChannelSide; +use crate::channel::extract_channel_id; use crate::{ chain::{ @@ -186,7 +184,9 @@ impl Supervisor { IbcEvent::OpenTryChannel(ref open_try) => { debug!("\n !!!! OpenTry in \n "); - if let Ok(object) = Object::for_open_try_channel(open_try.attributes(), src_chain) { + if let Ok(object) = + Object::for_open_try_channel(open_try.attributes(), src_chain) + { collected.per_object.entry(object).or_default().push(event); } else { debug!("\n !!!! ups object malformed Try in \n "); @@ -205,7 +205,9 @@ impl Supervisor { .push(event.clone()); } - if let Ok(object2) = Object::for_open_ack_channel(open_ack.attributes(), src_chain) { + if let Ok(object2) = + Object::for_open_ack_channel(open_ack.attributes(), src_chain) + { collected.per_object.entry(object2).or_default().push(event); } else { debug!("\n !!!! ups object malformed Ack in \n "); @@ -222,7 +224,9 @@ impl Supervisor { .or_default() .push(event.clone()); } - if let Ok(object2) = Object::for_open_confirm_channel(open_confirm.attributes(), src_chain) { + if let Ok(object2) = + Object::for_open_confirm_channel(open_confirm.attributes(), src_chain) + { collected .per_object .entry(object2) @@ -316,38 +320,11 @@ impl Supervisor { chain.id() ); - //channel object - // self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); - - // } end if channel not open - - ////start spawning channel worker - // let counterparty_chain_id = - // get_counterparty_chain_for_channel(chain.as_ref(), channel.clone()).unwrap(); - - // let counterparty_chain = self.registry.get_or_spawn(&counterparty_chain_id)?; - - // let channel_object = Object::Channel(Channel { - // dst_chain_id: counterparty_chain_id, - // src_chain_id: chain.id(), - // src_channel_id: channel.channel_id.clone(), - // src_port_id: channel.port_id.clone(), - // // connection_id: connection_id.clone(), - // }); - - // debug!( - // "create workers: creating a worker for object {:?}", - // channel_object - // ); - - // self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); - // //end the spawning channel worker - let client_res = channel_connection_client(chain.as_ref(), &channel.port_id, &channel.channel_id); let (client, channel) = match client_res { - Ok(conn_client) => (conn_client.client, conn_client.channel), + Ok(conn_client) => (conn_client.client,conn_client.channel), Err(Error::ConnectionNotOpen(..)) | Err(Error::ChannelNotOpen(..)) => { // These errors are silent. // Simply ignore the channel and return without spawning the workers. @@ -401,15 +378,36 @@ impl Supervisor { // https://github.com/informalsystems/ibc-rs/issues/901 // create the path object and spawn worker let path_object = Object::UnidirectionalChannelPath(UnidirectionalChannelPath { - dst_chain_id: counterparty_chain.id(), + dst_chain_id: counterparty_chain.clone().id(), src_chain_id: chain.id(), src_channel_id: channel.channel_id.clone(), - src_port_id: channel.port_id, + src_port_id: channel.port_id.clone(), }); self.worker_for_object(path_object, chain.clone(), counterparty_chain.clone()); + + //channel object - // self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); + + let counterparty_chain_id = + get_counterparty_chain_for_channel(chain.as_ref(), channel.clone()).unwrap(); + + let counterparty_chain = self.registry.get_or_spawn(&counterparty_chain_id)?; + + let channel_object = Object::Channel(Channel { + dst_chain_id: counterparty_chain_id, + src_chain_id: chain.id(), + src_channel_id: channel.channel_id.clone(), + src_port_id: channel.port_id.clone(), + // connection_id: connection_id.clone(), + }); + + debug!( + "create workers: creating a worker for object {:?}", + channel_object + ); + + self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); } // end if channel not open else { @@ -424,7 +422,7 @@ impl Supervisor { src_chain_id: chain.id(), src_channel_id: channel.channel_id.clone(), src_port_id: channel.port_id.clone(), - // connection_id: connection_id.clone(), + //connection_id: connection_id.clone(), }); debug!( @@ -727,196 +725,219 @@ impl Worker { let a_chain = self.chains.a.clone(); let b_chain = self.chains.b.clone(); - let a_channel = self.chains.a.query_channel( - &channel.src_port_id, - &channel.src_channel_id, - Height::zero(), //height - 1 de la newBlock - )?; - - let connection_id = a_channel.connection_hops().first().ok_or_else(|| { - Error::MissingConnectionHops(channel.src_channel_id.clone(), a_chain.id()) - })?; - - let connection = self - .chains - .a - .query_connection(&connection_id, Height::zero())?; - - let mut state = &ibc::ics04_channel::channel::State::Uninitialized; - - let mut b_channel = Default::default(); - - let counterparty_channel_id = if a_channel.remote.channel_id.is_none() { - Default::default() - } else { - b_channel = self.chains.b.query_channel( - &a_channel.remote.port_id.clone(), - &a_channel.remote.channel_id.clone().unwrap(), - Height::zero(), - )?; - state = &b_channel.state; - a_channel.remote.channel_id.clone().unwrap() - }; - + // let a_channel = self.chains.a.query_channel( + // &channel.src_port_id, + // &channel.src_channel_id, + // Height::zero(), //height - 1 de la newBlock + // )?; + + // let connection_id = a_channel.connection_hops().first().ok_or_else(|| { + // Error::MissingConnectionHops(channel.src_channel_id.clone(), a_chain.id()) + // })?; + + // let connection = self + // .chains + // .a + // .query_connection(&connection_id, Height::zero())?; + + // let mut state = &ibc::ics04_channel::channel::State::Uninitialized; + + // let mut b_channel = Default::default(); + + // let counterparty_channel_id = if a_channel.remote.channel_id.is_none() { + // Default::default() + // } else { + // b_channel = self.chains.b.query_channel( + // &a_channel.remote.port_id.clone(), + // &a_channel.remote.channel_id.clone().unwrap(), + // Height::zero(), + // )?; + // state = &b_channel.state; + // a_channel.remote.channel_id.clone().unwrap() + // }; + let mut handshake_channel = RelayChannel { - ordering: a_channel.ordering().clone(), + ordering: Default::default(), + //TODO how to get the order from raw tx a_side: ChannelSide::new( a_chain.clone(), - connection.client_id().clone(), - connection_id.clone(), - channel.src_port_id.clone(), - channel.src_channel_id.clone(), + Default::default(), + Default::default(), + Default::default(), + Default::default(), ), b_side: ChannelSide::new( b_chain.clone(), - connection.counterparty().client_id().clone(), - connection.counterparty().connection_id().unwrap().clone(), - a_channel.remote.port_id.clone(), - counterparty_channel_id.clone(), + Default::default(), + Default::default(), + Default::default(), + Default::default(), ), - connection_delay: connection.delay_period(), - version: Some(a_channel.version.clone()), + connection_delay: Default::default(), + //TODO detect version from event + version:Default::default(), }; - let mut stage = 0; //Nothing started - let mut found = false; + // let mut handshake_channel = RelayChannel { + // ordering: a_channel.ordering().clone(), + // a_side: ChannelSide::new( + // a_chain.clone(), + // connection.client_id().clone(), + // connection_id.clone(), + // channel.src_port_id.clone(), + // channel.src_channel_id.clone(), + // ), + // b_side: ChannelSide::new( + // b_chain.clone(), + // connection.counterparty().client_id().clone(), + // connection.counterparty().connection_id().unwrap().clone(), + // a_channel.remote.port_id.clone(), + // counterparty_channel_id.clone(), + // ), + // connection_delay: connection.delay_period(), + // version: Some(a_channel.version.clone()), + // }; + + // let mut stage = 0; //Nothing started + // let mut found = false; - debug!( - "\n [{}] initial handshake_channel is {:?} \n ", - channel.short_name(), - handshake_channel - ); + // debug!( + // "\n [{}] initial handshake_channel is {:?} \n ", + // channel.short_name(), + // handshake_channel + // ); //c0 ibc0 Init ? // -> OpenTry ibc1 -> create c1 ibc1 -->> //chan_open_init ibc1 => c1 //c0 ibc0 OpenTry ? <- chan_open_try c1 ibc-1 dest c0 ibc 0 --> new channel - if a_channel.state_matches(&ibc::ics04_channel::channel::State::Init) { - if a_channel.remote.channel_id.is_none() { - let req = QueryChannelsRequest { - pagination: ibc_proto::cosmos::base::query::pagination::all(), - }; - - let channels: Vec = b_chain.query_channels(req.clone())?; - for chan in channels.iter() { - if chan.channel_end.remote.channel_id.is_some() - && chan.channel_end.remote.channel_id.clone().unwrap() - == channel.src_channel_id.clone() - { - debug!( - "[{}] found a pair channel {} on chain {}", - channel.short_name(), - chan.channel_id, - handshake_channel.b_side.chain_id() - ); - found = true; - handshake_channel.b_side.channel_id = chan.channel_id.clone(); - - break; - } - } - stage = 1; // channel in Init - - if !found { - println!( - "\n [{}] sends build_chan_open_try_and_send \n on handshake_channel {:?} channel in state Init \n", - channel.short_name(), - handshake_channel - ); - - match handshake_channel.build_chan_open_try_and_send() { - Err(e) => { - debug!("Failed ChanTry {:?}: {:?}", handshake_channel.b_side, e); - } - Ok(event) => { - println!("{} {} => {:#?}\n", done, b_chain.id(), event); - } - } - } - } - } else { - if a_channel.state_matches(&ibc::ics04_channel::channel::State::TryOpen) { - stage = 2; //channel is in Try Open - - if a_channel.remote.channel_id.is_some() { - //Try chanOpenTry on b_chain - debug!("[{}] chain {} has channel {} in state TryOpen with counterparty {} in state {} \n", channel.short_name(), a_chain.id(), channel.src_channel_id.clone(), counterparty_channel_id.clone(), state); - - if !b_channel.state_matches(&ibc::ics04_channel::channel::State::Open) { - debug!( - "\n [{}] sends build_chan_open_ack_and_send \n on handshake_channel {:?}", - channel.short_name(),handshake_channel); - - match handshake_channel.build_chan_open_ack_and_send() { - Err(e) => { - debug!("Failed ChanAck {:?}: {:?}", handshake_channel.b_side, e); - } - Ok(event) => { - // handshake_channel.b_side.channel_id = extract_channel_id(&event)?.clone(); - println!("{} {} => {:#?}\n", done, b_chain.id(), event); - } - } - } //TODO else either counter party channel is more advanced or another channel closed the hanshake - } //TODO else error - } else { - match (a_channel.state().clone(), state) { - ( - ibc::ics04_channel::channel::State::Open, - ibc::ics04_channel::channel::State::TryOpen, - ) => { - stage = 3; // channel is Open - debug!( - "[{}] chain {} has channel {} in state Open counterparty TryOpen \n", - channel.short_name(), - a_chain.id(), - channel.src_channel_id.clone() - ); - - // Confirm to b_chain - debug!( - "[{}] sends build_chan_open_confirm_and_send \n on handshake_channel {:?}", - channel.short_name(), - handshake_channel - ); - - match handshake_channel.build_chan_open_confirm_and_send() { - Err(e) => { - debug!( - "Failed OpenConfirm {:?}: {:?}", - handshake_channel.b_side, e - ); - } - Ok(event) => { - println!("{} {} => {:#?}\n", done, b_chain.id(), event); - } - } - } - ( - ibc::ics04_channel::channel::State::Open, - ibc::ics04_channel::channel::State::Open, - ) => { - // stage = 3; //Channel is Open - println!( - "[{}]{} {} {} Channel handshake finished for {:#?}\n", - channel.short_name(), - done, - done, - done, - &channel.src_channel_id, - ); - return Ok(()); - } - _ => { - debug!( - "[{}] \n Error Unimplemented handshake case \n", - channel.short_name() - ) - } - } - } - }; - + // if a_channel.state_matches(&ibc::ics04_channel::channel::State::Init) { + // if a_channel.remote.channel_id.is_none() { + // let req = QueryChannelsRequest { + // pagination: ibc_proto::cosmos::base::query::pagination::all(), + // }; + + // let channels: Vec = b_chain.query_channels(req.clone())?; + // for chan in channels.iter() { + // if chan.channel_end.remote.channel_id.is_some() + // && chan.channel_end.remote.channel_id.clone().unwrap() + // == channel.src_channel_id.clone() + // { + // debug!( + // "[{}] found a pair channel {} on chain {}", + // channel.short_name(), + // chan.channel_id, + // handshake_channel.b_side.chain_id() + // ); + // found = true; + // handshake_channel.b_side.channel_id = chan.channel_id.clone(); + + // break; + // } + // } + // stage = 1; // channel in Init + + // if !found { + // println!( + // "\n [{}] sends build_chan_open_try_and_send \n on handshake_channel {:?} channel in state Init \n", + // channel.short_name(), + // handshake_channel + // ); + + // match handshake_channel.build_chan_open_try_and_send() { + // Err(e) => { + // debug!("Failed ChanTry {:?}: {:?}", handshake_channel.b_side, e); + // } + // Ok(event) => { + // println!("{} {} => {:#?}\n", done, b_chain.id(), event); + // } + // } + // } + // } + // } else { + // if a_channel.state_matches(&ibc::ics04_channel::channel::State::TryOpen) { + // stage = 2; //channel is in Try Open + + // if a_channel.remote.channel_id.is_some() { + // //Try chanOpenTry on b_chain + // debug!("[{}] chain {} has channel {} in state TryOpen with counterparty {} in state {} \n", channel.short_name(), a_chain.id(), channel.src_channel_id.clone(), counterparty_channel_id.clone(), state); + + // if !b_channel.state_matches(&ibc::ics04_channel::channel::State::Open) { + // debug!( + // "\n [{}] sends build_chan_open_ack_and_send \n on handshake_channel {:?}", + // channel.short_name(),handshake_channel); + + // match handshake_channel.build_chan_open_ack_and_send() { + // Err(e) => { + // debug!("Failed ChanAck {:?}: {:?}", handshake_channel.b_side, e); + // } + // Ok(event) => { + // // handshake_channel.b_side.channel_id = extract_channel_id(&event)?.clone(); + // println!("{} {} => {:#?}\n", done, b_chain.id(), event); + // } + // } + // } //TODO else either counter party channel is more advanced or another channel closed the hanshake + // } //TODO else error + // } else { + // match (a_channel.state().clone(), state) { + // ( + // ibc::ics04_channel::channel::State::Open, + // ibc::ics04_channel::channel::State::TryOpen, + // ) => { + // stage = 3; // channel is Open + // debug!( + // "[{}] chain {} has channel {} in state Open counterparty TryOpen \n", + // channel.short_name(), + // a_chain.id(), + // channel.src_channel_id.clone() + // ); + + // // Confirm to b_chain + // debug!( + // "[{}] sends build_chan_open_confirm_and_send \n on handshake_channel {:?}", + // channel.short_name(), + // handshake_channel + // ); + + // match handshake_channel.build_chan_open_confirm_and_send() { + // Err(e) => { + // debug!( + // "Failed OpenConfirm {:?}: {:?}", + // handshake_channel.b_side, e + // ); + // } + // Ok(event) => { + // println!("{} {} => {:#?}\n", done, b_chain.id(), event); + // } + // } + // } + // ( + // ibc::ics04_channel::channel::State::Open, + // ibc::ics04_channel::channel::State::Open, + // ) => { + // // stage = 3; //Channel is Open + // println!( + // "[{}]{} {} {} Channel handshake finished for {:#?}\n", + // channel.short_name(), + // done, + // done, + // done, + // &channel.src_channel_id, + // ); + // return Ok(()); + // } + // _ => { + // debug!( + // "[{}] \n Error Unimplemented handshake case \n", + // channel.short_name() + // ) + // } + // } + // } + // }; + + let mut first_iteration = true; loop { if let Ok(cmd) = self.rx.try_recv() { //Ok(WorkerCmd::IbcEvents { batch }) @@ -929,8 +950,63 @@ impl Worker { debug!( "\n [{}] Calling Open Init from the loop {:?}\n ", channel.short_name(), - open_init + open_init.clone() ); + + let connection_id = open_init.attributes().connection_id.clone(); + let counterparty_port_id = open_init.attributes().counterparty_port_id.clone(); + let connection = self.chains.a.query_connection(&connection_id.clone(), Height::zero())?; + let counterparty_channel_id = + match open_init.attributes().counterparty_channel_id.clone(){ + Some(chan_id) => chan_id, + None => Default::default(), + }; + let port_id = open_init.attributes().port_id.clone(); + let channel_id = match open_init.attributes().channel_id.clone(){ + Some(chan_id) => chan_id, + None => Default::default(), + }; + + + handshake_channel = RelayChannel { + ordering: Default::default(), + //TODO how to get the order from raw tx + a_side: ChannelSide::new( + a_chain.clone(), + connection.client_id().clone(), + connection_id.clone(), + port_id, + channel_id, + ), + b_side: ChannelSide::new( + b_chain.clone(), + connection.counterparty().client_id().clone(), + connection.counterparty().connection_id().unwrap().clone(), + counterparty_port_id.clone(), + counterparty_channel_id.clone(), + ), + connection_delay: connection.delay_period(), + //TODO detect version from event + version:Default::default(), + }; + + debug!( + "\n [{}] sends build_chan_open_try_and_send \n on handshake_channel {:?} channel in state Init \n", + channel.short_name(), + handshake_channel + ); + + match handshake_channel.build_chan_open_try_and_send() { + Err(e) => { + debug!("Failed ChanTry {:?}: {:?}", handshake_channel.b_side, e); + } + Ok(event) => { + handshake_channel.b_side.channel_id = extract_channel_id(&event)?.clone(); + println!("{} {} => {:#?}\n", done, b_chain.id(), event.clone()); + } + } + + first_iteration = false; } IbcEvent::OpenTryChannel(open_try) => { @@ -939,56 +1015,82 @@ impl Worker { channel.short_name(), open_try ); + + // Confirm to b_chain + debug!( + "[{}] sends build_chan_open_ack_and_send \n on handshake_channel {:?}", + channel.short_name(), + handshake_channel + ); + + match handshake_channel.build_chan_open_ack_and_send() { + Err(e) => { + debug!("Failed ChanAck {:?}: {:?}", handshake_channel.b_side, e); + } + Ok(event) => { + // handshake_channel.b_side.channel_id = extract_channel_id(&event)?.clone(); + println!("{} {} => {:#?}\n", done, b_chain.id(), event); + } + } + + first_iteration = false; + } IbcEvent::OpenAckChannel(open_ack) => { - debug!(" \n [{}] {} channel handshake OpenAck from {:?} {} channel from event OpenAck \n", + debug!(" \n [{}] channel handshake OpenAck from channel {} \n", channel.short_name(), - handshake_channel.a_side.channel_id(), - handshake_channel.a_side.chain_id(), + //handshake_channel.a_side.channel_id(), + //handshake_channel.a_side.chain_id(), open_ack.channel_id().clone().unwrap() ); - if stage == 1 && !found { - debug!( - "[{}] writting b_side before open_confirm {} ", - channel.short_name(), - handshake_channel.b_side.channel_id - ); - - handshake_channel.b_side.channel_id = - open_ack.counterparty_channel_id().clone().unwrap(); - - debug!( - "[{}] writting b_side after open_confirm {} ", - channel.short_name(), - handshake_channel.b_side.channel_id - ); - } - - debug!( - "[{}] hanshake_channel b_side channel id is {}", - channel.short_name(), - handshake_channel.b_side.channel_id() - ); + //if stage == 1 && !found { + // debug!( + // "[{}] writting b_side before open_confirm ", + // channel.short_name(), + // //handshake_channel.b_side.channel_id + // ); + + // handshake_channel.b_side.channel_id = + // open_ack.counterparty_channel_id().clone().unwrap(); + + // debug!( + // "[{}] writting b_side after open_confirm {} ", + // channel.short_name(), + // handshake_channel.b_side.channel_id + // ); + // } + + // debug!( + // "[{}] hanshake_channel b_side channel id is {}", + // channel.short_name(), + // handshake_channel.b_side.channel_id() + // ); let event = handshake_channel.build_chan_open_confirm_and_send()?; println!("{} {} => {:#?}\n", done, b_chain.id(), event); + + first_iteration = false; + } + IbcEvent::OpenConfirmChannel(open_confirm) => { - debug!("[{}] {} channel handshake OpenConfirm [{}] channel from event OpenConfirm {} ", - channel.short_name(), - handshake_channel.a_side.channel_id(), - handshake_channel.a_side.chain_id(), - open_confirm.channel_id().clone().unwrap() - ); + // debug!("[{}] {} channel handshake OpenConfirm [{}] channel from event OpenConfirm {} ", + // channel.short_name(), + // handshake_channel.a_side.channel_id(), + // handshake_channel.a_side.chain_id(), + // open_confirm.channel_id().clone().unwrap() + // ); println!( "{} {} {} Channel handshake finished for {:#?}\n", done, done, done, &channel.src_channel_id, ); + // first_iteration = false; + return Ok(()); } IbcEvent::CloseInitChannel(_) => {} @@ -1002,7 +1104,9 @@ impl Worker { height: _, new_block: _, } => { - debug!("\n new block \n "); + if first_iteration { + debug!("\n [{}] new block \n ",channel.short_name()); + } } //link.a_to_b.clear_packets(height)?, // _ => {} @@ -1026,6 +1130,8 @@ pub struct Channel { /// Source port identiier. pub src_port_id: PortId, + + // pub connection_id: ConnectionId, } impl Channel { @@ -1209,7 +1315,7 @@ impl Object { src_chain_id: src_chain.id(), src_channel_id: channel_id.clone(), src_port_id: e.port_id().clone(), - // connection_id: e.connection_id().clone(), + //connection_id: e.connection_id().clone(), } .into()) } @@ -1266,7 +1372,7 @@ impl Object { src_chain_id: src_chain.id(), src_channel_id: e.channel_id().clone().unwrap(), src_port_id: e.port_id().clone(), - //connection_id: e.connection_id().clone(), + // connection_id: e.connection_id().clone(), } .into()) } @@ -1290,7 +1396,7 @@ impl Object { src_chain_id: src_chain.id(), src_channel_id: e.channel_id().clone().unwrap(), src_port_id: e.port_id().clone(), - //connection_id: e.connection_id().clone(), + // connection_id: e.connection_id().clone(), } .into()) } From 4674677cdd5205766e64d3e8e958499afaf09d1c Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Mon, 10 May 2021 19:40:39 +0200 Subject: [PATCH 05/52] Update supervisor.rs --- relayer/src/supervisor.rs | 435 ++++++++++++++++++++++++++++++++------ 1 file changed, 366 insertions(+), 69 deletions(-) diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index 9993c5e13e..987a5dbf6c 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -20,15 +20,15 @@ use ibc::{ channel::IdentifiedChannelEnd, events::{Attributes, CloseInit, SendPacket, TimeoutPacket, WriteAcknowledgement}, }, - ics24_host::identifier::{ChainId, ChannelId, ClientId, PortId, ConnectionId}, + ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}, Height, }; use ibc_proto::ibc::core::channel::v1::QueryChannelsRequest; +use crate::channel::extract_channel_id; use crate::channel::Channel as RelayChannel; use crate::channel::ChannelSide; -use crate::channel::extract_channel_id; use crate::{ chain::{ @@ -324,7 +324,7 @@ impl Supervisor { channel_connection_client(chain.as_ref(), &channel.port_id, &channel.channel_id); let (client, channel) = match client_res { - Ok(conn_client) => (conn_client.client,conn_client.channel), + Ok(conn_client) => (conn_client.client, conn_client.channel), Err(Error::ConnectionNotOpen(..)) | Err(Error::ChannelNotOpen(..)) => { // These errors are silent. // Simply ignore the channel and return without spawning the workers. @@ -385,8 +385,7 @@ impl Supervisor { }); self.worker_for_object(path_object, chain.clone(), counterparty_chain.clone()); - - + //channel object let counterparty_chain_id = @@ -399,7 +398,7 @@ impl Supervisor { src_chain_id: chain.id(), src_channel_id: channel.channel_id.clone(), src_port_id: channel.port_id.clone(), - // connection_id: connection_id.clone(), + // connection_id: connection_id.clone(), }); debug!( @@ -755,10 +754,10 @@ impl Worker { // state = &b_channel.state; // a_channel.remote.channel_id.clone().unwrap() // }; - + let mut handshake_channel = RelayChannel { ordering: Default::default(), - //TODO how to get the order from raw tx + //TODO how to get the order from raw tx a_side: ChannelSide::new( a_chain.clone(), Default::default(), @@ -774,8 +773,8 @@ impl Worker { Default::default(), ), connection_delay: Default::default(), - //TODO detect version from event - version:Default::default(), + //TODO detect version from event + version: Default::default(), }; // let mut handshake_channel = RelayChannel { @@ -937,7 +936,7 @@ impl Worker { // } // }; - let mut first_iteration = true; + let mut first_iteration = true; loop { if let Ok(cmd) = self.rx.try_recv() { //Ok(WorkerCmd::IbcEvents { batch }) @@ -953,24 +952,33 @@ impl Worker { open_init.clone() ); - let connection_id = open_init.attributes().connection_id.clone(); - let counterparty_port_id = open_init.attributes().counterparty_port_id.clone(); - let connection = self.chains.a.query_connection(&connection_id.clone(), Height::zero())?; - let counterparty_channel_id = - match open_init.attributes().counterparty_channel_id.clone(){ - Some(chan_id) => chan_id, - None => Default::default(), - }; + let connection_id = + open_init.attributes().connection_id.clone(); + let counterparty_port_id = + open_init.attributes().counterparty_port_id.clone(); + let connection = self + .chains + .a + .query_connection(&connection_id.clone(), Height::zero())?; + let counterparty_channel_id = match open_init + .attributes() + .counterparty_channel_id + .clone() + { + Some(chan_id) => chan_id, + None => Default::default(), + }; let port_id = open_init.attributes().port_id.clone(); - let channel_id = match open_init.attributes().channel_id.clone(){ + let channel_id = match open_init.attributes().channel_id.clone() + { Some(chan_id) => chan_id, None => Default::default(), + //TODO err }; - handshake_channel = RelayChannel { ordering: Default::default(), - //TODO how to get the order from raw tx + //TODO how to get the order from raw tx a_side: ChannelSide::new( a_chain.clone(), connection.client_id().clone(), @@ -981,13 +989,17 @@ impl Worker { b_side: ChannelSide::new( b_chain.clone(), connection.counterparty().client_id().clone(), - connection.counterparty().connection_id().unwrap().clone(), + connection + .counterparty() + .connection_id() + .unwrap() + .clone(), counterparty_port_id.clone(), counterparty_channel_id.clone(), ), connection_delay: connection.delay_period(), - //TODO detect version from event - version:Default::default(), + //TODO detect version from event + version: Default::default(), }; debug!( @@ -995,18 +1007,77 @@ impl Worker { channel.short_name(), handshake_channel ); - + + let connection_id = + open_init.attributes().connection_id.clone(); + let counterparty_port_id = + open_init.attributes().counterparty_port_id.clone(); + let connection = self + .chains + .a + .query_connection(&connection_id.clone(), Height::zero())?; + let counterparty_channel_id = match open_init + .attributes() + .counterparty_channel_id + .clone() + { + Some(chan_id) => chan_id, + None => Default::default(), + }; + let port_id = open_init.attributes().port_id.clone(); + let channel_id = match open_init.attributes().channel_id.clone() + { + Some(chan_id) => chan_id, + None => Default::default(), + //TODO err + }; + + handshake_channel = RelayChannel { + ordering: Default::default(), + //TODO how to get the order from raw tx + a_side: ChannelSide::new( + a_chain.clone(), + connection.client_id().clone(), + connection_id.clone(), + port_id, + channel_id, + ), + b_side: ChannelSide::new( + b_chain.clone(), + connection.counterparty().client_id().clone(), + connection + .counterparty() + .connection_id() + .unwrap() + .clone(), + counterparty_port_id.clone(), + counterparty_channel_id.clone(), + ), + connection_delay: connection.delay_period(), + //TODO detect version from event + version: Default::default(), + }; + match handshake_channel.build_chan_open_try_and_send() { Err(e) => { - debug!("Failed ChanTry {:?}: {:?}", handshake_channel.b_side, e); + debug!( + "Failed ChanTry {:?}: {:?}", + handshake_channel.b_side, e + ); } Ok(event) => { - handshake_channel.b_side.channel_id = extract_channel_id(&event)?.clone(); - println!("{} {} => {:#?}\n", done, b_chain.id(), event.clone()); + handshake_channel.b_side.channel_id = + extract_channel_id(&event)?.clone(); + println!( + "{} {} => {:#?}\n", + done, + b_chain.id(), + event.clone() + ); } } - first_iteration = false; + first_iteration = false; } IbcEvent::OpenTryChannel(open_try) => { @@ -1016,51 +1087,57 @@ impl Worker { open_try ); - // Confirm to b_chain debug!( "[{}] sends build_chan_open_ack_and_send \n on handshake_channel {:?}", channel.short_name(), handshake_channel ); - + match handshake_channel.build_chan_open_ack_and_send() { Err(e) => { - debug!("Failed ChanAck {:?}: {:?}", handshake_channel.b_side, e); + debug!( + "Failed ChanAck {:?}: {:?}", + handshake_channel.b_side, e + ); } Ok(event) => { // handshake_channel.b_side.channel_id = extract_channel_id(&event)?.clone(); - println!("{} {} => {:#?}\n", done, b_chain.id(), event); + println!( + "{} {} => {:#?}\n", + done, + b_chain.id(), + event + ); } } - - first_iteration = false; + first_iteration = false; } IbcEvent::OpenAckChannel(open_ack) => { - debug!(" \n [{}] channel handshake OpenAck from channel {} \n", + debug!(" \n [{}] channel handshake OpenAck from chain {:?} on channel {} due to event {} \n", channel.short_name(), - //handshake_channel.a_side.channel_id(), - //handshake_channel.a_side.chain_id(), + handshake_channel.a_side.channel_id(), + handshake_channel.a_side.chain_id(), open_ack.channel_id().clone().unwrap() ); //if stage == 1 && !found { - // debug!( - // "[{}] writting b_side before open_confirm ", - // channel.short_name(), - // //handshake_channel.b_side.channel_id - // ); - - // handshake_channel.b_side.channel_id = - // open_ack.counterparty_channel_id().clone().unwrap(); - - // debug!( - // "[{}] writting b_side after open_confirm {} ", - // channel.short_name(), - // handshake_channel.b_side.channel_id - // ); - // } + // debug!( + // "[{}] writting b_side before open_confirm ", + // channel.short_name(), + // //handshake_channel.b_side.channel_id + // ); + + // handshake_channel.b_side.channel_id = + // open_ack.counterparty_channel_id().clone().unwrap(); + + // debug!( + // "[{}] writting b_side after open_confirm {} ", + // channel.short_name(), + // handshake_channel.b_side.channel_id + // ); + // } // debug!( // "[{}] hanshake_channel b_side channel id is {}", @@ -1071,25 +1148,24 @@ impl Worker { let event = handshake_channel.build_chan_open_confirm_and_send()?; println!("{} {} => {:#?}\n", done, b_chain.id(), event); - - first_iteration = false; + first_iteration = false; } IbcEvent::OpenConfirmChannel(open_confirm) => { - // debug!("[{}] {} channel handshake OpenConfirm [{}] channel from event OpenConfirm {} ", - // channel.short_name(), - // handshake_channel.a_side.channel_id(), - // handshake_channel.a_side.chain_id(), - // open_confirm.channel_id().clone().unwrap() - // ); + debug!("[{}] {} channel handshake OpenConfirm [{}] channel from event OpenConfirm {} ", + channel.short_name(), + handshake_channel.a_side.channel_id(), + handshake_channel.a_side.chain_id(), + open_confirm.channel_id().clone().unwrap() + ); println!( "{} {} {} Channel handshake finished for {:#?}\n", done, done, done, &channel.src_channel_id, ); - // first_iteration = false; + // first_iteration = false; return Ok(()); } @@ -1101,11 +1177,233 @@ impl Worker { } WorkerCmd::NewBlock { - height: _, + height: current_height, new_block: _, } => { if first_iteration { - debug!("\n [{}] new block \n ",channel.short_name()); + debug!("\n [{}] new block \n ", channel.short_name()); + + let height = current_height.decrement()?; + + let a_channel = self.chains.a.query_channel( + &channel.src_port_id, + &channel.src_channel_id, + height, //current_height - 1 de la newBlock + )?; + + let connection_id = + a_channel.connection_hops().first().ok_or_else(|| { + Error::MissingConnectionHops( + channel.src_channel_id.clone(), + a_chain.id(), + ) + })?; + + let connection = self + .chains + .a + .query_connection(&connection_id, Height::zero())?; + + let mut counterparty_state = + &ibc::ics04_channel::channel::State::Uninitialized; + + let mut b_channel = Default::default(); + + let counterparty_channel_id = if a_channel.remote.channel_id.is_none() { + Default::default() + } else { + b_channel = self.chains.b.query_channel( + &a_channel.remote.port_id.clone(), + &a_channel.remote.channel_id.clone().unwrap(), + Height::zero(), + )?; + counterparty_state = &b_channel.state; + a_channel.remote.channel_id.clone().unwrap() + }; + + let mut handshake_channel = RelayChannel { + ordering: a_channel.ordering().clone(), + a_side: ChannelSide::new( + a_chain.clone(), + connection.client_id().clone(), + connection_id.clone(), + channel.src_port_id.clone(), + channel.src_channel_id.clone(), + ), + b_side: ChannelSide::new( + b_chain.clone(), + connection.counterparty().client_id().clone(), + connection.counterparty().connection_id().unwrap().clone(), + a_channel.remote.port_id.clone(), + counterparty_channel_id.clone(), + ), + connection_delay: connection.delay_period(), + version: Some(a_channel.version.clone()), + }; + + // let mut stage = 0; //Nothing started + let mut found = false; + + debug!( + "\n [{}] initial handshake_channel is {:?} \n ", + channel.short_name(), + handshake_channel + ); + + if a_channel.state_matches(&ibc::ics04_channel::channel::State::Init) { + if a_channel.remote.channel_id.is_none() { + let req = QueryChannelsRequest { + pagination: ibc_proto::cosmos::base::query::pagination::all( + ), + }; + //TODO Query up to a height + let channels: Vec = + b_chain.query_channels(req.clone())?; + for chan in channels.iter() { + if chan.channel_end.remote.channel_id.is_some() + && chan.channel_end.remote.channel_id.clone().unwrap() + == channel.src_channel_id.clone() + { + debug!( + "[{}] found a pair channel {} on chain {}", + channel.short_name(), + chan.channel_id, + handshake_channel.b_side.chain_id() + ); + found = true; + handshake_channel.b_side.channel_id = + chan.channel_id.clone(); + + break; + } + } + // stage = 1; // channel in Init + + if !found { + println!( + "\n [{}] sends build_chan_open_try_and_send \n on handshake_channel {:?} channel in state Init \n", + channel.short_name(), + handshake_channel + ); + + match handshake_channel.build_chan_open_try_and_send() { + Err(e) => { + debug!( + "Failed ChanTry {:?}: {:?}", + handshake_channel.b_side, e + ); + } + Ok(event) => { + println!( + "{} {} => {:#?}\n", + done, + b_chain.id(), + event + ); + } + } + } + } + } else { + if a_channel + .state_matches(&ibc::ics04_channel::channel::State::TryOpen) + { + //stage = 2; //channel is in Try Open + + if a_channel.remote.channel_id.is_some() { + //Try chanOpenTry on b_chain + debug!("[{}] chain {} has channel {} in state TryOpen with counterparty {} in state {} \n", channel.short_name(), a_chain.id(), channel.src_channel_id.clone(), counterparty_channel_id.clone(), counterparty_state); + + if !b_channel.state_matches( + &ibc::ics04_channel::channel::State::Open, + ) { + debug!( + "\n [{}] sends build_chan_open_ack_and_send \n on handshake_channel {:?}", + channel.short_name(),handshake_channel); + + match handshake_channel.build_chan_open_ack_and_send() { + Err(e) => { + debug!( + "Failed ChanAck {:?}: {:?}", + handshake_channel.b_side, e + ); + } + Ok(event) => { + // handshake_channel.b_side.channel_id = extract_channel_id(&event)?.clone(); + println!( + "{} {} => {:#?}\n", + done, + b_chain.id(), + event + ); + } + } + } //TODO else either counter party channel is more advanced or another channel closed the hanshake + } //TODO else error + } else { + match (a_channel.state().clone(), counterparty_state) { + ( + ibc::ics04_channel::channel::State::Open, + ibc::ics04_channel::channel::State::TryOpen, + ) => { + //stage = 3; // channel is Open + debug!( + "[{}] chain {} has channel {} in state Open counterparty TryOpen \n", + channel.short_name(), + a_chain.id(), + channel.src_channel_id.clone() + ); + + // Confirm to b_chain + debug!( + "[{}] sends build_chan_open_confirm_and_send \n on handshake_channel {:?}", + channel.short_name(), + handshake_channel + ); + + match handshake_channel + .build_chan_open_confirm_and_send() + { + Err(e) => { + debug!( + "Failed OpenConfirm {:?}: {:?}", + handshake_channel.b_side, e + ); + } + Ok(event) => { + println!( + "{} {} => {:#?}\n", + done, + b_chain.id(), + event + ); + } + } + } + ( + ibc::ics04_channel::channel::State::Open, + ibc::ics04_channel::channel::State::Open, + ) => { + // stage = 3; //Channel is Open + println!( + "[{}]{} {} {} Channel handshake finished for {:#?}\n", + channel.short_name(), + done, + done, + done, + &channel.src_channel_id, + ); + return Ok(()); + } + _ => { + debug!( + "[{}] \n Error Unimplemented handshake case \n", + channel.short_name() + ) + } + } + } + }; } } //link.a_to_b.clear_packets(height)?, @@ -1130,8 +1428,7 @@ pub struct Channel { /// Source port identiier. pub src_port_id: PortId, - - // pub connection_id: ConnectionId, + // pub connection_id: ConnectionId, } impl Channel { @@ -1372,7 +1669,7 @@ impl Object { src_chain_id: src_chain.id(), src_channel_id: e.channel_id().clone().unwrap(), src_port_id: e.port_id().clone(), - // connection_id: e.connection_id().clone(), + // connection_id: e.connection_id().clone(), } .into()) } @@ -1396,7 +1693,7 @@ impl Object { src_chain_id: src_chain.id(), src_channel_id: e.channel_id().clone().unwrap(), src_port_id: e.port_id().clone(), - // connection_id: e.connection_id().clone(), + // connection_id: e.connection_id().clone(), } .into()) } From 54e43ef7af5c36f992c96f8969c7cd8b052a732c Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Mon, 10 May 2021 19:49:36 +0200 Subject: [PATCH 06/52] Temp fix for option channel IDs --- relayer-cli/src/commands/tx/channel.rs | 6 +- relayer/src/supervisor.rs | 180 ++++++++++++++----------- 2 files changed, 106 insertions(+), 80 deletions(-) diff --git a/relayer-cli/src/commands/tx/channel.rs b/relayer-cli/src/commands/tx/channel.rs index 8eef6d585b..d06db384d6 100644 --- a/relayer-cli/src/commands/tx/channel.rs +++ b/relayer-cli/src/commands/tx/channel.rs @@ -122,9 +122,9 @@ pub struct TxRawChanOpenTryCmd { src_chan_id: ChannelId, #[options( - help = "identifier of the destination channel (optional)", - short = "d", - meta = "ID" + help = "identifier of the destination channel (optional)", + short = "d", + meta = "ID" )] dst_chan_id: ChannelId, } diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index 9993c5e13e..a636122eb6 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -20,15 +20,15 @@ use ibc::{ channel::IdentifiedChannelEnd, events::{Attributes, CloseInit, SendPacket, TimeoutPacket, WriteAcknowledgement}, }, - ics24_host::identifier::{ChainId, ChannelId, ClientId, PortId, ConnectionId}, + ics24_host::identifier::{ChainId, ChannelId, ClientId, PortId}, Height, }; use ibc_proto::ibc::core::channel::v1::QueryChannelsRequest; +use crate::channel::extract_channel_id; use crate::channel::Channel as RelayChannel; use crate::channel::ChannelSide; -use crate::channel::extract_channel_id; use crate::{ chain::{ @@ -324,7 +324,7 @@ impl Supervisor { channel_connection_client(chain.as_ref(), &channel.port_id, &channel.channel_id); let (client, channel) = match client_res { - Ok(conn_client) => (conn_client.client,conn_client.channel), + Ok(conn_client) => (conn_client.client, conn_client.channel), Err(Error::ConnectionNotOpen(..)) | Err(Error::ChannelNotOpen(..)) => { // These errors are silent. // Simply ignore the channel and return without spawning the workers. @@ -385,8 +385,7 @@ impl Supervisor { }); self.worker_for_object(path_object, chain.clone(), counterparty_chain.clone()); - - + //channel object let counterparty_chain_id = @@ -398,8 +397,8 @@ impl Supervisor { dst_chain_id: counterparty_chain_id, src_chain_id: chain.id(), src_channel_id: channel.channel_id.clone(), - src_port_id: channel.port_id.clone(), - // connection_id: connection_id.clone(), + src_port_id: channel.port_id, + // connection_id: connection_id.clone(), }); debug!( @@ -421,7 +420,7 @@ impl Supervisor { dst_chain_id: counterparty_chain_id, src_chain_id: chain.id(), src_channel_id: channel.channel_id.clone(), - src_port_id: channel.port_id.clone(), + src_port_id: channel.port_id, //connection_id: connection_id.clone(), }); @@ -755,10 +754,10 @@ impl Worker { // state = &b_channel.state; // a_channel.remote.channel_id.clone().unwrap() // }; - + let mut handshake_channel = RelayChannel { ordering: Default::default(), - //TODO how to get the order from raw tx + //TODO how to get the order from raw tx a_side: ChannelSide::new( a_chain.clone(), Default::default(), @@ -774,8 +773,8 @@ impl Worker { Default::default(), ), connection_delay: Default::default(), - //TODO detect version from event - version:Default::default(), + //TODO detect version from event + version: Default::default(), }; // let mut handshake_channel = RelayChannel { @@ -937,7 +936,7 @@ impl Worker { // } // }; - let mut first_iteration = true; + let mut first_iteration = true; loop { if let Ok(cmd) = self.rx.try_recv() { //Ok(WorkerCmd::IbcEvents { batch }) @@ -953,24 +952,32 @@ impl Worker { open_init.clone() ); - let connection_id = open_init.attributes().connection_id.clone(); - let counterparty_port_id = open_init.attributes().counterparty_port_id.clone(); - let connection = self.chains.a.query_connection(&connection_id.clone(), Height::zero())?; - let counterparty_channel_id = - match open_init.attributes().counterparty_channel_id.clone(){ - Some(chan_id) => chan_id, - None => Default::default(), - }; + let connection_id = + open_init.attributes().connection_id.clone(); + let counterparty_port_id = + open_init.attributes().counterparty_port_id.clone(); + let connection = self + .chains + .a + .query_connection(&connection_id.clone(), Height::zero())?; + let counterparty_channel_id = match open_init + .attributes() + .counterparty_channel_id + .clone() + { + Some(chan_id) => chan_id, + None => Default::default(), + }; let port_id = open_init.attributes().port_id.clone(); - let channel_id = match open_init.attributes().channel_id.clone(){ + let channel_id = match open_init.attributes().channel_id.clone() + { Some(chan_id) => chan_id, None => Default::default(), }; - handshake_channel = RelayChannel { ordering: Default::default(), - //TODO how to get the order from raw tx + //TODO how to get the order from raw tx a_side: ChannelSide::new( a_chain.clone(), connection.client_id().clone(), @@ -981,13 +988,17 @@ impl Worker { b_side: ChannelSide::new( b_chain.clone(), connection.counterparty().client_id().clone(), - connection.counterparty().connection_id().unwrap().clone(), + connection + .counterparty() + .connection_id() + .unwrap() + .clone(), counterparty_port_id.clone(), counterparty_channel_id.clone(), ), connection_delay: connection.delay_period(), - //TODO detect version from event - version:Default::default(), + //TODO detect version from event + version: Default::default(), }; debug!( @@ -995,18 +1006,27 @@ impl Worker { channel.short_name(), handshake_channel ); - + match handshake_channel.build_chan_open_try_and_send() { Err(e) => { - debug!("Failed ChanTry {:?}: {:?}", handshake_channel.b_side, e); + debug!( + "Failed ChanTry {:?}: {:?}", + handshake_channel.b_side, e + ); } Ok(event) => { - handshake_channel.b_side.channel_id = extract_channel_id(&event)?.clone(); - println!("{} {} => {:#?}\n", done, b_chain.id(), event.clone()); + handshake_channel.b_side.channel_id = + extract_channel_id(&event)?.clone(); + println!( + "{} {} => {:#?}\n", + done, + b_chain.id(), + event.clone() + ); } } - first_iteration = false; + first_iteration = false; } IbcEvent::OpenTryChannel(open_try) => { @@ -1022,45 +1042,53 @@ impl Worker { channel.short_name(), handshake_channel ); - + match handshake_channel.build_chan_open_ack_and_send() { Err(e) => { - debug!("Failed ChanAck {:?}: {:?}", handshake_channel.b_side, e); + debug!( + "Failed ChanAck {:?}: {:?}", + handshake_channel.b_side, e + ); } Ok(event) => { // handshake_channel.b_side.channel_id = extract_channel_id(&event)?.clone(); - println!("{} {} => {:#?}\n", done, b_chain.id(), event); + println!( + "{} {} => {:#?}\n", + done, + b_chain.id(), + event + ); } } - - first_iteration = false; + first_iteration = false; } IbcEvent::OpenAckChannel(open_ack) => { - debug!(" \n [{}] channel handshake OpenAck from channel {} \n", - channel.short_name(), - //handshake_channel.a_side.channel_id(), - //handshake_channel.a_side.chain_id(), - open_ack.channel_id().clone().unwrap() - ); + debug!( + " \n [{}] channel handshake OpenAck from channel {} \n", + channel.short_name(), + //handshake_channel.a_side.channel_id(), + //handshake_channel.a_side.chain_id(), + open_ack.channel_id().clone().unwrap() + ); //if stage == 1 && !found { - // debug!( - // "[{}] writting b_side before open_confirm ", - // channel.short_name(), - // //handshake_channel.b_side.channel_id - // ); - - // handshake_channel.b_side.channel_id = - // open_ack.counterparty_channel_id().clone().unwrap(); - - // debug!( - // "[{}] writting b_side after open_confirm {} ", - // channel.short_name(), - // handshake_channel.b_side.channel_id - // ); - // } + // debug!( + // "[{}] writting b_side before open_confirm ", + // channel.short_name(), + // //handshake_channel.b_side.channel_id + // ); + + // handshake_channel.b_side.channel_id = + // open_ack.counterparty_channel_id().clone().unwrap(); + + // debug!( + // "[{}] writting b_side after open_confirm {} ", + // channel.short_name(), + // handshake_channel.b_side.channel_id + // ); + // } // debug!( // "[{}] hanshake_channel b_side channel id is {}", @@ -1071,25 +1099,24 @@ impl Worker { let event = handshake_channel.build_chan_open_confirm_and_send()?; println!("{} {} => {:#?}\n", done, b_chain.id(), event); - - first_iteration = false; + first_iteration = false; } - IbcEvent::OpenConfirmChannel(open_confirm) => { - // debug!("[{}] {} channel handshake OpenConfirm [{}] channel from event OpenConfirm {} ", - // channel.short_name(), - // handshake_channel.a_side.channel_id(), - // handshake_channel.a_side.chain_id(), - // open_confirm.channel_id().clone().unwrap() - // ); + IbcEvent::OpenConfirmChannel(_open_confirm) => { + // debug!("[{}] {} channel handshake OpenConfirm [{}] channel from event OpenConfirm {} ", + // channel.short_name(), + // handshake_channel.a_side.channel_id(), + // handshake_channel.a_side.chain_id(), + // open_confirm.channel_id().clone().unwrap() + // ); println!( "{} {} {} Channel handshake finished for {:#?}\n", done, done, done, &channel.src_channel_id, ); - // first_iteration = false; + // first_iteration = false; return Ok(()); } @@ -1105,7 +1132,7 @@ impl Worker { new_block: _, } => { if first_iteration { - debug!("\n [{}] new block \n ",channel.short_name()); + debug!("\n [{}] new block \n ", channel.short_name()); } } //link.a_to_b.clear_packets(height)?, @@ -1130,8 +1157,7 @@ pub struct Channel { /// Source port identiier. pub src_port_id: PortId, - - // pub connection_id: ConnectionId, + // pub connection_id: ConnectionId, } impl Channel { @@ -1300,7 +1326,7 @@ impl Object { if dst_chain_id.is_err() { debug!("\n err dest_chan_id in init\n "); - return Err(format!("dest chain missing in init").into()); + return Err("dest chain missing in init".into()); } debug!( @@ -1311,7 +1337,7 @@ impl Object { ); Ok(Channel { - dst_chain_id: dst_chain_id.clone().unwrap(), + dst_chain_id: dst_chain_id.unwrap(), src_chain_id: src_chain.id(), src_channel_id: channel_id.clone(), src_port_id: e.port_id().clone(), @@ -1334,7 +1360,7 @@ impl Object { if dst_chain_id.is_err() { debug!("\n err dest_chan_id in try\n "); - return Err(format!("dest chain missing in OpenTry").into()); + return Err("dest chain missing in OpenTry".into()); } debug!( @@ -1345,7 +1371,7 @@ impl Object { ); Ok(Channel { - dst_chain_id: dst_chain_id.clone().unwrap(), + dst_chain_id: dst_chain_id.unwrap(), src_chain_id: src_chain.id(), src_channel_id: e.channel_id().clone().unwrap(), src_port_id: e.port_id().clone(), @@ -1372,7 +1398,7 @@ impl Object { src_chain_id: src_chain.id(), src_channel_id: e.channel_id().clone().unwrap(), src_port_id: e.port_id().clone(), - // connection_id: e.connection_id().clone(), + // connection_id: e.connection_id().clone(), } .into()) } @@ -1396,7 +1422,7 @@ impl Object { src_chain_id: src_chain.id(), src_channel_id: e.channel_id().clone().unwrap(), src_port_id: e.port_id().clone(), - // connection_id: e.connection_id().clone(), + // connection_id: e.connection_id().clone(), } .into()) } From 1f80a9d3d240923675cb33939ec6fd43ff5c3601 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Mon, 10 May 2021 20:03:46 +0200 Subject: [PATCH 07/52] Fix open try --- relayer-cli/src/commands/tx/channel.rs | 24 +++--- relayer/src/channel.rs | 107 ++++++++++++++++--------- relayer/src/link.rs | 100 ++++++++++++++--------- relayer/src/supervisor.rs | 6 +- 4 files changed, 145 insertions(+), 92 deletions(-) diff --git a/relayer-cli/src/commands/tx/channel.rs b/relayer-cli/src/commands/tx/channel.rs index d06db384d6..47476a45f6 100644 --- a/relayer-cli/src/commands/tx/channel.rs +++ b/relayer-cli/src/commands/tx/channel.rs @@ -80,14 +80,14 @@ impl Runnable for TxRawChanOpenInitCmd { ClientId::default(), ConnectionId::default(), self.src_port_id.clone(), - ChannelId::default(), + None, ), b_side: ChannelSide::new( chains.dst.clone(), dst_connection.client_id().clone(), self.dst_conn_id.clone(), self.dst_port_id.clone(), - ChannelId::default(), + None, ), version: None, } @@ -126,7 +126,7 @@ pub struct TxRawChanOpenTryCmd { short = "d", meta = "ID" )] - dst_chan_id: ChannelId, + dst_chan_id: Option, } impl Runnable for TxRawChanOpenTryCmd { @@ -144,7 +144,7 @@ impl Runnable for TxRawChanOpenTryCmd { ClientId::default(), ConnectionId::default(), self.src_port_id.clone(), - self.src_chan_id.clone(), + Some(self.src_chan_id.clone()), ), b_side: ChannelSide::new( chains.dst.clone(), @@ -209,14 +209,14 @@ impl Runnable for TxRawChanOpenAckCmd { ClientId::default(), ConnectionId::default(), self.src_port_id.clone(), - self.src_chan_id.clone(), + Some(self.src_chan_id.clone()), ), b_side: ChannelSide::new( chains.dst.clone(), dst_connection.client_id().clone(), self.dst_conn_id.clone(), self.dst_port_id.clone(), - self.dst_chan_id.clone(), + Some(self.dst_chan_id.clone()), ), version: None, } @@ -274,14 +274,14 @@ impl Runnable for TxRawChanOpenConfirmCmd { ClientId::default(), ConnectionId::default(), self.src_port_id.clone(), - self.src_chan_id.clone(), + Some(self.src_chan_id.clone()), ), b_side: ChannelSide::new( chains.dst.clone(), dst_connection.client_id().clone(), self.dst_conn_id.clone(), self.dst_port_id.clone(), - self.dst_chan_id.clone(), + Some(self.dst_chan_id.clone()), ), version: None, } @@ -339,14 +339,14 @@ impl Runnable for TxRawChanCloseInitCmd { ClientId::default(), ConnectionId::default(), self.src_port_id.clone(), - self.src_chan_id.clone(), + Some(self.src_chan_id.clone()), ), b_side: ChannelSide::new( chains.dst.clone(), dst_connection.client_id().clone(), self.dst_conn_id.clone(), self.dst_port_id.clone(), - self.dst_chan_id.clone(), + Some(self.dst_chan_id.clone()), ), version: None, } @@ -404,14 +404,14 @@ impl Runnable for TxRawChanCloseConfirmCmd { ClientId::default(), ConnectionId::default(), self.src_port_id.clone(), - self.src_chan_id.clone(), + Some(self.src_chan_id.clone()), ), b_side: ChannelSide::new( chains.dst.clone(), dst_connection.client_id().clone(), self.dst_conn_id.clone(), self.dst_port_id.clone(), - self.dst_chan_id.clone(), + Some(self.dst_chan_id.clone()), ), version: None, } diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index c4491b69e1..9ec7f50e88 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -45,7 +45,7 @@ pub struct ChannelSide { client_id: ClientId, connection_id: ConnectionId, port_id: PortId, - pub channel_id: ChannelId, + pub channel_id: Option, } impl ChannelSide { @@ -54,7 +54,7 @@ impl ChannelSide { client_id: ClientId, connection_id: ConnectionId, port_id: PortId, - channel_id: ChannelId, + channel_id: Option, ) -> ChannelSide { Self { chain, @@ -81,8 +81,8 @@ impl ChannelSide { &self.port_id } - pub fn channel_id(&self) -> &ChannelId { - &self.channel_id + pub fn channel_id(&self) -> Option<&ChannelId> { + self.channel_id.as_ref() } } @@ -169,12 +169,12 @@ impl Channel { &self.b_side.port_id } - pub fn src_channel_id(&self) -> &ChannelId { - &self.a_side.channel_id + pub fn src_channel_id(&self) -> Option<&ChannelId> { + self.a_side.channel_id() } - pub fn dst_channel_id(&self) -> &ChannelId { - &self.b_side.channel_id + pub fn dst_channel_id(&self) -> Option<&ChannelId> { + self.b_side.channel_id() } pub fn flipped(&self) -> Channel { @@ -205,7 +205,7 @@ impl Channel { continue; } Ok(event) => { - self.a_side.channel_id = extract_channel_id(&event)?.clone(); + self.a_side.channel_id = Some(extract_channel_id(&event)?.clone()); println!("{} {} => {:#?}\n", done, a_chain.id(), event); init_success = true; break; @@ -232,7 +232,7 @@ impl Channel { continue; } Ok(event) => { - self.b_side.channel_id = extract_channel_id(&event)?.clone(); + self.b_side.channel_id = Some(extract_channel_id(&event)?.clone()); println!("{} {} => {:#?}\n", done, b_chain.id(), event); try_success = true; break; @@ -251,14 +251,23 @@ impl Channel { while counter < MAX_ITER { counter += 1; + assert!(self.src_channel_id().is_some()); + assert!(self.dst_channel_id().is_some()); + // Continue loop if query error - let a_channel = - a_chain.query_channel(&self.src_port_id(), &self.src_channel_id(), Height::zero()); + let a_channel = a_chain.query_channel( + &self.src_port_id(), + &self.src_channel_id().unwrap(), + Height::zero(), + ); if a_channel.is_err() { continue; } - let b_channel = - b_chain.query_channel(&self.dst_port_id(), &self.dst_channel_id(), Height::zero()); + let b_channel = b_chain.query_channel( + &self.dst_port_id(), + &self.dst_channel_id().unwrap(), + Height::zero(), + ); if b_channel.is_err() { continue; } @@ -414,10 +423,8 @@ impl Channel { msg_type: ChannelMsgType, ) -> Result { // If there is a channel present on the destination chain, it should look like this: - let counterparty = Counterparty::new( - self.src_port_id().clone(), - Option::from(self.src_channel_id().clone()), - ); + let counterparty = + Counterparty::new(self.src_port_id().clone(), self.src_channel_id().cloned()); // The highest expected state, depends on the message type: let highest_state = match msg_type { @@ -435,10 +442,15 @@ impl Channel { self.dst_version()?, ); - // Retrieve existing channel if any + // Retrieve existing channel + assert!(self.dst_channel_id().is_some()); let dst_channel = self .dst_chain() - .query_channel(self.dst_port_id(), self.dst_channel_id(), Height::default()) + .query_channel( + self.dst_port_id(), + self.dst_channel_id().unwrap(), + Height::default(), + ) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; // Check if a connection is expected to exist on destination chain @@ -450,7 +462,7 @@ impl Channel { } check_destination_channel_state( - self.dst_channel_id().clone(), + self.dst_channel_id().cloned().unwrap(), dst_channel, dst_expected_channel.clone(), )?; @@ -459,9 +471,11 @@ impl Channel { } pub fn build_chan_open_try(&self) -> Result, ChannelError> { + assert!(self.src_channel_id().is_some()); + let src_channel_id = self.src_channel_id().unwrap(); let src_channel = self .src_chain() - .query_channel(self.src_port_id(), self.src_channel_id(), Height::default()) + .query_channel(self.src_port_id(), src_channel_id, Height::default()) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?; // Retrieve the connection @@ -477,16 +491,14 @@ impl Channel { let proofs = self .src_chain() - .build_channel_proofs(self.src_port_id(), self.src_channel_id(), query_height) + .build_channel_proofs(self.src_port_id(), src_channel_id, query_height) .map_err(|e| ChannelError::Failed(format!("failed to build channel proofs: {}", e)))?; // Build message(s) to update client on destination let mut msgs = self.build_update_client_on_dst(proofs.height())?; - let counterparty = Counterparty::new( - self.src_port_id().clone(), - Some(self.src_channel_id().clone()), - ); + let counterparty = + Counterparty::new(self.src_port_id().clone(), Some(src_channel_id.clone())); let channel = ChannelEnd::new( State::TryOpen, @@ -506,7 +518,7 @@ impl Channel { })?; let previous_channel_id = if src_channel.counterparty().channel_id.is_none() { - Some(self.b_side.channel_id.clone()) + self.b_side.channel_id.clone() } else { src_channel.counterparty().channel_id.clone() }; @@ -526,6 +538,7 @@ impl Channel { } pub fn build_chan_open_try_and_send(&self) -> Result { + println!("\n SLEF {:#?}", self); let dst_msgs = self.build_chan_open_try()?; let events = self @@ -556,10 +569,13 @@ impl Channel { pub fn build_chan_open_ack(&self) -> Result, ChannelError> { // Check that the destination chain will accept the message let _dst_expected_channel = self.validated_expected_channel(ChannelMsgType::OpenAck)?; + assert!(self.src_channel_id().is_some()); + let src_channel_id = self.src_channel_id().unwrap(); + assert!(self.dst_channel_id().is_some()); let _src_channel = self .src_chain() - .query_channel(self.src_port_id(), self.src_channel_id(), Height::default()) + .query_channel(self.src_port_id(), src_channel_id, Height::default()) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?; // Retrieve the connection @@ -575,7 +591,7 @@ impl Channel { let proofs = self .src_chain() - .build_channel_proofs(self.src_port_id(), self.src_channel_id(), query_height) + .build_channel_proofs(self.src_port_id(), src_channel_id, query_height) .map_err(|e| { ChannelError::Failed(format!( "failed while building the channel proofs at ACK step with error: {}", @@ -598,8 +614,8 @@ impl Channel { // Build the domain type message let new_msg = MsgChannelOpenAck { port_id: self.dst_port_id().clone(), - channel_id: self.dst_channel_id().clone(), - counterparty_channel_id: self.src_channel_id().clone(), + channel_id: self.dst_channel_id().unwrap().clone(), + counterparty_channel_id: src_channel_id.clone(), counterparty_version: self.src_version()?, proofs, signer, @@ -641,9 +657,13 @@ impl Channel { // Check that the destination chain will accept the message let _dst_expected_channel = self.validated_expected_channel(ChannelMsgType::OpenConfirm)?; + assert!(self.src_channel_id().is_some()); + let src_channel_id = self.src_channel_id().unwrap(); + assert!(self.dst_channel_id().is_some()); + let _src_channel = self .src_chain() - .query_channel(self.src_port_id(), self.src_channel_id(), Height::default()) + .query_channel(self.src_port_id(), src_channel_id, Height::default()) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?; // Retrieve the connection @@ -659,7 +679,7 @@ impl Channel { let proofs = self .src_chain() - .build_channel_proofs(self.src_port_id(), self.src_channel_id(), query_height) + .build_channel_proofs(self.src_port_id(), src_channel_id, query_height) .map_err(|e| ChannelError::Failed(format!("failed to build channel proofs: {}", e)))?; // Build message(s) to update client on destination @@ -677,7 +697,7 @@ impl Channel { // Build the domain type message let new_msg = MsgChannelOpenConfirm { port_id: self.dst_port_id().clone(), - channel_id: self.dst_channel_id().clone(), + channel_id: self.dst_channel_id().unwrap().clone(), proofs, signer, }; @@ -715,9 +735,12 @@ impl Channel { } pub fn build_chan_close_init(&self) -> Result, ChannelError> { + assert!(self.dst_channel_id().is_some()); + let dst_channel_id = self.dst_channel_id().unwrap(); + let _channel = self .dst_chain() - .query_channel(self.dst_port_id(), self.dst_channel_id(), Height::default()) + .query_channel(self.dst_port_id(), dst_channel_id, Height::default()) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; let signer = self.dst_chain().get_signer().map_err(|e| { @@ -731,7 +754,7 @@ impl Channel { // Build the domain type message let new_msg = MsgChannelCloseInit { port_id: self.dst_port_id().clone(), - channel_id: self.dst_channel_id().clone(), + channel_id: dst_channel_id.clone(), signer, }; @@ -772,9 +795,13 @@ impl Channel { let _dst_expected_channel = self.validated_expected_channel(ChannelMsgType::CloseConfirm)?; + assert!(self.src_channel_id().is_some()); + let src_channel_id = self.src_channel_id().unwrap(); + assert!(self.dst_channel_id().is_some()); + let _src_channel = self .src_chain() - .query_channel(self.src_port_id(), self.src_channel_id(), Height::default()) + .query_channel(self.src_port_id(), src_channel_id, Height::default()) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?; // Retrieve the connection @@ -790,7 +817,7 @@ impl Channel { let proofs = self .src_chain() - .build_channel_proofs(self.src_port_id(), self.src_channel_id(), query_height) + .build_channel_proofs(self.src_port_id(), src_channel_id, query_height) .map_err(|e| ChannelError::Failed(format!("failed to build channel proofs: {}", e)))?; // Build message(s) to update client on destination @@ -808,7 +835,7 @@ impl Channel { // Build the domain type message let new_msg = MsgChannelCloseConfirm { port_id: self.dst_port_id().clone(), - channel_id: self.dst_channel_id().clone(), + channel_id: self.dst_channel_id().unwrap().clone(), proofs, signer, }; diff --git a/relayer/src/link.rs b/relayer/src/link.rs index fd7e802315..94380973cf 100644 --- a/relayer/src/link.rs +++ b/relayer/src/link.rs @@ -250,12 +250,12 @@ impl RelayPath { &self.channel.dst_port_id() } - pub fn src_channel_id(&self) -> &ChannelId { - &self.channel.src_channel_id() + pub fn src_channel_id(&self) -> Option<&ChannelId> { + self.channel.src_channel_id() } - pub fn dst_channel_id(&self) -> &ChannelId { - &self.channel.dst_channel_id() + pub fn dst_channel_id(&self) -> Option<&ChannelId> { + self.channel.dst_channel_id() } pub fn channel(&self) -> &Channel { @@ -263,16 +263,18 @@ impl RelayPath { } fn src_channel(&self, height: Height) -> Result { + assert!(self.src_channel_id().is_some()); Ok(self .src_chain() - .query_channel(self.src_port_id(), self.src_channel_id(), height) + .query_channel(self.src_port_id(), self.src_channel_id().unwrap(), height) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?) } fn dst_channel(&self, height: Height) -> Result { + assert!(self.dst_channel_id().is_some()); Ok(self .dst_chain() - .query_channel(self.dst_port_id(), self.dst_channel_id(), height) + .query_channel(self.dst_port_id(), self.dst_channel_id().unwrap(), height) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?) } @@ -327,15 +329,17 @@ impl RelayPath { } fn build_chan_close_confirm_from_event(&self, event: &IbcEvent) -> Result { + assert!(self.src_channel_id().is_some()); + let src_channel_id = self.src_channel_id().unwrap(); let proofs = self .src_chain() - .build_channel_proofs(self.src_port_id(), self.src_channel_id(), event.height()) + .build_channel_proofs(self.src_port_id(), src_channel_id, event.height()) .map_err(|e| ChannelError::Failed(format!("failed to build channel proofs: {}", e)))?; // Build the domain type message let new_msg = MsgChannelCloseConfirm { port_id: self.dst_port_id().clone(), - channel_id: self.dst_channel_id().clone(), + channel_id: src_channel_id.clone(), proofs, signer: self.dst_signer()?, }; @@ -351,28 +355,29 @@ impl RelayPath { for event in events.iter() { match event { IbcEvent::SendPacket(send_packet_ev) => { - if self.src_channel_id() == &send_packet_ev.packet.source_channel + if self.src_channel_id() == Some(&send_packet_ev.packet.source_channel) && self.src_port_id() == &send_packet_ev.packet.source_port { result.push(event.clone()); } } IbcEvent::WriteAcknowledgement(write_ack_ev) => { - if self.channel.src_channel_id() == &write_ack_ev.packet.destination_channel + if self.channel.src_channel_id() + == Some(&write_ack_ev.packet.destination_channel) && self.channel.src_port_id() == &write_ack_ev.packet.destination_port { result.push(event.clone()); } } IbcEvent::CloseInitChannel(chan_close_ev) => { - if self.channel.src_channel_id() == chan_close_ev.channel_id() + if self.channel.src_channel_id() == Some(chan_close_ev.channel_id()) && self.channel.src_port_id() == chan_close_ev.port_id() { result.push(event.clone()); } } IbcEvent::TimeoutPacket(timeout_ev) => { - if self.channel.src_channel_id() == timeout_ev.src_channel_id() + if self.channel.src_channel_id() == Some(timeout_ev.src_channel_id()) && self.channel.src_port_id() == timeout_ev.src_port_id() { result.push(event.clone()); @@ -824,10 +829,13 @@ impl RelayPath { ) -> Result<(Vec, Height), LinkError> { let mut events_result = vec![]; + assert!(self.src_channel_id().is_some()); + let src_channel_id = self.src_channel_id().unwrap(); + // Query packet commitments on source chain that have not been acknowledged let pc_request = QueryPacketCommitmentsRequest { port_id: self.src_port_id().to_string(), - channel_id: self.src_channel_id().to_string(), + channel_id: src_channel_id.to_string(), pagination: ibc_proto::cosmos::base::query::pagination::all(), }; let (packet_commitments, src_response_height) = @@ -846,10 +854,13 @@ impl RelayPath { commit_sequences ); + assert!(self.src_channel_id().is_some()); + let dst_channel_id = self.dst_channel_id().unwrap(); + // Get the packets that have not been received on destination chain let request = QueryUnreceivedPacketsRequest { port_id: self.dst_port_id().to_string(), - channel_id: self.dst_channel_id().to_string(), + channel_id: dst_channel_id.to_string(), packet_commitment_sequences: commit_sequences, }; @@ -872,12 +883,15 @@ impl RelayPath { return Ok((events_result, query_height)); } + assert!(self.src_channel_id().is_some()); + assert!(self.dst_channel_id().is_some()); + let query = QueryTxRequest::Packet(QueryPacketEventDataRequest { event_id: IbcEventType::SendPacket, source_port_id: self.src_port_id().clone(), - source_channel_id: self.src_channel_id().clone(), + source_channel_id: self.src_channel_id().unwrap().clone(), destination_port_id: self.dst_port_id().clone(), - destination_channel_id: self.dst_channel_id().clone(), + destination_channel_id: self.dst_channel_id().unwrap().clone(), sequences, height: query_height, }); @@ -903,10 +917,15 @@ impl RelayPath { ) -> Result<(Vec, Height), LinkError> { let mut events_result = vec![]; + assert!(self.src_channel_id().is_some()); + let src_channel_id = self.src_channel_id().unwrap(); + assert!(self.dst_channel_id().is_some()); + let dst_channel_id = self.dst_channel_id().unwrap(); + // Get the sequences of packets that have been acknowledged on source let pc_request = QueryPacketAcknowledgementsRequest { port_id: self.src_port_id().to_string(), - channel_id: self.src_channel_id().to_string(), + channel_id: src_channel_id.to_string(), pagination: ibc_proto::cosmos::base::query::pagination::all(), }; let (acks_on_source, src_response_height) = self @@ -930,7 +949,7 @@ impl RelayPath { let request = QueryUnreceivedAcksRequest { port_id: self.dst_port_id().to_string(), - channel_id: self.dst_channel_id().to_string(), + channel_id: dst_channel_id.to_string(), packet_ack_sequences: acked_sequences, }; @@ -958,9 +977,9 @@ impl RelayPath { .query_txs(QueryTxRequest::Packet(QueryPacketEventDataRequest { event_id: IbcEventType::WriteAck, source_port_id: self.dst_port_id().clone(), - source_channel_id: self.dst_channel_id().clone(), + source_channel_id: dst_channel_id.clone(), destination_port_id: self.src_port_id().clone(), - destination_channel_id: self.src_channel_id().clone(), + destination_channel_id: src_channel_id.clone(), sequences, height: query_height, })) @@ -1056,12 +1075,15 @@ impl RelayPath { &self, event: &WriteAcknowledgement, ) -> Result, LinkError> { + assert!(self.src_channel_id().is_some()); + let dst_channel_id = self.dst_channel_id().unwrap(); + let packet = event.packet.clone(); let acked = self.dst_chain() .query_unreceived_acknowledgement(QueryUnreceivedAcksRequest { port_id: self.dst_port_id().to_string(), - channel_id: self.dst_channel_id().to_string(), + channel_id: dst_channel_id.to_string(), packet_ack_sequences: vec![packet.sequence.into()], })?; if acked.is_empty() { @@ -1101,12 +1123,15 @@ impl RelayPath { packet: &Packet, height: Height, ) -> Result, LinkError> { + assert!(self.src_channel_id().is_some()); + let dst_channel_id = self.dst_channel_id().unwrap(); + let (packet_type, next_sequence_received) = if self.ordered_channel() { let next_seq = self .dst_chain() .query_next_sequence_receive(QueryNextSequenceReceiveRequest { port_id: self.dst_port_id().to_string(), - channel_id: self.dst_channel_id().to_string(), + channel_id: dst_channel_id.to_string(), }) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; (PacketMsgType::TimeoutOrdered, next_seq) @@ -1115,7 +1140,7 @@ impl RelayPath { self.dst_chain() .query_unreceived_packets(QueryUnreceivedPacketsRequest { port_id: self.dst_port_id().to_string(), - channel_id: self.dst_channel_id().to_string(), + channel_id: dst_channel_id.to_string(), packet_commitment_sequences: vec![packet.sequence.into()], })?; if acked.is_empty() { @@ -1508,35 +1533,36 @@ impl Link { } pub fn is_closed(&self) -> Result { + assert!(self.a_to_b.src_channel_id().is_some()); + let a_channel_id = self.a_to_b.src_channel_id().unwrap(); + let a_channel = self .a_to_b .src_chain() - .query_channel( - self.a_to_b.src_port_id(), - self.a_to_b.src_channel_id(), - Height::default(), - ) + .query_channel(self.a_to_b.src_port_id(), a_channel_id, Height::default()) .map_err(|e| { LinkError::Failed(format!( "channel {} does not exist on chain {}; context={}", - self.a_to_b.src_channel_id(), + a_channel_id, self.a_to_b.src_chain().id(), e )) })?; + if self.a_to_b.dst_channel_id().is_none() { + return Ok(a_channel.state_matches(&ChannelState::Closed)); + } + + let b_channel_id = self.a_to_b.dst_channel_id().unwrap(); + let b_channel = self .a_to_b .dst_chain() - .query_channel( - self.a_to_b.dst_port_id(), - self.a_to_b.dst_channel_id(), - Height::default(), - ) + .query_channel(self.a_to_b.dst_port_id(), b_channel_id, Height::default()) .map_err(|e| { LinkError::Failed(format!( "channel {} does not exist on chain {}; context={}", - self.a_to_b.dst_channel_id(), + b_channel_id, self.a_to_b.dst_chain().id(), e )) @@ -1612,14 +1638,14 @@ impl Link { a_connection.client_id().clone(), a_connection_id, opts.src_port_id.clone(), - opts.src_channel_id.clone(), + Some(opts.src_channel_id.clone()), ), b_side: ChannelSide::new( b_chain, a_connection.counterparty().client_id().clone(), a_connection.counterparty().connection_id().unwrap().clone(), a_channel.counterparty().port_id.clone(), - b_channel_id, + Some(b_channel_id), ), connection_delay: a_connection.delay_period(), version: None, diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index 73ef709d08..e80ace9e59 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -984,7 +984,7 @@ impl Worker { connection.client_id().clone(), connection_id.clone(), port_id, - channel_id, + Some(channel_id), ), b_side: ChannelSide::new( b_chain.clone(), @@ -995,7 +995,7 @@ impl Worker { .unwrap() .clone(), counterparty_port_id.clone(), - counterparty_channel_id.clone(), + Some(counterparty_channel_id.clone()), ), connection_delay: connection.delay_period(), //TODO detect version from event @@ -1017,7 +1017,7 @@ impl Worker { } Ok(event) => { handshake_channel.b_side.channel_id = - extract_channel_id(&event)?.clone(); + Some(extract_channel_id(&event)?.clone()); println!( "{} {} => {:#?}\n", done, From 727f3b182b10973152ae80dfc7ba0be405ef8e11 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Mon, 10 May 2021 20:05:22 +0200 Subject: [PATCH 08/52] cleanup --- relayer/src/channel.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 9ec7f50e88..cac001f58a 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -538,7 +538,6 @@ impl Channel { } pub fn build_chan_open_try_and_send(&self) -> Result { - println!("\n SLEF {:#?}", self); let dst_msgs = self.build_chan_open_try()?; let events = self From 60c9124d97d51340269a1b39433fcf703d054677 Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Mon, 10 May 2021 21:15:55 +0200 Subject: [PATCH 09/52] event loop but no channelEnd to complete started handshakes --- relayer/src/supervisor.rs | 499 ++++++++++++++++++++++---------------- 1 file changed, 289 insertions(+), 210 deletions(-) diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index e80ace9e59..33c99c53f9 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -402,7 +402,7 @@ impl Supervisor { }); debug!( - "create workers: creating a worker for object {:?}", + "create workers: creating a worker for a channel object {:?}", channel_object ); @@ -410,6 +410,13 @@ impl Supervisor { } // end if channel not open else { + + + debug!( + "\n BABABABAABB + \n" + ); + // //start spawning channel worker let counterparty_chain_id = get_counterparty_chain_for_channel(chain.as_ref(), channel.clone()).unwrap(); @@ -425,7 +432,7 @@ impl Supervisor { }); debug!( - "create workers: creating a worker for object {:?}", + "create workers: creating a worker for a channel object that is not open {:?}", channel_object ); @@ -724,37 +731,6 @@ impl Worker { let a_chain = self.chains.a.clone(); let b_chain = self.chains.b.clone(); - // let a_channel = self.chains.a.query_channel( - // &channel.src_port_id, - // &channel.src_channel_id, - // Height::zero(), //height - 1 de la newBlock - // )?; - - // let connection_id = a_channel.connection_hops().first().ok_or_else(|| { - // Error::MissingConnectionHops(channel.src_channel_id.clone(), a_chain.id()) - // })?; - - // let connection = self - // .chains - // .a - // .query_connection(&connection_id, Height::zero())?; - - // let mut state = &ibc::ics04_channel::channel::State::Uninitialized; - - // let mut b_channel = Default::default(); - - // let counterparty_channel_id = if a_channel.remote.channel_id.is_none() { - // Default::default() - // } else { - // b_channel = self.chains.b.query_channel( - // &a_channel.remote.port_id.clone(), - // &a_channel.remote.channel_id.clone().unwrap(), - // Height::zero(), - // )?; - // state = &b_channel.state; - // a_channel.remote.channel_id.clone().unwrap() - // }; - let mut handshake_channel = RelayChannel { ordering: Default::default(), //TODO how to get the order from raw tx @@ -763,180 +739,25 @@ impl Worker { Default::default(), Default::default(), Default::default(), - Default::default(), + None, ), b_side: ChannelSide::new( b_chain.clone(), Default::default(), Default::default(), Default::default(), - Default::default(), + None, ), connection_delay: Default::default(), //TODO detect version from event version: Default::default(), }; - // let mut handshake_channel = RelayChannel { - // ordering: a_channel.ordering().clone(), - // a_side: ChannelSide::new( - // a_chain.clone(), - // connection.client_id().clone(), - // connection_id.clone(), - // channel.src_port_id.clone(), - // channel.src_channel_id.clone(), - // ), - // b_side: ChannelSide::new( - // b_chain.clone(), - // connection.counterparty().client_id().clone(), - // connection.counterparty().connection_id().unwrap().clone(), - // a_channel.remote.port_id.clone(), - // counterparty_channel_id.clone(), - // ), - // connection_delay: connection.delay_period(), - // version: Some(a_channel.version.clone()), - // }; - - // let mut stage = 0; //Nothing started - // let mut found = false; - - // debug!( - // "\n [{}] initial handshake_channel is {:?} \n ", - // channel.short_name(), - // handshake_channel - // ); - - //c0 ibc0 Init ? // -> OpenTry ibc1 -> create c1 ibc1 -->> - - //chan_open_init ibc1 => c1 - //c0 ibc0 OpenTry ? <- chan_open_try c1 ibc-1 dest c0 ibc 0 --> new channel - - // if a_channel.state_matches(&ibc::ics04_channel::channel::State::Init) { - // if a_channel.remote.channel_id.is_none() { - // let req = QueryChannelsRequest { - // pagination: ibc_proto::cosmos::base::query::pagination::all(), - // }; - - // let channels: Vec = b_chain.query_channels(req.clone())?; - // for chan in channels.iter() { - // if chan.channel_end.remote.channel_id.is_some() - // && chan.channel_end.remote.channel_id.clone().unwrap() - // == channel.src_channel_id.clone() - // { - // debug!( - // "[{}] found a pair channel {} on chain {}", - // channel.short_name(), - // chan.channel_id, - // handshake_channel.b_side.chain_id() - // ); - // found = true; - // handshake_channel.b_side.channel_id = chan.channel_id.clone(); - - // break; - // } - // } - // stage = 1; // channel in Init - - // if !found { - // println!( - // "\n [{}] sends build_chan_open_try_and_send \n on handshake_channel {:?} channel in state Init \n", - // channel.short_name(), - // handshake_channel - // ); - - // match handshake_channel.build_chan_open_try_and_send() { - // Err(e) => { - // debug!("Failed ChanTry {:?}: {:?}", handshake_channel.b_side, e); - // } - // Ok(event) => { - // println!("{} {} => {:#?}\n", done, b_chain.id(), event); - // } - // } - // } - // } - // } else { - // if a_channel.state_matches(&ibc::ics04_channel::channel::State::TryOpen) { - // stage = 2; //channel is in Try Open - - // if a_channel.remote.channel_id.is_some() { - // //Try chanOpenTry on b_chain - // debug!("[{}] chain {} has channel {} in state TryOpen with counterparty {} in state {} \n", channel.short_name(), a_chain.id(), channel.src_channel_id.clone(), counterparty_channel_id.clone(), state); - - // if !b_channel.state_matches(&ibc::ics04_channel::channel::State::Open) { - // debug!( - // "\n [{}] sends build_chan_open_ack_and_send \n on handshake_channel {:?}", - // channel.short_name(),handshake_channel); - - // match handshake_channel.build_chan_open_ack_and_send() { - // Err(e) => { - // debug!("Failed ChanAck {:?}: {:?}", handshake_channel.b_side, e); - // } - // Ok(event) => { - // // handshake_channel.b_side.channel_id = extract_channel_id(&event)?.clone(); - // println!("{} {} => {:#?}\n", done, b_chain.id(), event); - // } - // } - // } //TODO else either counter party channel is more advanced or another channel closed the hanshake - // } //TODO else error - // } else { - // match (a_channel.state().clone(), state) { - // ( - // ibc::ics04_channel::channel::State::Open, - // ibc::ics04_channel::channel::State::TryOpen, - // ) => { - // stage = 3; // channel is Open - // debug!( - // "[{}] chain {} has channel {} in state Open counterparty TryOpen \n", - // channel.short_name(), - // a_chain.id(), - // channel.src_channel_id.clone() - // ); - - // // Confirm to b_chain - // debug!( - // "[{}] sends build_chan_open_confirm_and_send \n on handshake_channel {:?}", - // channel.short_name(), - // handshake_channel - // ); - - // match handshake_channel.build_chan_open_confirm_and_send() { - // Err(e) => { - // debug!( - // "Failed OpenConfirm {:?}: {:?}", - // handshake_channel.b_side, e - // ); - // } - // Ok(event) => { - // println!("{} {} => {:#?}\n", done, b_chain.id(), event); - // } - // } - // } - // ( - // ibc::ics04_channel::channel::State::Open, - // ibc::ics04_channel::channel::State::Open, - // ) => { - // // stage = 3; //Channel is Open - // println!( - // "[{}]{} {} {} Channel handshake finished for {:#?}\n", - // channel.short_name(), - // done, - // done, - // done, - // &channel.src_channel_id, - // ); - // return Ok(()); - // } - // _ => { - // debug!( - // "[{}] \n Error Unimplemented handshake case \n", - // channel.short_name() - // ) - // } - // } - // } - // }; + debug!("[{}] started ", channel.short_name()); + let mut first_iteration = true; + loop { if let Ok(cmd) = self.rx.try_recv() { //Ok(WorkerCmd::IbcEvents { batch }) @@ -960,21 +781,14 @@ impl Worker { .chains .a .query_connection(&connection_id.clone(), Height::zero())?; - let counterparty_channel_id = match open_init + let counterparty_channel_id = open_init .attributes() .counterparty_channel_id - .clone() - { - Some(chan_id) => chan_id, - None => Default::default(), - }; + .clone(); + let port_id = open_init.attributes().port_id.clone(); - let channel_id = match open_init.attributes().channel_id.clone() - { - Some(chan_id) => chan_id, - None => Default::default(), - //TODO err - }; + let channel_id = open_init.attributes().channel_id.clone(); + handshake_channel = RelayChannel { ordering: Default::default(), @@ -984,7 +798,7 @@ impl Worker { connection.client_id().clone(), connection_id.clone(), port_id, - Some(channel_id), + channel_id, ), b_side: ChannelSide::new( b_chain.clone(), @@ -995,7 +809,7 @@ impl Worker { .unwrap() .clone(), counterparty_port_id.clone(), - Some(counterparty_channel_id.clone()), + counterparty_channel_id.clone(), ), connection_delay: connection.delay_period(), //TODO detect version from event @@ -1037,6 +851,50 @@ impl Worker { open_try ); + let connection_id = + open_try.attributes().connection_id.clone(); + let counterparty_port_id = + open_try.attributes().counterparty_port_id.clone(); + let connection = self + .chains + .a + .query_connection(&connection_id.clone(), Height::zero())?; + let counterparty_channel_id = open_try + .attributes() + .counterparty_channel_id + .clone(); + + let port_id = open_try.attributes().port_id.clone(); + let channel_id = open_try.attributes().channel_id.clone(); + + + handshake_channel = RelayChannel { + ordering: Default::default(), + //TODO how to get the order from raw tx + a_side: ChannelSide::new( + a_chain.clone(), + connection.client_id().clone(), + connection_id.clone(), + port_id, + channel_id, + ), + b_side: ChannelSide::new( + b_chain.clone(), + connection.counterparty().client_id().clone(), + connection + .counterparty() + .connection_id() + .unwrap() + .clone(), + counterparty_port_id.clone(), + counterparty_channel_id.clone(), + ), + connection_delay: connection.delay_period(), + //TODO detect version from event + version: Default::default(), + }; + + debug!( "[{}] sends build_chan_open_ack_and_send \n on handshake_channel {:?}", channel.short_name(), @@ -1080,8 +938,9 @@ impl Worker { // //handshake_channel.b_side.channel_id // ); - // handshake_channel.b_side.channel_id = - // open_ack.counterparty_channel_id().clone().unwrap(); + if handshake_channel.b_side.channel_id.is_none() { + handshake_channel.b_side.channel_id = open_ack.counterparty_channel_id().clone(); + } // debug!( // "[{}] writting b_side after open_confirm {} ", @@ -1128,11 +987,231 @@ impl Worker { } WorkerCmd::NewBlock { - height: _, + height: current_height, new_block: _, } => { if first_iteration { debug!("\n [{}] new block \n ", channel.short_name()); + + let height = current_height.decrement()?; + + let a_channel = self.chains.a.query_channel( + &channel.src_port_id, + &channel.src_channel_id, + height, //height - 1 de la newBlock + )?; + + let connection_id = + a_channel.connection_hops().first().ok_or_else(|| { + Error::MissingConnectionHops( + channel.src_channel_id.clone(), + a_chain.id(), + ) + })?; + + let connection = self + .chains + .a + .query_connection(&connection_id, Height::zero())?; + + let mut state = &ibc::ics04_channel::channel::State::Uninitialized; + + let mut b_channel = Default::default(); + + let counterparty_channel_id = if a_channel.remote.channel_id.is_none() { + None + } else { + b_channel = self.chains.b.query_channel( + &a_channel.remote.port_id.clone(), + &a_channel.remote.channel_id.clone().unwrap(), + Height::zero(), + )?; + state = &b_channel.state; + a_channel.remote.channel_id.clone() + }; + + let mut handshake_channel = RelayChannel { + ordering: a_channel.ordering().clone(), + a_side: ChannelSide::new( + a_chain.clone(), + connection.client_id().clone(), + connection_id.clone(), + channel.src_port_id.clone(), + Some(channel.src_channel_id.clone()), + ), + b_side: ChannelSide::new( + b_chain.clone(), + connection.counterparty().client_id().clone(), + connection.counterparty().connection_id().unwrap().clone(), + a_channel.remote.port_id.clone(), + counterparty_channel_id.clone(), + ), + connection_delay: connection.delay_period(), + version: Some(a_channel.version.clone()), + }; + + let mut found_counterparty = false; + + debug!( + "\n [{}] initial handshake_channel is {:?} \n ", + channel.short_name(), + handshake_channel + ); + + if a_channel.state_matches(&ibc::ics04_channel::channel::State::Init) { + if a_channel.remote.channel_id.is_none() { + let req = QueryChannelsRequest { + pagination: ibc_proto::cosmos::base::query::pagination::all( + ), + }; + + let channels: Vec = + b_chain.query_channels(req.clone())?; + for chan in channels.iter() { + if chan.channel_end.remote.channel_id.is_some() + && chan.channel_end.remote.channel_id.clone().unwrap() + == channel.src_channel_id.clone() + { + debug!( + "[{}] found a pair channel {} on chain {}", + channel.short_name(), + chan.channel_id, + handshake_channel.b_side.chain_id() + ); + found_counterparty = true; + handshake_channel.b_side.channel_id = + Some(chan.channel_id.clone()); + + break; + } + } + // stage = 1; // channel in Init + + if !found_counterparty { + println!( + "\n [{}] sends build_chan_open_try_and_send \n on handshake_channel {:?} channel in state Init \n", + channel.short_name(), + handshake_channel + ); + + match handshake_channel.build_chan_open_try_and_send() { + Err(e) => { + debug!( + "Failed ChanTry {:?}: {:?}", + handshake_channel.b_side, e + ); + } + Ok(event) => { + println!( + "{} {} => {:#?}\n", + done, + b_chain.id(), + event + ); + } + } + } + } + } else { + if a_channel + .state_matches(&ibc::ics04_channel::channel::State::TryOpen) + { + // stage = 2; //channel is in Try Open + + if a_channel.remote.channel_id.is_some() { + //Try chanOpenTry on b_chain + //debug!("[{}] chain {} has channel {} in state TryOpen with counterparty {} in state {} \n", channel.short_name(), a_chain.id(), channel.src_channel_id.clone(), counterparty_channel_id.clone(), state); + + if !b_channel.state_matches( + &ibc::ics04_channel::channel::State::Open, + ) { + debug!( + "\n [{}] sends build_chan_open_ack_and_send \n on handshake_channel {:?}", + channel.short_name(),handshake_channel); + + match handshake_channel.build_chan_open_ack_and_send() { + Err(e) => { + debug!( + "Failed ChanAck {:?}: {:?}", + handshake_channel.b_side, e + ); + } + Ok(event) => { + handshake_channel.b_side.channel_id = Some(extract_channel_id(&event)?.clone()); + println!( + "{} {} => {:#?}\n", + done, + b_chain.id(), + event + ); + } + } + } //TODO else either counter party channel is more advanced or another channel closed the hanshake + } //TODO else error + } else { + match (a_channel.state().clone(), state) { + ( + ibc::ics04_channel::channel::State::Open, + ibc::ics04_channel::channel::State::TryOpen, + ) => { + //stage = 3; // channel is Open + debug!( + "[{}] chain {} has channel {} in state Open counterparty TryOpen \n", + channel.short_name(), + a_chain.id(), + channel.src_channel_id.clone() + ); + + // Confirm to b_chain + debug!( + "[{}] sends build_chan_open_confirm_and_send \n on handshake_channel {:?}", + channel.short_name(), + handshake_channel + ); + + match handshake_channel + .build_chan_open_confirm_and_send() + { + Err(e) => { + debug!( + "Failed OpenConfirm {:?}: {:?}", + handshake_channel.b_side, e + ); + } + Ok(event) => { + println!( + "{} {} => {:#?}\n", + done, + b_chain.id(), + event + ); + } + } + } + ( + ibc::ics04_channel::channel::State::Open, + ibc::ics04_channel::channel::State::Open, + ) => { + // stage = 3; //Channel is Open + println!( + "[{}]{} {} {} Channel handshake finished for {:#?}\n", + channel.short_name(), + done, + done, + done, + &channel.src_channel_id, + ); + return Ok(()); + } + _ => { + debug!( + "[{}] \n Error Unimplemented handshake case \n", + channel.short_name() + ) + } + } + } + }; } } //link.a_to_b.clear_packets(height)?, From 478041b886d643e749ccd57903342ff0d7e2385a Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Tue, 11 May 2021 10:52:14 +0200 Subject: [PATCH 10/52] handshake channel --- relayer/src/chain/handle.rs | 6 + relayer/src/supervisor.rs | 224 ++++++++++++++++-------------------- 2 files changed, 105 insertions(+), 125 deletions(-) diff --git a/relayer/src/chain/handle.rs b/relayer/src/chain/handle.rs index ef8befd12d..2ba9455ce8 100644 --- a/relayer/src/chain/handle.rs +++ b/relayer/src/chain/handle.rs @@ -296,6 +296,12 @@ pub trait ChainHandle: DynClone + Send + Sync + Debug { height: Height, ) -> Result; + // fn query_connection_channels( + // &self, + // connection_id: &ConnectionId, + // height: Height, + // ) -> Result, Error>; + fn query_next_sequence_receive( &self, request: QueryNextSequenceReceiveRequest, diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index 33c99c53f9..b54de2770a 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -24,7 +24,7 @@ use ibc::{ Height, }; -use ibc_proto::ibc::core::channel::v1::QueryChannelsRequest; +use ibc_proto::ibc::core::channel::v1::{QueryChannelsRequest, QueryConnectionChannelsRequest}; use crate::channel::extract_channel_id; use crate::channel::Channel as RelayChannel; @@ -410,8 +410,6 @@ impl Supervisor { } // end if channel not open else { - - debug!( "\n BABABABAABB \n" @@ -755,7 +753,6 @@ impl Worker { debug!("[{}] started ", channel.short_name()); - let mut first_iteration = true; loop { @@ -781,14 +778,11 @@ impl Worker { .chains .a .query_connection(&connection_id.clone(), Height::zero())?; - let counterparty_channel_id = open_init - .attributes() - .counterparty_channel_id - .clone(); - + let counterparty_channel_id = + open_init.attributes().counterparty_channel_id.clone(); + let port_id = open_init.attributes().port_id.clone(); let channel_id = open_init.attributes().channel_id.clone(); - handshake_channel = RelayChannel { ordering: Default::default(), @@ -851,22 +845,18 @@ impl Worker { open_try ); - let connection_id = - open_try.attributes().connection_id.clone(); + let connection_id = open_try.attributes().connection_id.clone(); let counterparty_port_id = open_try.attributes().counterparty_port_id.clone(); let connection = self .chains .a .query_connection(&connection_id.clone(), Height::zero())?; - let counterparty_channel_id = open_try - .attributes() - .counterparty_channel_id - .clone(); - + let counterparty_channel_id = + open_try.attributes().counterparty_channel_id.clone(); + let port_id = open_try.attributes().port_id.clone(); let channel_id = open_try.attributes().channel_id.clone(); - handshake_channel = RelayChannel { ordering: Default::default(), @@ -894,7 +884,6 @@ impl Worker { version: Default::default(), }; - debug!( "[{}] sends build_chan_open_ack_and_send \n on handshake_channel {:?}", channel.short_name(), @@ -931,29 +920,18 @@ impl Worker { open_ack.channel_id().clone().unwrap() ); - //if stage == 1 && !found { - // debug!( - // "[{}] writting b_side before open_confirm ", - // channel.short_name(), - // //handshake_channel.b_side.channel_id - // ); if handshake_channel.b_side.channel_id.is_none() { - handshake_channel.b_side.channel_id = open_ack.counterparty_channel_id().clone(); + handshake_channel.b_side.channel_id = + open_ack.counterparty_channel_id().clone(); } - // debug!( - // "[{}] writting b_side after open_confirm {} ", - // channel.short_name(), - // handshake_channel.b_side.channel_id - // ); - // } - - // debug!( - // "[{}] hanshake_channel b_side channel id is {}", - // channel.short_name(), - // handshake_channel.b_side.channel_id() - // ); + debug!( + "[{}] writting b_side before open_confirm {} ", + channel.short_name(), + handshake_channel.b_side.channel_id.clone().unwrap() + ); + let event = handshake_channel.build_chan_open_confirm_and_send()?; @@ -963,20 +941,12 @@ impl Worker { } IbcEvent::OpenConfirmChannel(_open_confirm) => { - // debug!("[{}] {} channel handshake OpenConfirm [{}] channel from event OpenConfirm {} ", - // channel.short_name(), - // handshake_channel.a_side.channel_id(), - // handshake_channel.a_side.chain_id(), - // open_confirm.channel_id().clone().unwrap() - // ); println!( "{} {} {} Channel handshake finished for {:#?}\n", done, done, done, &channel.src_channel_id, ); - // first_iteration = false; - return Ok(()); } IbcEvent::CloseInitChannel(_) => {} @@ -985,7 +955,6 @@ impl Worker { } } } - WorkerCmd::NewBlock { height: current_height, new_block: _, @@ -998,7 +967,7 @@ impl Worker { let a_channel = self.chains.a.query_channel( &channel.src_port_id, &channel.src_channel_id, - height, //height - 1 de la newBlock + height, )?; let connection_id = @@ -1014,7 +983,7 @@ impl Worker { .a .query_connection(&connection_id, Height::zero())?; - let mut state = &ibc::ics04_channel::channel::State::Uninitialized; + let mut counterparty_state = &ibc::ics04_channel::channel::State::Uninitialized; let mut b_channel = Default::default(); @@ -1026,11 +995,11 @@ impl Worker { &a_channel.remote.channel_id.clone().unwrap(), Height::zero(), )?; - state = &b_channel.state; + counterparty_state = &b_channel.state; a_channel.remote.channel_id.clone() }; - let mut handshake_channel = RelayChannel { + handshake_channel = RelayChannel { ordering: a_channel.ordering().clone(), a_side: ChannelSide::new( a_chain.clone(), @@ -1050,6 +1019,8 @@ impl Worker { version: Some(a_channel.version.clone()), }; + debug!("\n[{}] the Init handshake from new block is {:?} \n ", channel.short_name(), handshake_channel); + let mut found_counterparty = false; debug!( @@ -1058,70 +1029,78 @@ impl Worker { handshake_channel ); - if a_channel.state_matches(&ibc::ics04_channel::channel::State::Init) { - if a_channel.remote.channel_id.is_none() { - let req = QueryChannelsRequest { - pagination: ibc_proto::cosmos::base::query::pagination::all( - ), - }; - - let channels: Vec = - b_chain.query_channels(req.clone())?; - for chan in channels.iter() { - if chan.channel_end.remote.channel_id.is_some() - && chan.channel_end.remote.channel_id.clone().unwrap() - == channel.src_channel_id.clone() - { - debug!( - "[{}] found a pair channel {} on chain {}", - channel.short_name(), - chan.channel_id, - handshake_channel.b_side.chain_id() - ); - found_counterparty = true; - handshake_channel.b_side.channel_id = - Some(chan.channel_id.clone()); + match a_channel.state { + ibc::ics04_channel::channel::State::Init => { + if a_channel.remote.channel_id.is_none() { + // let req = QueryConnectionChannelsRequest { + // connection: connection_id.to_string(), + // pagination: + // ibc_proto::cosmos::base::query::pagination::all(), + // }; + + // let channels: Vec = + // b_chain.query_connection_channels(req.clone())?; + let req = QueryChannelsRequest { + pagination: + ibc_proto::cosmos::base::query::pagination::all(), + }; + + let channels: Vec = + b_chain.query_channels(req.clone())?; + for chan in channels.iter() { + if chan.channel_end.remote.channel_id.is_some() + && chan + .channel_end + .remote + .channel_id + .clone() + .unwrap() + == channel.src_channel_id.clone() + { + debug!( + "[{}] found a pair channel {} on chain {}", + channel.short_name(), + chan.channel_id, + handshake_channel.b_side.chain_id() + ); + found_counterparty = true; + handshake_channel.b_side.channel_id = + Some(chan.channel_id.clone()); - break; + break; + } } - } - // stage = 1; // channel in Init - if !found_counterparty { - println!( - "\n [{}] sends build_chan_open_try_and_send \n on handshake_channel {:?} channel in state Init \n", - channel.short_name(), - handshake_channel - ); + if !found_counterparty { + println!( + "\n [{}] sends build_chan_open_try_and_send \n on handshake_channel {:?} channel in state Init \n", + channel.short_name(), + handshake_channel + ); - match handshake_channel.build_chan_open_try_and_send() { - Err(e) => { - debug!( - "Failed ChanTry {:?}: {:?}", - handshake_channel.b_side, e - ); - } - Ok(event) => { - println!( - "{} {} => {:#?}\n", - done, - b_chain.id(), - event - ); + match handshake_channel.build_chan_open_try_and_send() { + Err(e) => { + debug!( + "Failed ChanTry {:?}: {:?}", + handshake_channel.b_side, e + ); + } + Ok(event) => { + println!( + "{} {} => {:#?}\n", + done, + b_chain.id(), + event + ); + } } } } } - } else { - if a_channel - .state_matches(&ibc::ics04_channel::channel::State::TryOpen) - { - // stage = 2; //channel is in Try Open + ibc::ics04_channel::channel::State::TryOpen => { if a_channel.remote.channel_id.is_some() { - //Try chanOpenTry on b_chain - //debug!("[{}] chain {} has channel {} in state TryOpen with counterparty {} in state {} \n", channel.short_name(), a_chain.id(), channel.src_channel_id.clone(), counterparty_channel_id.clone(), state); - + if !b_channel.state_matches( &ibc::ics04_channel::channel::State::Open, ) { @@ -1137,7 +1116,8 @@ impl Worker { ); } Ok(event) => { - handshake_channel.b_side.channel_id = Some(extract_channel_id(&event)?.clone()); + handshake_channel.b_side.channel_id = + Some(extract_channel_id(&event)?.clone()); println!( "{} {} => {:#?}\n", done, @@ -1148,13 +1128,10 @@ impl Worker { } } //TODO else either counter party channel is more advanced or another channel closed the hanshake } //TODO else error - } else { - match (a_channel.state().clone(), state) { - ( - ibc::ics04_channel::channel::State::Open, - ibc::ics04_channel::channel::State::TryOpen, - ) => { - //stage = 3; // channel is Open + } + ibc::ics04_channel::channel::State::Open => { + match counterparty_state { + ibc::ics04_channel::channel::State::TryOpen => { debug!( "[{}] chain {} has channel {} in state Open counterparty TryOpen \n", channel.short_name(), @@ -1188,11 +1165,7 @@ impl Worker { } } } - ( - ibc::ics04_channel::channel::State::Open, - ibc::ics04_channel::channel::State::Open, - ) => { - // stage = 3; //Channel is Open + ibc::ics04_channel::channel::State::Open => { println!( "[{}]{} {} {} Channel handshake finished for {:#?}\n", channel.short_name(), @@ -1210,13 +1183,14 @@ impl Worker { ) } } - } - }; - } - } //link.a_to_b.clear_packets(height)?, + } //end a_channel OPEN - // _ => {} - } + _ => {} //TODO Uninit and Close + } //end match a_state + first_iteration = false; + } //end first iteration + } //end worker end block cmd + }; } } } @@ -1318,7 +1292,7 @@ impl Object { match self { Object::UnidirectionalChannelPath(p) => p.src_chain_id == *src_chain_id, Object::Client(_) => false, - Object::Channel(_) => false, + Object::Channel(c) => c.src_chain_id == *src_chain_id, } } } From 306f501c767f1b71d732dc63b79d4f1624a35edc Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Tue, 11 May 2021 11:15:25 +0200 Subject: [PATCH 11/52] added query_connection_channels --- relayer/src/chain.rs | 2 +- relayer/src/chain/cosmos.rs | 18 +++++++++++++----- relayer/src/chain/handle.rs | 16 ++++++++++------ relayer/src/chain/handle/prod.rs | 9 ++++++++- relayer/src/chain/mock.rs | 2 +- relayer/src/chain/runtime.rs | 21 ++++++++++++++++++++- relayer/src/supervisor.rs | 14 ++++---------- 7 files changed, 57 insertions(+), 25 deletions(-) diff --git a/relayer/src/chain.rs b/relayer/src/chain.rs index d4c859b0c8..9e20b3b77c 100644 --- a/relayer/src/chain.rs +++ b/relayer/src/chain.rs @@ -177,7 +177,7 @@ pub trait Chain: Sized { fn query_connection_channels( &self, request: QueryConnectionChannelsRequest, - ) -> Result, Error>; + ) -> Result, Error>; /// Performs a query to retrieve the identifiers of all channels. fn query_channels( diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index d8c8731e56..9359cbe6b5 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -749,7 +749,7 @@ impl Chain for CosmosSdkChain { fn query_connection_channels( &self, request: QueryConnectionChannelsRequest, - ) -> Result, Error> { + ) -> Result, Error> { crate::time!("query_connection_channels"); let mut client = self @@ -770,13 +770,21 @@ impl Chain for CosmosSdkChain { // TODO: add warnings for any identifiers that fail to parse (below). // https://github.com/informalsystems/ibc-rs/pull/506#discussion_r555945560 - let vec_ids = response + + let channels = response .channels - .iter() - .filter_map(|ic| ChannelId::from_str(ic.channel_id.as_str()).ok()) + .into_iter() + .filter_map(|ch| IdentifiedChannelEnd::try_from(ch).ok()) .collect(); + Ok(channels) + + // let vec_ids = response + // .channels + // .iter() + // .filter_map(|ic| ChannelId::from_str(ic.channel_id.as_str()).ok()) + // .collect(); - Ok(vec_ids) + // Ok(vec_ids) } fn query_channels( diff --git a/relayer/src/chain/handle.rs b/relayer/src/chain/handle.rs index 2ba9455ce8..ce242f9139 100644 --- a/relayer/src/chain/handle.rs +++ b/relayer/src/chain/handle.rs @@ -26,7 +26,7 @@ use ibc::{ Height, }; use ibc_proto::ibc::core::channel::v1::{ - PacketState, QueryChannelsRequest, QueryNextSequenceReceiveRequest, + PacketState, QueryChannelsRequest,QueryConnectionChannelsRequest, QueryNextSequenceReceiveRequest, QueryPacketAcknowledgementsRequest, QueryPacketCommitmentsRequest, QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest, }; @@ -166,6 +166,11 @@ pub enum ChainRequest { reply_to: ReplyTo>, }, + QueryConnectionChannels { + request: QueryConnectionChannelsRequest, + reply_to: ReplyTo>, + }, + QueryChannel { port_id: PortId, channel_id: ChannelId, @@ -296,11 +301,10 @@ pub trait ChainHandle: DynClone + Send + Sync + Debug { height: Height, ) -> Result; - // fn query_connection_channels( - // &self, - // connection_id: &ConnectionId, - // height: Height, - // ) -> Result, Error>; + fn query_connection_channels( + &self, + request: QueryConnectionChannelsRequest, + ) -> Result, Error>; fn query_next_sequence_receive( &self, diff --git a/relayer/src/chain/handle/prod.rs b/relayer/src/chain/handle/prod.rs index c5bb7dc809..88ed88a865 100644 --- a/relayer/src/chain/handle/prod.rs +++ b/relayer/src/chain/handle/prod.rs @@ -24,7 +24,7 @@ use ibc::{ Height, }; use ibc_proto::ibc::core::channel::v1::{ - PacketState, QueryChannelsRequest, QueryNextSequenceReceiveRequest, + PacketState, QueryChannelsRequest, QueryConnectionChannelsRequest, QueryNextSequenceReceiveRequest, QueryPacketAcknowledgementsRequest, QueryPacketCommitmentsRequest, QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest, }; @@ -188,6 +188,13 @@ impl ChainHandle for ProdChainHandle { self.send(|reply_to| ChainRequest::QueryChannels { request, reply_to }) } + fn query_connection_channels( + &self, + request: QueryConnectionChannelsRequest, + ) -> Result, Error> { + self.send(|reply_to| ChainRequest::QueryConnectionChannels { request, reply_to }) + } + fn query_channel( &self, port_id: &PortId, diff --git a/relayer/src/chain/mock.rs b/relayer/src/chain/mock.rs index 486feebcb4..835c0d0ef0 100644 --- a/relayer/src/chain/mock.rs +++ b/relayer/src/chain/mock.rs @@ -177,7 +177,7 @@ impl Chain for MockChain { fn query_connection_channels( &self, _request: QueryConnectionChannelsRequest, - ) -> Result, Error> { + ) -> Result, Error> { unimplemented!() } diff --git a/relayer/src/chain/runtime.rs b/relayer/src/chain/runtime.rs index baeced739e..c5b821ef50 100644 --- a/relayer/src/chain/runtime.rs +++ b/relayer/src/chain/runtime.rs @@ -29,7 +29,7 @@ use ibc::{ use ibc_proto::ibc::core::{ channel::v1::{ - PacketState, QueryChannelsRequest, QueryNextSequenceReceiveRequest, + PacketState, QueryChannelsRequest, QueryConnectionChannelsRequest, QueryNextSequenceReceiveRequest, QueryPacketAcknowledgementsRequest, QueryPacketCommitmentsRequest, QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest, }, @@ -264,6 +264,10 @@ impl ChainRuntime { self.query_channels(request, reply_to)? }, + Ok(ChainRequest::QueryConnectionChannels { request, reply_to }) => { + self.query_connection_channels(request, reply_to)? + }, + Ok(ChainRequest::QueryChannel { port_id, channel_id, height, reply_to }) => { self.query_channel(port_id, channel_id, height, reply_to)? }, @@ -620,6 +624,21 @@ impl ChainRuntime { Ok(()) } + fn query_connection_channels( + &self, + request: QueryConnectionChannelsRequest, + reply_to: ReplyTo>, + ) -> Result<(), Error> { + + let result = self.chain.query_connection_channels(request); + + reply_to + .send(result) + .map_err(|e| Kind::Channel.context(e))?; + + Ok(()) + } + fn query_channels( &self, request: QueryChannelsRequest, diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index b54de2770a..89ededf999 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -1032,21 +1032,15 @@ impl Worker { match a_channel.state { ibc::ics04_channel::channel::State::Init => { if a_channel.remote.channel_id.is_none() { - // let req = QueryConnectionChannelsRequest { - // connection: connection_id.to_string(), - // pagination: - // ibc_proto::cosmos::base::query::pagination::all(), - // }; - - // let channels: Vec = - // b_chain.query_connection_channels(req.clone())?; - let req = QueryChannelsRequest { + let req = QueryConnectionChannelsRequest { + connection: connection_id.to_string(), pagination: ibc_proto::cosmos::base::query::pagination::all(), }; let channels: Vec = - b_chain.query_channels(req.clone())?; + b_chain.query_connection_channels(req.clone())?; + for chan in channels.iter() { if chan.channel_end.remote.channel_id.is_some() && chan From c30ea38a6531f331508f7732e9741208277fd8d4 Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Tue, 11 May 2021 11:18:55 +0200 Subject: [PATCH 12/52] Update supervisor.rs --- relayer/src/supervisor.rs | 66 +++++---------------------------------- 1 file changed, 7 insertions(+), 59 deletions(-) diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index 89ededf999..f2e5a85ac6 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -757,19 +757,13 @@ impl Worker { loop { if let Ok(cmd) = self.rx.try_recv() { - //Ok(WorkerCmd::IbcEvents { batch }) - // Ok(cmd) match cmd { WorkerCmd::IbcEvents { batch } => { for event in batch.events { match event { IbcEvent::OpenInitChannel(open_init) => { - debug!( - "\n [{}] Calling Open Init from the loop {:?}\n ", - channel.short_name(), - open_init.clone() - ); - + + //Create channel handshake object let connection_id = open_init.attributes().connection_id.clone(); let counterparty_port_id = @@ -845,6 +839,7 @@ impl Worker { open_try ); + //Create channel handshake object let connection_id = open_try.attributes().connection_id.clone(); let counterparty_port_id = open_try.attributes().counterparty_port_id.clone(); @@ -884,11 +879,7 @@ impl Worker { version: Default::default(), }; - debug!( - "[{}] sends build_chan_open_ack_and_send \n on handshake_channel {:?}", - channel.short_name(), - handshake_channel - ); + match handshake_channel.build_chan_open_ack_and_send() { Err(e) => { @@ -912,27 +903,12 @@ impl Worker { } IbcEvent::OpenAckChannel(open_ack) => { - debug!( - " \n [{}] channel handshake OpenAck from channel {} \n", - channel.short_name(), - //handshake_channel.a_side.channel_id(), - //handshake_channel.a_side.chain_id(), - open_ack.channel_id().clone().unwrap() - ); - - + if handshake_channel.b_side.channel_id.is_none() { handshake_channel.b_side.channel_id = open_ack.counterparty_channel_id().clone(); } - debug!( - "[{}] writting b_side before open_confirm {} ", - channel.short_name(), - handshake_channel.b_side.channel_id.clone().unwrap() - ); - - let event = handshake_channel.build_chan_open_confirm_and_send()?; println!("{} {} => {:#?}\n", done, b_chain.id(), event); @@ -1019,16 +995,8 @@ impl Worker { version: Some(a_channel.version.clone()), }; - debug!("\n[{}] the Init handshake from new block is {:?} \n ", channel.short_name(), handshake_channel); - let mut found_counterparty = false; - debug!( - "\n [{}] initial handshake_channel is {:?} \n ", - channel.short_name(), - handshake_channel - ); - match a_channel.state { ibc::ics04_channel::channel::State::Init => { if a_channel.remote.channel_id.is_none() { @@ -1066,11 +1034,7 @@ impl Worker { } if !found_counterparty { - println!( - "\n [{}] sends build_chan_open_try_and_send \n on handshake_channel {:?} channel in state Init \n", - channel.short_name(), - handshake_channel - ); + match handshake_channel.build_chan_open_try_and_send() { Err(e) => { @@ -1098,10 +1062,7 @@ impl Worker { if !b_channel.state_matches( &ibc::ics04_channel::channel::State::Open, ) { - debug!( - "\n [{}] sends build_chan_open_ack_and_send \n on handshake_channel {:?}", - channel.short_name(),handshake_channel); - + match handshake_channel.build_chan_open_ack_and_send() { Err(e) => { debug!( @@ -1126,19 +1087,6 @@ impl Worker { ibc::ics04_channel::channel::State::Open => { match counterparty_state { ibc::ics04_channel::channel::State::TryOpen => { - debug!( - "[{}] chain {} has channel {} in state Open counterparty TryOpen \n", - channel.short_name(), - a_chain.id(), - channel.src_channel_id.clone() - ); - - // Confirm to b_chain - debug!( - "[{}] sends build_chan_open_confirm_and_send \n on handshake_channel {:?}", - channel.short_name(), - handshake_channel - ); match handshake_channel .build_chan_open_confirm_and_send() From 9432ee093b49197f0eac24745b8120adbaa30e9d Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Tue, 11 May 2021 11:24:00 +0200 Subject: [PATCH 13/52] Update supervisor.rs --- relayer/src/supervisor.rs | 53 +++++++++++++-------------------------- 1 file changed, 17 insertions(+), 36 deletions(-) diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index f2e5a85ac6..a1aae41cc3 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -1320,23 +1320,14 @@ impl Object { let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id()); if dst_chain_id.is_err() { - debug!("\n err dest_chan_id in init\n "); return Err("dest chain missing in init".into()); } - debug!( - " in for_open_init_channel dst_chain_id {} src_chain_id {} with event {:?} ", - dst_chain_id.clone().unwrap(), - src_chain.id(), - e - ); - Ok(Channel { dst_chain_id: dst_chain_id.unwrap(), src_chain_id: src_chain.id(), src_channel_id: channel_id.clone(), src_port_id: e.port_id().clone(), - //connection_id: e.connection_id().clone(), } .into()) } @@ -1349,22 +1340,14 @@ impl Object { let channel_id = e .channel_id() .as_ref() - .ok_or_else(|| format!("channel_id missing in OpenInit event '{:?}'", e))?; + .ok_or_else(|| format!("channel_id missing in OpenTry event '{:?}'", e))?; let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id()); if dst_chain_id.is_err() { - debug!("\n err dest_chan_id in try\n "); return Err("dest chain missing in OpenTry".into()); } - debug!( - " in for_open_try_channel dst_chain_id {} src_chain_id {} with event {:?} ", - dst_chain_id.clone().unwrap(), - src_chain.id(), - e - ); - Ok(Channel { dst_chain_id: dst_chain_id.unwrap(), src_chain_id: src_chain.id(), @@ -1378,22 +1361,21 @@ impl Object { e: &Attributes, src_chain: &dyn ChainHandle, ) -> Result { - let dst_chain_id = - get_counterparty_chain(src_chain, &e.channel_id().clone().unwrap(), &e.port_id())?; - debug!( - " in for_open_ack_channel dst_chain_id {} src_chain_id {} with event {:?} ", - dst_chain_id, - src_chain.id(), - e - ); + let channel_id = e + .channel_id() + .as_ref() + .ok_or_else(|| format!("channel_id missing in OpenAck event '{:?}'", e))?; + + let dst_chain_id = + get_counterparty_chain(src_chain, channel_id, &e.port_id())?; + Ok(Channel { dst_chain_id, src_chain_id: src_chain.id(), src_channel_id: e.channel_id().clone().unwrap(), src_port_id: e.port_id().clone(), - // connection_id: e.connection_id().clone(), } .into()) } @@ -1402,22 +1384,21 @@ impl Object { e: &Attributes, src_chain: &dyn ChainHandle, ) -> Result { - let dst_chain_id = - get_counterparty_chain(src_chain, &e.channel_id().clone().unwrap(), &e.port_id())?; - debug!( - " in for_open_confirm_channel dst_chain_id {} src_chain_id {} with event {:?} ", - dst_chain_id, - src_chain.id(), - e - ); + let channel_id = e + .channel_id() + .as_ref() + .ok_or_else(|| format!("channel_id missing in OpenInit event '{:?}'", e))?; + + + let dst_chain_id = + get_counterparty_chain(src_chain, channel_id, &e.port_id())?; Ok(Channel { dst_chain_id, src_chain_id: src_chain.id(), src_channel_id: e.channel_id().clone().unwrap(), src_port_id: e.port_id().clone(), - // connection_id: e.connection_id().clone(), } .into()) } From e6f96a408e40180d39813777acb1ec889f68114b Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Tue, 11 May 2021 11:29:55 +0200 Subject: [PATCH 14/52] fmt + clippy --- relayer/src/chain/cosmos.rs | 1 - relayer/src/chain/handle.rs | 6 +-- relayer/src/chain/handle/prod.rs | 6 +-- relayer/src/chain/runtime.rs | 7 ++- relayer/src/supervisor.rs | 85 +++++++++++++------------------- 5 files changed, 44 insertions(+), 61 deletions(-) diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index 9359cbe6b5..298403e841 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -770,7 +770,6 @@ impl Chain for CosmosSdkChain { // TODO: add warnings for any identifiers that fail to parse (below). // https://github.com/informalsystems/ibc-rs/pull/506#discussion_r555945560 - let channels = response .channels .into_iter() diff --git a/relayer/src/chain/handle.rs b/relayer/src/chain/handle.rs index ce242f9139..05e5bf5a60 100644 --- a/relayer/src/chain/handle.rs +++ b/relayer/src/chain/handle.rs @@ -26,9 +26,9 @@ use ibc::{ Height, }; use ibc_proto::ibc::core::channel::v1::{ - PacketState, QueryChannelsRequest,QueryConnectionChannelsRequest, QueryNextSequenceReceiveRequest, - QueryPacketAcknowledgementsRequest, QueryPacketCommitmentsRequest, QueryUnreceivedAcksRequest, - QueryUnreceivedPacketsRequest, + PacketState, QueryChannelsRequest, QueryConnectionChannelsRequest, + QueryNextSequenceReceiveRequest, QueryPacketAcknowledgementsRequest, + QueryPacketCommitmentsRequest, QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest, }; use ibc_proto::ibc::core::client::v1::QueryConsensusStatesRequest; use ibc_proto::ibc::core::commitment::v1::MerkleProof; diff --git a/relayer/src/chain/handle/prod.rs b/relayer/src/chain/handle/prod.rs index 88ed88a865..aad102bea8 100644 --- a/relayer/src/chain/handle/prod.rs +++ b/relayer/src/chain/handle/prod.rs @@ -24,9 +24,9 @@ use ibc::{ Height, }; use ibc_proto::ibc::core::channel::v1::{ - PacketState, QueryChannelsRequest, QueryConnectionChannelsRequest, QueryNextSequenceReceiveRequest, - QueryPacketAcknowledgementsRequest, QueryPacketCommitmentsRequest, QueryUnreceivedAcksRequest, - QueryUnreceivedPacketsRequest, + PacketState, QueryChannelsRequest, QueryConnectionChannelsRequest, + QueryNextSequenceReceiveRequest, QueryPacketAcknowledgementsRequest, + QueryPacketCommitmentsRequest, QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest, }; use ibc_proto::ibc::core::client::v1::QueryConsensusStatesRequest; use ibc_proto::ibc::core::commitment::v1::MerkleProof; diff --git a/relayer/src/chain/runtime.rs b/relayer/src/chain/runtime.rs index c5b821ef50..ebc5aaba0d 100644 --- a/relayer/src/chain/runtime.rs +++ b/relayer/src/chain/runtime.rs @@ -29,9 +29,9 @@ use ibc::{ use ibc_proto::ibc::core::{ channel::v1::{ - PacketState, QueryChannelsRequest, QueryConnectionChannelsRequest, QueryNextSequenceReceiveRequest, - QueryPacketAcknowledgementsRequest, QueryPacketCommitmentsRequest, - QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest, + PacketState, QueryChannelsRequest, QueryConnectionChannelsRequest, + QueryNextSequenceReceiveRequest, QueryPacketAcknowledgementsRequest, + QueryPacketCommitmentsRequest, QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest, }, client::v1::QueryConsensusStatesRequest, commitment::v1::MerkleProof, @@ -629,7 +629,6 @@ impl ChainRuntime { request: QueryConnectionChannelsRequest, reply_to: ReplyTo>, ) -> Result<(), Error> { - let result = self.chain.query_connection_channels(request); reply_to diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index a1aae41cc3..91785f3524 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -762,8 +762,7 @@ impl Worker { for event in batch.events { match event { IbcEvent::OpenInitChannel(open_init) => { - - //Create channel handshake object + //Create channel handshake object let connection_id = open_init.attributes().connection_id.clone(); let counterparty_port_id = @@ -839,7 +838,7 @@ impl Worker { open_try ); - //Create channel handshake object + //Create channel handshake object let connection_id = open_try.attributes().connection_id.clone(); let counterparty_port_id = open_try.attributes().counterparty_port_id.clone(); @@ -879,8 +878,6 @@ impl Worker { version: Default::default(), }; - - match handshake_channel.build_chan_open_ack_and_send() { Err(e) => { debug!( @@ -903,7 +900,6 @@ impl Worker { } IbcEvent::OpenAckChannel(open_ack) => { - if handshake_channel.b_side.channel_id.is_none() { handshake_channel.b_side.channel_id = open_ack.counterparty_channel_id().clone(); @@ -917,7 +913,6 @@ impl Worker { } IbcEvent::OpenConfirmChannel(_open_confirm) => { - println!( "{} {} {} Channel handshake finished for {:#?}\n", done, done, done, &channel.src_channel_id, @@ -943,7 +938,7 @@ impl Worker { let a_channel = self.chains.a.query_channel( &channel.src_port_id, &channel.src_channel_id, - height, + height, )?; let connection_id = @@ -959,7 +954,8 @@ impl Worker { .a .query_connection(&connection_id, Height::zero())?; - let mut counterparty_state = &ibc::ics04_channel::channel::State::Uninitialized; + let mut counterparty_state = + &ibc::ics04_channel::channel::State::Uninitialized; let mut b_channel = Default::default(); @@ -976,7 +972,7 @@ impl Worker { }; handshake_channel = RelayChannel { - ordering: a_channel.ordering().clone(), + ordering: *a_channel.ordering(), a_side: ChannelSide::new( a_chain.clone(), connection.client_id().clone(), @@ -1008,7 +1004,7 @@ impl Worker { let channels: Vec = b_chain.query_connection_channels(req.clone())?; - + for chan in channels.iter() { if chan.channel_end.remote.channel_id.is_some() && chan @@ -1034,8 +1030,6 @@ impl Worker { } if !found_counterparty { - - match handshake_channel.build_chan_open_try_and_send() { Err(e) => { debug!( @@ -1057,37 +1051,34 @@ impl Worker { } ibc::ics04_channel::channel::State::TryOpen => { - if a_channel.remote.channel_id.is_some() { - - if !b_channel.state_matches( + if a_channel.remote.channel_id.is_some() + && !b_channel.state_matches( &ibc::ics04_channel::channel::State::Open, - ) { - - match handshake_channel.build_chan_open_ack_and_send() { - Err(e) => { - debug!( - "Failed ChanAck {:?}: {:?}", - handshake_channel.b_side, e - ); - } - Ok(event) => { - handshake_channel.b_side.channel_id = - Some(extract_channel_id(&event)?.clone()); - println!( - "{} {} => {:#?}\n", - done, - b_chain.id(), - event - ); - } + ) + { + match handshake_channel.build_chan_open_ack_and_send() { + Err(e) => { + debug!( + "Failed ChanAck {:?}: {:?}", + handshake_channel.b_side, e + ); + } + Ok(event) => { + handshake_channel.b_side.channel_id = + Some(extract_channel_id(&event)?.clone()); + println!( + "{} {} => {:#?}\n", + done, + b_chain.id(), + event + ); } - } //TODO else either counter party channel is more advanced or another channel closed the hanshake - } //TODO else error + } + } } ibc::ics04_channel::channel::State::Open => { match counterparty_state { ibc::ics04_channel::channel::State::TryOpen => { - match handshake_channel .build_chan_open_confirm_and_send() { @@ -1129,7 +1120,7 @@ impl Worker { _ => {} //TODO Uninit and Close } //end match a_state - first_iteration = false; + first_iteration = false; } //end first iteration } //end worker end block cmd }; @@ -1361,16 +1352,13 @@ impl Object { e: &Attributes, src_chain: &dyn ChainHandle, ) -> Result { - let channel_id = e .channel_id() .as_ref() .ok_or_else(|| format!("channel_id missing in OpenAck event '{:?}'", e))?; + let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id())?; - let dst_chain_id = - get_counterparty_chain(src_chain, channel_id, &e.port_id())?; - Ok(Channel { dst_chain_id, src_chain_id: src_chain.id(), @@ -1384,15 +1372,12 @@ impl Object { e: &Attributes, src_chain: &dyn ChainHandle, ) -> Result { - let channel_id = e - .channel_id() - .as_ref() - .ok_or_else(|| format!("channel_id missing in OpenInit event '{:?}'", e))?; - + .channel_id() + .as_ref() + .ok_or_else(|| format!("channel_id missing in OpenInit event '{:?}'", e))?; - let dst_chain_id = - get_counterparty_chain(src_chain, channel_id, &e.port_id())?; + let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id())?; Ok(Channel { dst_chain_id, From a5fc0b78093c4cb2337552f853a84da379d039d3 Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Tue, 11 May 2021 11:37:01 +0200 Subject: [PATCH 15/52] Update supervisor.rs --- relayer/src/supervisor.rs | 73 ++++++--------------------------------- 1 file changed, 10 insertions(+), 63 deletions(-) diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index 91785f3524..d0991f19a6 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -11,7 +11,7 @@ use itertools::Itertools; use tracing::{debug, error, error_span, info, trace, warn}; use ibc::{ - events::{IbcEvent, VecIbcEvents}, + events::IbcEvent, ics02_client::{ client_state::ClientState, events::{NewBlock, UpdateClient}, @@ -172,24 +172,18 @@ impl Supervisor { } IbcEvent::OpenInitChannel(ref open_init) => { - debug!("\n !!!! Init in \n "); if let Ok(object) = Object::for_open_init_channel(open_init.attributes(), src_chain) { collected.per_object.entry(object).or_default().push(event); - } else { - debug!("\n !!!! ups object malformed Init in \n "); } } IbcEvent::OpenTryChannel(ref open_try) => { - debug!("\n !!!! OpenTry in \n "); if let Ok(object) = Object::for_open_try_channel(open_try.attributes(), src_chain) { collected.per_object.entry(object).or_default().push(event); - } else { - debug!("\n !!!! ups object malformed Try in \n "); } } @@ -205,12 +199,14 @@ impl Supervisor { .push(event.clone()); } - if let Ok(object2) = + if let Ok(channel_object) = Object::for_open_ack_channel(open_ack.attributes(), src_chain) { - collected.per_object.entry(object2).or_default().push(event); - } else { - debug!("\n !!!! ups object malformed Ack in \n "); + collected + .per_object + .entry(channel_object) + .or_default() + .push(event); } } IbcEvent::OpenConfirmChannel(ref open_confirm) => { @@ -224,12 +220,12 @@ impl Supervisor { .or_default() .push(event.clone()); } - if let Ok(object2) = + if let Ok(channel_object) = Object::for_open_confirm_channel(open_confirm.attributes(), src_chain) { collected .per_object - .entry(object2) + .entry(channel_object) .or_default() .push(event.clone()); } @@ -401,21 +397,8 @@ impl Supervisor { // connection_id: connection_id.clone(), }); - debug!( - "create workers: creating a worker for a channel object {:?}", - channel_object - ); - self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); - } - // end if channel not open - else { - debug!( - "\n BABABABAABB - \n" - ); - - // //start spawning channel worker + } else { let counterparty_chain_id = get_counterparty_chain_for_channel(chain.as_ref(), channel.clone()).unwrap(); @@ -426,16 +409,9 @@ impl Supervisor { src_chain_id: chain.id(), src_channel_id: channel.channel_id.clone(), src_port_id: channel.port_id, - //connection_id: connection_id.clone(), }); - debug!( - "create workers: creating a worker for a channel object that is not open {:?}", - channel_object - ); - self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); - //end the spawning channel worker } Ok(()) @@ -503,13 +479,6 @@ impl Supervisor { continue; } - debug!( - "chain {} sent {} for object {:?}", - chain_id, - VecIbcEvents(events.clone()), - object, - ); - let src = self.registry.get_or_spawn(object.src_chain_id())?; let dst = self.registry.get_or_spawn(object.dst_chain_id())?; @@ -751,8 +720,6 @@ impl Worker { version: Default::default(), }; - debug!("[{}] started ", channel.short_name()); - let mut first_iteration = true; loop { @@ -803,12 +770,6 @@ impl Worker { version: Default::default(), }; - debug!( - "\n [{}] sends build_chan_open_try_and_send \n on handshake_channel {:?} channel in state Init \n", - channel.short_name(), - handshake_channel - ); - match handshake_channel.build_chan_open_try_and_send() { Err(e) => { debug!( @@ -832,12 +793,6 @@ impl Worker { } IbcEvent::OpenTryChannel(open_try) => { - debug!( - "\n [{}] Calling Open Try from the loop {:?} \n ", - channel.short_name(), - open_try - ); - //Create channel handshake object let connection_id = open_try.attributes().connection_id.clone(); let counterparty_port_id = @@ -931,8 +886,6 @@ impl Worker { new_block: _, } => { if first_iteration { - debug!("\n [{}] new block \n ", channel.short_name()); - let height = current_height.decrement()?; let a_channel = self.chains.a.query_channel( @@ -1015,12 +968,6 @@ impl Worker { .unwrap() == channel.src_channel_id.clone() { - debug!( - "[{}] found a pair channel {} on chain {}", - channel.short_name(), - chan.channel_id, - handshake_channel.b_side.chain_id() - ); found_counterparty = true; handshake_channel.b_side.channel_id = Some(chan.channel_id.clone()); From 3bc6091dbc5811d5ef4a126440e792378383b344 Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Tue, 11 May 2021 12:17:47 +0200 Subject: [PATCH 16/52] add check for uninitialized channel_connection_client --- relayer/src/chain/counterparty.rs | 7 +++---- relayer/src/supervisor/error.rs | 3 +++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/relayer/src/chain/counterparty.rs b/relayer/src/chain/counterparty.rs index ce44ea287d..43435e5fa9 100644 --- a/relayer/src/chain/counterparty.rs +++ b/relayer/src/chain/counterparty.rs @@ -50,10 +50,9 @@ pub fn channel_connection_client( .query_channel(port_id, channel_id, Height::zero()) .map_err(|e| Error::QueryFailed(format!("{}", e)))?; - //change to Unintialized - // if !channel_end.is_open() { - // return Err(Error::ChannelNotOpen(channel_id.clone(), chain.id())); - // } + if channel_end.state_matches(&ibc::ics04_channel::channel::State::Uninitialized) { + return Err(Error::ChannelUninitialized(channel_id.clone(), chain.id())); + } let connection_id = channel_end .connection_hops() diff --git a/relayer/src/supervisor/error.rs b/relayer/src/supervisor/error.rs index e397235976..c93beb70ec 100644 --- a/relayer/src/supervisor/error.rs +++ b/relayer/src/supervisor/error.rs @@ -7,6 +7,9 @@ pub enum Error { #[error("channel {0} on chain {1} is not open")] ChannelNotOpen(ChannelId, ChainId), + #[error("channel {0} on chain {1} is not open")] + ChannelUninitialized(ChannelId, ChainId), + #[error("connection {0} (underlying channel {1}) on chain {2} is not open")] ConnectionNotOpen(ConnectionId, ChannelId, ChainId), From 833f8fe42fb6094d7e7f305d5249bbd0c1138172 Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Tue, 11 May 2021 19:38:49 +0200 Subject: [PATCH 17/52] refactor event loop --- modules/src/events.rs | 11 +++ relayer/src/channel.rs | 81 +++++++++++++++++ relayer/src/supervisor.rs | 182 +++----------------------------------- 3 files changed, 105 insertions(+), 169 deletions(-) diff --git a/modules/src/events.rs b/modules/src/events.rs index 385dc56ee7..4bf8176e6d 100644 --- a/modules/src/events.rs +++ b/modules/src/events.rs @@ -7,6 +7,7 @@ use crate::ics02_client::events as ClientEvents; use crate::ics02_client::events::NewBlock; use crate::ics03_connection::events as ConnectionEvents; use crate::ics04_channel::events as ChannelEvents; +use crate::ics04_channel::events::Attributes as ChannelAttributes; use crate::Height; use prost::alloc::fmt::Formatter; use std::fmt; @@ -183,6 +184,16 @@ impl IbcEvent { _ => unimplemented!(), } } + + pub fn attributes(&mut self) -> &ChannelAttributes { + match self { + IbcEvent::OpenInitChannel(ev) => ev.attributes(), + IbcEvent::OpenTryChannel(ev) => ev.attributes(), + IbcEvent::OpenAckChannel(ev) => ev.attributes(), + IbcEvent::OpenConfirmChannel(ev) => ev.attributes(), + _ => unimplemented!(), + } + } } #[derive(Debug, Clone, Deserialize, Serialize)] diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index cac001f58a..5b08061232 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -1,3 +1,4 @@ +use anomaly::BoxError; use prost_types::Any; use serde::Serialize; use thiserror::Error; @@ -27,6 +28,9 @@ pub enum ChannelError { #[error("failed with underlying cause: {0}")] Failed(String), + #[error("failed due to missing counterparty connection")] + MissingCounterpartyConnection, + #[error("failed during an operation on client ({0}) hosted by chain ({1}) with error: {2}")] ClientOperation(ClientId, ChainId, ForeignClientError), @@ -137,6 +141,71 @@ impl Channel { Ok(channel) } + pub fn restore( + chain: Box, + counterparty_chain: Box, + channel_open_event: IbcEvent, + ) -> Result { + match channel_open_event.clone() { + IbcEvent::OpenInitChannel(_open_init) => {} + IbcEvent::OpenTryChannel(_open_try) => {} + IbcEvent::OpenAckChannel(_open_ack) => {} + IbcEvent::OpenConfirmChannel(_open_confirm) => {} + _ => return Err("Supported only for Channel Open Events".to_string().into()), + }; + + let connection_id = channel_open_event + .clone() + .attributes() + .connection_id + .clone(); + let counterparty_port_id = channel_open_event + .clone() + .attributes() + .counterparty_port_id + .clone(); + let connection = chain.query_connection(&connection_id, Height::zero())?; + let counterparty_channel_id = channel_open_event + .clone() + .attributes() + .counterparty_channel_id + .clone(); + + let port_id = channel_open_event.clone().attributes().port_id.clone(); + let channel_id = channel_open_event.clone().attributes().channel_id.clone(); + + let counterparty_connection_id = match connection.counterparty().connection_id() { + Some(x) => x.clone(), + None => { + return Err("failed due to missing counterparty connection" + .to_string() + .into()) + } + }; + + Ok(Channel { + ordering: Default::default(), + //TODO how to get the order from raw tx + a_side: ChannelSide::new( + chain.clone(), + connection.client_id().clone(), + connection_id, + port_id, + channel_id, + ), + b_side: ChannelSide::new( + counterparty_chain.clone(), + connection.counterparty().client_id().clone(), + counterparty_connection_id, + counterparty_port_id, + counterparty_channel_id, + ), + connection_delay: connection.delay_period(), + //TODO detect version from event + version: Default::default(), + }) + } + pub fn src_chain(&self) -> Box { self.a_side.chain.clone() } @@ -311,6 +380,18 @@ impl Channel { ))) } + pub fn handshake_step(&mut self, event: IbcEvent) -> Result, ChannelError> { + match event { + IbcEvent::OpenInitChannel(_open_init) => Ok(vec![self.build_chan_open_try_and_send()?]), + IbcEvent::OpenTryChannel(_open_try) => Ok(vec![self.build_chan_open_ack_and_send()?]), + IbcEvent::OpenAckChannel(_open_ack) => { + Ok(vec![self.build_chan_open_confirm_and_send()?]) + } + IbcEvent::OpenConfirmChannel(_open_confirm) => Ok(vec![]), + _ => Ok(vec![]), + } + } + pub fn build_update_client_on_dst(&self, height: Height) -> Result, ChannelError> { let client = ForeignClient::restore(self.dst_client_id(), self.dst_chain(), self.src_chain()); diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index d0991f19a6..d43b35a5aa 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -698,27 +698,7 @@ impl Worker { let a_chain = self.chains.a.clone(); let b_chain = self.chains.b.clone(); - let mut handshake_channel = RelayChannel { - ordering: Default::default(), - //TODO how to get the order from raw tx - a_side: ChannelSide::new( - a_chain.clone(), - Default::default(), - Default::default(), - Default::default(), - None, - ), - b_side: ChannelSide::new( - b_chain.clone(), - Default::default(), - Default::default(), - Default::default(), - None, - ), - connection_delay: Default::default(), - //TODO detect version from event - version: Default::default(), - }; + let mut handshake_channel; let mut first_iteration = true; @@ -727,158 +707,22 @@ impl Worker { match cmd { WorkerCmd::IbcEvents { batch } => { for event in batch.events { - match event { - IbcEvent::OpenInitChannel(open_init) => { - //Create channel handshake object - let connection_id = - open_init.attributes().connection_id.clone(); - let counterparty_port_id = - open_init.attributes().counterparty_port_id.clone(); - let connection = self - .chains - .a - .query_connection(&connection_id.clone(), Height::zero())?; - let counterparty_channel_id = - open_init.attributes().counterparty_channel_id.clone(); - - let port_id = open_init.attributes().port_id.clone(); - let channel_id = open_init.attributes().channel_id.clone(); - - handshake_channel = RelayChannel { - ordering: Default::default(), - //TODO how to get the order from raw tx - a_side: ChannelSide::new( - a_chain.clone(), - connection.client_id().clone(), - connection_id.clone(), - port_id, - channel_id, - ), - b_side: ChannelSide::new( - b_chain.clone(), - connection.counterparty().client_id().clone(), - connection - .counterparty() - .connection_id() - .unwrap() - .clone(), - counterparty_port_id.clone(), - counterparty_channel_id.clone(), - ), - connection_delay: connection.delay_period(), - //TODO detect version from event - version: Default::default(), - }; - - match handshake_channel.build_chan_open_try_and_send() { - Err(e) => { - debug!( - "Failed ChanTry {:?}: {:?}", - handshake_channel.b_side, e - ); - } - Ok(event) => { - handshake_channel.b_side.channel_id = - Some(extract_channel_id(&event)?.clone()); - println!( - "{} {} => {:#?}\n", - done, - b_chain.id(), - event.clone() - ); - } - } - - first_iteration = false; - } - - IbcEvent::OpenTryChannel(open_try) => { - //Create channel handshake object - let connection_id = open_try.attributes().connection_id.clone(); - let counterparty_port_id = - open_try.attributes().counterparty_port_id.clone(); - let connection = self - .chains - .a - .query_connection(&connection_id.clone(), Height::zero())?; - let counterparty_channel_id = - open_try.attributes().counterparty_channel_id.clone(); - - let port_id = open_try.attributes().port_id.clone(); - let channel_id = open_try.attributes().channel_id.clone(); - - handshake_channel = RelayChannel { - ordering: Default::default(), - //TODO how to get the order from raw tx - a_side: ChannelSide::new( - a_chain.clone(), - connection.client_id().clone(), - connection_id.clone(), - port_id, - channel_id, - ), - b_side: ChannelSide::new( - b_chain.clone(), - connection.counterparty().client_id().clone(), - connection - .counterparty() - .connection_id() - .unwrap() - .clone(), - counterparty_port_id.clone(), - counterparty_channel_id.clone(), - ), - connection_delay: connection.delay_period(), - //TODO detect version from event - version: Default::default(), - }; - - match handshake_channel.build_chan_open_ack_and_send() { - Err(e) => { - debug!( - "Failed ChanAck {:?}: {:?}", - handshake_channel.b_side, e - ); - } - Ok(event) => { - // handshake_channel.b_side.channel_id = extract_channel_id(&event)?.clone(); - println!( - "{} {} => {:#?}\n", - done, - b_chain.id(), - event - ); - } - } - - first_iteration = false; - } - - IbcEvent::OpenAckChannel(open_ack) => { - if handshake_channel.b_side.channel_id.is_none() { - handshake_channel.b_side.channel_id = - open_ack.counterparty_channel_id().clone(); - } - - let event = - handshake_channel.build_chan_open_confirm_and_send()?; - println!("{} {} => {:#?}\n", done, b_chain.id(), event); + handshake_channel = RelayChannel::restore( + a_chain.clone(), + b_chain.clone(), + event.clone(), + )?; + let result = handshake_channel.handshake_step(event.clone()); - first_iteration = false; + match result { + Err(e) => { + debug!("\n Failed {:?} with error {:?} \n", event, e); } - - IbcEvent::OpenConfirmChannel(_open_confirm) => { - println!( - "{} {} {} Channel handshake finished for {:#?}\n", - done, done, done, &channel.src_channel_id, - ); - - return Ok(()); + Ok(ev) => { + println!("{} => {:#?}\n", done, ev.clone()); } - IbcEvent::CloseInitChannel(_) => {} - IbcEvent::CloseConfirmChannel(_) => {} - _ => {} } + first_iteration = false; } } WorkerCmd::NewBlock { From c0f7ea9f334936ee6ae1b82ff038896dc9702613 Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Wed, 12 May 2021 16:37:48 +0200 Subject: [PATCH 18/52] refactor channel worker new_block branch --- relayer/src/channel.rs | 108 +++++++++++++++++++- relayer/src/supervisor.rs | 202 ++++---------------------------------- 2 files changed, 124 insertions(+), 186 deletions(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 5b08061232..86b4a09014 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -5,7 +5,7 @@ use thiserror::Error; use tracing::error; use ibc::events::IbcEvent; -use ibc::ics04_channel::channel::{ChannelEnd, Counterparty, Order, State}; +use ibc::ics04_channel::channel::{ChannelEnd, Counterparty, IdentifiedChannelEnd, Order, State}; use ibc::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm; use ibc::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit; use ibc::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; @@ -21,8 +21,12 @@ use crate::connection::Connection; use crate::error::Error; use crate::foreign_client::{ForeignClient, ForeignClientError}; use crate::relay::MAX_ITER; +use crate::supervisor::error::Error as WorkerChannelError; +use crate::supervisor::Channel as WorkerChannelObject; use std::time::Duration; +use ibc_proto::ibc::core::channel::v1::QueryConnectionChannelsRequest; + #[derive(Debug, Error)] pub enum ChannelError { #[error("failed with underlying cause: {0}")] @@ -141,7 +145,7 @@ impl Channel { Ok(channel) } - pub fn restore( + pub fn restore_from_event( chain: Box, counterparty_chain: Box, channel_open_event: IbcEvent, @@ -206,6 +210,67 @@ impl Channel { }) } + pub fn restore_from_state( + chain: Box, + counterparty_chain: Box, + channel: WorkerChannelObject, + height: Height, + ) -> Result<(Channel, State), BoxError> { + let a_channel = + chain.query_channel(&channel.src_port_id, &channel.src_channel_id, height)?; + + let connection_id = a_channel.connection_hops().first().ok_or_else(|| { + WorkerChannelError::MissingConnectionHops(channel.src_channel_id.clone(), chain.id()) + })?; + + let connection = chain.query_connection(&connection_id, Height::zero())?; + + let mut handshake_channel = Channel { + ordering: *a_channel.ordering(), + a_side: ChannelSide::new( + chain.clone(), + connection.client_id().clone(), + connection_id.clone(), + channel.src_port_id.clone(), + Some(channel.src_channel_id.clone()), + ), + b_side: ChannelSide::new( + counterparty_chain.clone(), + connection.counterparty().client_id().clone(), + connection.counterparty().connection_id().unwrap().clone(), + a_channel.remote.port_id.clone(), + a_channel.remote.channel_id.clone(), + ), + connection_delay: connection.delay_period(), + version: Some(a_channel.version.clone()), + }; + + if a_channel.state_matches(&ibc::ics04_channel::channel::State::Init) + && a_channel.remote.channel_id.is_none() + { + let req = QueryConnectionChannelsRequest { + connection: connection_id.to_string(), + pagination: ibc_proto::cosmos::base::query::pagination::all(), + }; + + let channels: Vec = + counterparty_chain.query_connection_channels(req)?; + + for chan in channels.iter() { + if chan.channel_end.remote.channel_id.is_some() + && chan.channel_end.remote.channel_id.clone().unwrap() + == channel.src_channel_id.clone() + { + handshake_channel.b_side.channel_id = Some(chan.channel_id.clone()); + + break; + } + } + } + + Ok((handshake_channel, a_channel.state)) + } + pub fn src_chain(&self) -> Box { self.a_side.chain.clone() } @@ -380,9 +445,20 @@ impl Channel { ))) } - pub fn handshake_step(&mut self, event: IbcEvent) -> Result, ChannelError> { + pub fn handshake_step_with_event( + &mut self, + event: IbcEvent, + ) -> Result, ChannelError> { match event { - IbcEvent::OpenInitChannel(_open_init) => Ok(vec![self.build_chan_open_try_and_send()?]), + IbcEvent::OpenInitChannel(_open_init) => { + // There is a race here: for the same source channel s, in Init, + // another chan_open_try with -s src_chan (destination d) can come from the user and if it is + // executed first on the chain, before the one send by the relayer, + // the later will create a new channel (d' != d) stuck in TryOpen whose counterparty is s + // There is no way to avoid it, we can add a check (like in handshake_step_with_state) but + // it will slow down and there will still be a window where the behavior is possible. + Ok(vec![self.build_chan_open_try_and_send()?]) + } IbcEvent::OpenTryChannel(_open_try) => Ok(vec![self.build_chan_open_ack_and_send()?]), IbcEvent::OpenAckChannel(_open_ack) => { Ok(vec![self.build_chan_open_confirm_and_send()?]) @@ -392,6 +468,24 @@ impl Channel { } } + pub fn handshake_step_with_state( + &mut self, + state: State, + ) -> Result, ChannelError> { + match state { + ibc::ics04_channel::channel::State::Init => { + Ok(vec![self.build_chan_open_try_and_send()?]) + } + ibc::ics04_channel::channel::State::TryOpen => { + Ok(vec![self.build_chan_open_ack_and_send()?]) + } + ibc::ics04_channel::channel::State::Open => { + Ok(vec![self.build_chan_open_confirm_and_send()?]) + } + _ => Ok(vec![]), + } + } + pub fn build_update_client_on_dst(&self, height: Height) -> Result, ChannelError> { let client = ForeignClient::restore(self.dst_client_id(), self.dst_chain(), self.src_chain()); @@ -619,6 +713,12 @@ impl Channel { } pub fn build_chan_open_try_and_send(&self) -> Result { + if self.b_side.channel_id().is_some() { + return Err(ChannelError::Failed( + "Counterparty channel defined".to_string(), + )); + }; + let dst_msgs = self.build_chan_open_try()?; let events = self diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index d43b35a5aa..dbfae76ab1 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -24,11 +24,9 @@ use ibc::{ Height, }; -use ibc_proto::ibc::core::channel::v1::{QueryChannelsRequest, QueryConnectionChannelsRequest}; +use ibc_proto::ibc::core::channel::v1::QueryChannelsRequest; -use crate::channel::extract_channel_id; use crate::channel::Channel as RelayChannel; -use crate::channel::ChannelSide; use crate::{ chain::{ @@ -44,7 +42,7 @@ use crate::{ registry::Registry, }; -mod error; +pub mod error; pub use error::Error; /// A command for a [`Worker`]. @@ -707,12 +705,12 @@ impl Worker { match cmd { WorkerCmd::IbcEvents { batch } => { for event in batch.events { - handshake_channel = RelayChannel::restore( + handshake_channel = RelayChannel::restore_from_event( a_chain.clone(), b_chain.clone(), event.clone(), )?; - let result = handshake_channel.handshake_step(event.clone()); + let result = handshake_channel.handshake_step_with_event(event.clone()); match result { Err(e) => { @@ -732,188 +730,28 @@ impl Worker { if first_iteration { let height = current_height.decrement()?; - let a_channel = self.chains.a.query_channel( - &channel.src_port_id, - &channel.src_channel_id, + let (h, state) = RelayChannel::restore_from_state( + a_chain.clone(), + b_chain.clone(), + channel.clone(), height, )?; - let connection_id = - a_channel.connection_hops().first().ok_or_else(|| { - Error::MissingConnectionHops( - channel.src_channel_id.clone(), - a_chain.id(), - ) - })?; - - let connection = self - .chains - .a - .query_connection(&connection_id, Height::zero())?; - - let mut counterparty_state = - &ibc::ics04_channel::channel::State::Uninitialized; - - let mut b_channel = Default::default(); - - let counterparty_channel_id = if a_channel.remote.channel_id.is_none() { - None - } else { - b_channel = self.chains.b.query_channel( - &a_channel.remote.port_id.clone(), - &a_channel.remote.channel_id.clone().unwrap(), - Height::zero(), - )?; - counterparty_state = &b_channel.state; - a_channel.remote.channel_id.clone() - }; - - handshake_channel = RelayChannel { - ordering: *a_channel.ordering(), - a_side: ChannelSide::new( - a_chain.clone(), - connection.client_id().clone(), - connection_id.clone(), - channel.src_port_id.clone(), - Some(channel.src_channel_id.clone()), - ), - b_side: ChannelSide::new( - b_chain.clone(), - connection.counterparty().client_id().clone(), - connection.counterparty().connection_id().unwrap().clone(), - a_channel.remote.port_id.clone(), - counterparty_channel_id.clone(), - ), - connection_delay: connection.delay_period(), - version: Some(a_channel.version.clone()), - }; - - let mut found_counterparty = false; - - match a_channel.state { - ibc::ics04_channel::channel::State::Init => { - if a_channel.remote.channel_id.is_none() { - let req = QueryConnectionChannelsRequest { - connection: connection_id.to_string(), - pagination: - ibc_proto::cosmos::base::query::pagination::all(), - }; - - let channels: Vec = - b_chain.query_connection_channels(req.clone())?; - - for chan in channels.iter() { - if chan.channel_end.remote.channel_id.is_some() - && chan - .channel_end - .remote - .channel_id - .clone() - .unwrap() - == channel.src_channel_id.clone() - { - found_counterparty = true; - handshake_channel.b_side.channel_id = - Some(chan.channel_id.clone()); - - break; - } - } - - if !found_counterparty { - match handshake_channel.build_chan_open_try_and_send() { - Err(e) => { - debug!( - "Failed ChanTry {:?}: {:?}", - handshake_channel.b_side, e - ); - } - Ok(event) => { - println!( - "{} {} => {:#?}\n", - done, - b_chain.id(), - event - ); - } - } - } - } - } + handshake_channel = h; - ibc::ics04_channel::channel::State::TryOpen => { - if a_channel.remote.channel_id.is_some() - && !b_channel.state_matches( - &ibc::ics04_channel::channel::State::Open, - ) - { - match handshake_channel.build_chan_open_ack_and_send() { - Err(e) => { - debug!( - "Failed ChanAck {:?}: {:?}", - handshake_channel.b_side, e - ); - } - Ok(event) => { - handshake_channel.b_side.channel_id = - Some(extract_channel_id(&event)?.clone()); - println!( - "{} {} => {:#?}\n", - done, - b_chain.id(), - event - ); - } - } - } + let result = handshake_channel.handshake_step_with_state(state); + + match result { + Err(e) => { + debug!("\n Failed with error {:?} \n", e); } - ibc::ics04_channel::channel::State::Open => { - match counterparty_state { - ibc::ics04_channel::channel::State::TryOpen => { - match handshake_channel - .build_chan_open_confirm_and_send() - { - Err(e) => { - debug!( - "Failed OpenConfirm {:?}: {:?}", - handshake_channel.b_side, e - ); - } - Ok(event) => { - println!( - "{} {} => {:#?}\n", - done, - b_chain.id(), - event - ); - } - } - } - ibc::ics04_channel::channel::State::Open => { - println!( - "[{}]{} {} {} Channel handshake finished for {:#?}\n", - channel.short_name(), - done, - done, - done, - &channel.src_channel_id, - ); - return Ok(()); - } - _ => { - debug!( - "[{}] \n Error Unimplemented handshake case \n", - channel.short_name() - ) - } - } - } //end a_channel OPEN - - _ => {} //TODO Uninit and Close - } //end match a_state + Ok(ev) => { + println!("{} => {:#?}\n", done, ev.clone()); + } + } first_iteration = false; - } //end first iteration - } //end worker end block cmd + } + } }; } } From 3ac9f551e93d6fb982b815c0d0ccef071adea0e6 Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Wed, 12 May 2021 17:16:29 +0200 Subject: [PATCH 19/52] merged master --- relayer/src/channel.rs | 2 +- relayer/src/object.rs | 128 ++++++++++++++++++++++++++++++++++++++ relayer/src/supervisor.rs | 9 ++- relayer/src/worker.rs | 72 ++++++++++++++++++++- 4 files changed, 204 insertions(+), 7 deletions(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 86b4a09014..c285768771 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -22,7 +22,7 @@ use crate::error::Error; use crate::foreign_client::{ForeignClient, ForeignClientError}; use crate::relay::MAX_ITER; use crate::supervisor::error::Error as WorkerChannelError; -use crate::supervisor::Channel as WorkerChannelObject; +use crate::object::Channel as WorkerChannelObject; use std::time::Duration; use ibc_proto::ibc::core::channel::v1::QueryConnectionChannelsRequest; diff --git a/relayer/src/object.rs b/relayer/src/object.rs index 7c460fca01..d0b032feff 100644 --- a/relayer/src/object.rs +++ b/relayer/src/object.rs @@ -73,6 +73,8 @@ pub enum Object { Client(Client), /// See [`UnidirectionalChannelPath`]. UnidirectionalChannelPath(UnidirectionalChannelPath), + /// See [`Channel`]. + Channel(Channel), } impl Object { @@ -83,6 +85,7 @@ impl Object { match self { Object::UnidirectionalChannelPath(p) => p.src_chain_id == *src_chain_id, Object::Client(_) => false, + Object::Channel(c) => c.src_chain_id == *src_chain_id, } } } @@ -99,11 +102,44 @@ impl From for Object { } } +impl From for Object { + fn from(c: Channel) -> Self { + Self::Channel(c) + } +} + +//Channel +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Channel { + /// Destination chain identifier. + pub dst_chain_id: ChainId, + + /// Source chain identifier. + pub src_chain_id: ChainId, + + /// Source channel identiier. + pub src_channel_id: ChannelId, + + /// Source port identiier. + pub src_port_id: PortId, + // pub connection_id: ConnectionId, +} + +impl Channel { + pub fn short_name(&self) -> String { + format!( + "{}/{}:{} -> {}", + self.src_channel_id, self.src_port_id, self.src_chain_id, self.dst_chain_id, + ) + } +} + impl Object { pub fn src_chain_id(&self) -> &ChainId { match self { Self::Client(ref client) => &client.src_chain_id, Self::UnidirectionalChannelPath(ref path) => &path.src_chain_id, + Self::Channel(ref channel) => &channel.src_chain_id, } } @@ -111,6 +147,7 @@ impl Object { match self { Self::Client(ref client) => &client.dst_chain_id, Self::UnidirectionalChannelPath(ref path) => &path.dst_chain_id, + Self::Channel(ref channel) => &channel.dst_chain_id, } } @@ -118,6 +155,7 @@ impl Object { match self { Self::Client(ref client) => client.short_name(), Self::UnidirectionalChannelPath(ref path) => path.short_name(), + Self::Channel(ref channel) => channel.short_name(), } } @@ -174,6 +212,96 @@ impl Object { .into()) } + /// Build the object associated with the given [`OpenInit`] event. + pub fn for_open_init_channel( + e: &Attributes, + src_chain: &dyn ChainHandle, + ) -> Result { + let channel_id = e + .channel_id() + .as_ref() + .ok_or_else(|| format!("channel_id missing in OpenInit event '{:?}'", e))?; + + let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id()); + + if dst_chain_id.is_err() { + return Err("dest chain missing in init".into()); + } + + Ok(Channel { + dst_chain_id: dst_chain_id.unwrap(), + src_chain_id: src_chain.id(), + src_channel_id: channel_id.clone(), + src_port_id: e.port_id().clone(), + } + .into()) + } + + /// Build the object associated with the given [`OpenTry`] event. + pub fn for_open_try_channel( + e: &Attributes, + src_chain: &dyn ChainHandle, + ) -> Result { + let channel_id = e + .channel_id() + .as_ref() + .ok_or_else(|| format!("channel_id missing in OpenTry event '{:?}'", e))?; + + let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id()); + + if dst_chain_id.is_err() { + return Err("dest chain missing in OpenTry".into()); + } + + Ok(Channel { + dst_chain_id: dst_chain_id.unwrap(), + src_chain_id: src_chain.id(), + src_channel_id: e.channel_id().clone().unwrap(), + src_port_id: e.port_id().clone(), + } + .into()) + } + + pub fn for_open_ack_channel( + e: &Attributes, + src_chain: &dyn ChainHandle, + ) -> Result { + let channel_id = e + .channel_id() + .as_ref() + .ok_or_else(|| format!("channel_id missing in OpenAck event '{:?}'", e))?; + + let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id())?; + + Ok(Channel { + dst_chain_id, + src_chain_id: src_chain.id(), + src_channel_id: e.channel_id().clone().unwrap(), + src_port_id: e.port_id().clone(), + } + .into()) + } + + pub fn for_open_confirm_channel( + e: &Attributes, + src_chain: &dyn ChainHandle, + ) -> Result { + let channel_id = e + .channel_id() + .as_ref() + .ok_or_else(|| format!("channel_id missing in OpenInit event '{:?}'", e))?; + + let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id())?; + + Ok(Channel { + dst_chain_id, + src_chain_id: src_chain.id(), + src_channel_id: e.channel_id().clone().unwrap(), + src_port_id: e.port_id().clone(), + } + .into()) + } + /// Build the object associated with the given [`SendPacket`] event. pub fn for_send_packet(e: &SendPacket, src_chain: &dyn ChainHandle) -> Result { let dst_chain_id = diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index 967f1ced5f..f2235678c1 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -6,7 +6,7 @@ use itertools::Itertools; use tracing::{debug, error, trace, warn}; use ibc::{ - events::{IbcEvent, VecIbcEvents}, + events::IbcEvent, ics02_client::client_state::ClientState, ics04_channel::channel::IdentifiedChannelEnd, ics24_host::identifier::ChainId, @@ -15,21 +15,20 @@ use ibc::{ use ibc_proto::ibc::core::channel::v1::QueryChannelsRequest; -use crate::channel::Channel as RelayChannel; - use crate::{ chain::{ - counterparty::channel_connection_client, + counterparty::{channel_connection_client,get_counterparty_chain_for_channel}, handle::{ChainHandle, ChainHandlePair}, }, config::Config, event::monitor::{EventBatch, UnwrapOrClone}, - object::{Client, Object, UnidirectionalChannelPath}, + object::{Client, Object, UnidirectionalChannelPath, Channel}, registry::Registry, util::recv_multiple, worker::{Worker, WorkerHandle}, }; + pub mod error; pub use error::Error; diff --git a/relayer/src/worker.rs b/relayer/src/worker.rs index b5242ed8b6..1b2576fa80 100644 --- a/relayer/src/worker.rs +++ b/relayer/src/worker.rs @@ -11,8 +11,9 @@ use crate::{ chain::handle::ChainHandlePair, foreign_client::{ForeignClient, ForeignClientError, MisbehaviourResults}, link::{Link, LinkParameters}, - object::{Client, Object, UnidirectionalChannelPath}, + object::{Client, Object, UnidirectionalChannelPath, Channel}, }; +use crate::channel::Channel as RelayChannel; mod handle; pub use handle::WorkerHandle; @@ -59,6 +60,7 @@ impl Worker { let result = match object { Object::UnidirectionalChannelPath(path) => self.run_uni_chan_path(path), Object::Client(client) => self.run_client(client), + Object::Channel(channel) => self.run_channel(channel), }; if let Err(e) = result { @@ -189,4 +191,72 @@ impl Worker { } } } + + /// Run the event loop for events associated with a [`Channel`]. + fn run_channel(self, channel: Channel) -> Result<(), BoxError> { + let done = '🥳'; + + let a_chain = self.chains.a.clone(); + let b_chain = self.chains.b.clone(); + + let mut handshake_channel; + + let mut first_iteration = true; + + loop { + if let Ok(cmd) = self.rx.try_recv() { + match cmd { + WorkerCmd::IbcEvents { batch } => { + for event in batch.events { + handshake_channel = RelayChannel::restore_from_event( + a_chain.clone(), + b_chain.clone(), + event.clone(), + )?; + let result = handshake_channel.handshake_step_with_event(event.clone()); + + match result { + Err(e) => { + debug!("\n Failed {:?} with error {:?} \n", event, e); + } + Ok(ev) => { + println!("{} => {:#?}\n", done, ev.clone()); + } + } + first_iteration = false; + } + } + WorkerCmd::NewBlock { + height: current_height, + new_block: _, + } => { + if first_iteration { + let height = current_height.decrement()?; + + let (h, state) = RelayChannel::restore_from_state( + a_chain.clone(), + b_chain.clone(), + channel.clone(), + height, + )?; + + handshake_channel = h; + + let result = handshake_channel.handshake_step_with_state(state); + + match result { + Err(e) => { + debug!("\n Failed with error {:?} \n", e); + } + Ok(ev) => { + println!("{} => {:#?}\n", done, ev.clone()); + } + } + first_iteration = false; + } + } + }; + } + } + } } From 3755d85cedd93d4e472af13c3f1cac4ec2a4a416 Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Wed, 12 May 2021 17:18:01 +0200 Subject: [PATCH 20/52] fmt --- relayer/src/channel.rs | 2 +- relayer/src/supervisor.rs | 12 ++++-------- relayer/src/worker.rs | 6 +++--- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index c285768771..e63498feb5 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -20,9 +20,9 @@ use crate::chain::handle::ChainHandle; use crate::connection::Connection; use crate::error::Error; use crate::foreign_client::{ForeignClient, ForeignClientError}; +use crate::object::Channel as WorkerChannelObject; use crate::relay::MAX_ITER; use crate::supervisor::error::Error as WorkerChannelError; -use crate::object::Channel as WorkerChannelObject; use std::time::Duration; use ibc_proto::ibc::core::channel::v1::QueryConnectionChannelsRequest; diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index f2235678c1..f372c94b8d 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -6,29 +6,25 @@ use itertools::Itertools; use tracing::{debug, error, trace, warn}; use ibc::{ - events::IbcEvent, - ics02_client::client_state::ClientState, - ics04_channel::channel::IdentifiedChannelEnd, - ics24_host::identifier::ChainId, - Height, + events::IbcEvent, ics02_client::client_state::ClientState, + ics04_channel::channel::IdentifiedChannelEnd, ics24_host::identifier::ChainId, Height, }; use ibc_proto::ibc::core::channel::v1::QueryChannelsRequest; use crate::{ chain::{ - counterparty::{channel_connection_client,get_counterparty_chain_for_channel}, + counterparty::{channel_connection_client, get_counterparty_chain_for_channel}, handle::{ChainHandle, ChainHandlePair}, }, config::Config, event::monitor::{EventBatch, UnwrapOrClone}, - object::{Client, Object, UnidirectionalChannelPath, Channel}, + object::{Channel, Client, Object, UnidirectionalChannelPath}, registry::Registry, util::recv_multiple, worker::{Worker, WorkerHandle}, }; - pub mod error; pub use error::Error; diff --git a/relayer/src/worker.rs b/relayer/src/worker.rs index 1b2576fa80..2cb8730254 100644 --- a/relayer/src/worker.rs +++ b/relayer/src/worker.rs @@ -7,13 +7,13 @@ use tracing::{debug, error, error_span, info, trace, warn}; use ibc::{events::IbcEvent, ics02_client::events::UpdateClient}; +use crate::channel::Channel as RelayChannel; use crate::{ chain::handle::ChainHandlePair, foreign_client::{ForeignClient, ForeignClientError, MisbehaviourResults}, link::{Link, LinkParameters}, - object::{Client, Object, UnidirectionalChannelPath, Channel}, + object::{Channel, Client, Object, UnidirectionalChannelPath}, }; -use crate::channel::Channel as RelayChannel; mod handle; pub use handle::WorkerHandle; @@ -197,7 +197,7 @@ impl Worker { let done = '🥳'; let a_chain = self.chains.a.clone(); - let b_chain = self.chains.b.clone(); + let b_chain = self.chains.b.clone(); let mut handshake_channel; From b3919565993f6386605bbc975bbc8754ae2bcdeb Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Wed, 12 May 2021 17:42:40 +0200 Subject: [PATCH 21/52] fmt + clippy --- relayer/src/chain/counterparty.rs | 8 -------- relayer/src/channel.rs | 11 +++++------ relayer/src/supervisor.rs | 7 +------ relayer/src/supervisor/error.rs | 3 --- 4 files changed, 6 insertions(+), 23 deletions(-) diff --git a/relayer/src/chain/counterparty.rs b/relayer/src/chain/counterparty.rs index 43435e5fa9..ca189162e7 100644 --- a/relayer/src/chain/counterparty.rs +++ b/relayer/src/chain/counterparty.rs @@ -115,13 +115,5 @@ pub fn get_counterparty_chain_for_channel( .query_client_state(&client_id, Height::zero()) .map_err(|e| Error::QueryFailed(format!("{}", e)))?; - // trace!( - // chain_id=%chain.id(), port_id=%port_id, channel_id=%channel_id, - // "counterparty chain: {}", client_state.chain_id() - // ); - //let counterparty_chain_id = client_state.chain_id(); - // let counterparty_chain = self.registry - // .get_or_spawn(&client_state.chain_id())?; - Ok(client_state.chain_id()) } diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index e63498feb5..0d7870e079 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -148,7 +148,7 @@ impl Channel { pub fn restore_from_event( chain: Box, counterparty_chain: Box, - channel_open_event: IbcEvent, + mut channel_open_event: IbcEvent, ) -> Result { match channel_open_event.clone() { IbcEvent::OpenInitChannel(_open_init) => {} @@ -176,7 +176,7 @@ impl Channel { .clone(); let port_id = channel_open_event.clone().attributes().port_id.clone(); - let channel_id = channel_open_event.clone().attributes().channel_id.clone(); + let channel_id = channel_open_event.attributes().channel_id.clone(); let counterparty_connection_id = match connection.counterparty().connection_id() { Some(x) => x.clone(), @@ -262,7 +262,6 @@ impl Channel { == channel.src_channel_id.clone() { handshake_channel.b_side.channel_id = Some(chan.channel_id.clone()); - break; } } @@ -452,9 +451,9 @@ impl Channel { match event { IbcEvent::OpenInitChannel(_open_init) => { // There is a race here: for the same source channel s, in Init, - // another chan_open_try with -s src_chan (destination d) can come from the user and if it is - // executed first on the chain, before the one send by the relayer, - // the later will create a new channel (d' != d) stuck in TryOpen whose counterparty is s + // another chan_open_try with source s (that creates destination d) can come from the user and if it is + // executed first on the chain, before the one send by the relayer. + // In this case the relayer will create a new channel (d' != d) stuck in TryOpen whose counterparty is s // There is no way to avoid it, we can add a check (like in handshake_step_with_state) but // it will slow down and there will still be a window where the behavior is possible. Ok(vec![self.build_chan_open_try_and_send()?]) diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index f372c94b8d..4e44a7eb04 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -222,7 +222,7 @@ impl Supervisor { let (client, channel) = match client_res { Ok(conn_client) => (conn_client.client, conn_client.channel), - Err(Error::ConnectionNotOpen(..)) | Err(Error::ChannelNotOpen(..)) => { + Err(Error::ConnectionNotOpen(..)) | Err(Error::ChannelUninitialized(..)) => { // These errors are silent. // Simply ignore the channel and return without spawning the workers. warn!( @@ -256,7 +256,6 @@ impl Supervisor { } if channel.channel_end.is_open() { - //if channel open { let counterparty_chain = self .registry .get_or_spawn(&client.client_state.chain_id())?; @@ -268,7 +267,6 @@ impl Supervisor { src_chain_id: client.client_state.chain_id(), }); - //if channel open self.worker_for_object(client_object, chain.clone(), counterparty_chain.clone()); // TODO: Only start the Uni worker if there are outstanding packets or ACKs. @@ -283,8 +281,6 @@ impl Supervisor { self.worker_for_object(path_object, chain.clone(), counterparty_chain.clone()); - //channel object - let counterparty_chain_id = get_counterparty_chain_for_channel(chain.as_ref(), channel.clone()).unwrap(); @@ -295,7 +291,6 @@ impl Supervisor { src_chain_id: chain.id(), src_channel_id: channel.channel_id.clone(), src_port_id: channel.port_id, - // connection_id: connection_id.clone(), }); self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); diff --git a/relayer/src/supervisor/error.rs b/relayer/src/supervisor/error.rs index c93beb70ec..78f72a87a9 100644 --- a/relayer/src/supervisor/error.rs +++ b/relayer/src/supervisor/error.rs @@ -4,9 +4,6 @@ use ibc::ics24_host::identifier::{ChainId, ChannelId, ConnectionId}; #[derive(Clone, Debug, Error, PartialEq, Eq)] pub enum Error { - #[error("channel {0} on chain {1} is not open")] - ChannelNotOpen(ChannelId, ChainId), - #[error("channel {0} on chain {1} is not open")] ChannelUninitialized(ChannelId, ChainId), From a031f7e300303a049604429533eb271bd94cce10 Mon Sep 17 00:00:00 2001 From: cezarad <9439384+cezarad@users.noreply.github.com> Date: Thu, 13 May 2021 18:42:59 +0200 Subject: [PATCH 22/52] refactor and add retry --- modules/src/events.rs | 12 ++-- relayer/src/channel.rs | 42 ++++++------ relayer/src/object.rs | 133 ++++++++++---------------------------- relayer/src/supervisor.rs | 72 +++++++++------------ relayer/src/worker.rs | 69 +++++++++++++++----- 5 files changed, 142 insertions(+), 186 deletions(-) diff --git a/modules/src/events.rs b/modules/src/events.rs index 4bf8176e6d..8b63d02ef0 100644 --- a/modules/src/events.rs +++ b/modules/src/events.rs @@ -185,13 +185,13 @@ impl IbcEvent { } } - pub fn attributes(&mut self) -> &ChannelAttributes { + pub fn channel_attributes(&mut self) -> Option<&ChannelAttributes> { match self { - IbcEvent::OpenInitChannel(ev) => ev.attributes(), - IbcEvent::OpenTryChannel(ev) => ev.attributes(), - IbcEvent::OpenAckChannel(ev) => ev.attributes(), - IbcEvent::OpenConfirmChannel(ev) => ev.attributes(), - _ => unimplemented!(), + IbcEvent::OpenInitChannel(ev) => Some(ev.attributes()), + IbcEvent::OpenTryChannel(ev) => Some(ev.attributes()), + IbcEvent::OpenAckChannel(ev) => Some(ev.attributes()), + IbcEvent::OpenConfirmChannel(ev) => Some(ev.attributes()), + _ => None, } } } diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 0d7870e079..1bac98ffce 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -150,33 +150,27 @@ impl Channel { counterparty_chain: Box, mut channel_open_event: IbcEvent, ) -> Result { - match channel_open_event.clone() { - IbcEvent::OpenInitChannel(_open_init) => {} - IbcEvent::OpenTryChannel(_open_try) => {} - IbcEvent::OpenAckChannel(_open_ack) => {} - IbcEvent::OpenConfirmChannel(_open_confirm) => {} - _ => return Err("Supported only for Channel Open Events".to_string().into()), + let channel_event_attributes = match channel_open_event.channel_attributes() { + None => { + return Err(ChannelError::Failed( + "A channel object must be build only from a channel event ".to_string(), + ) + .into()) + } + Some(attributes) => attributes, }; - let connection_id = channel_open_event - .clone() - .attributes() - .connection_id - .clone(); - let counterparty_port_id = channel_open_event - .clone() - .attributes() - .counterparty_port_id - .clone(); + let connection_id = channel_event_attributes.connection_id.clone(); + let counterparty_port_id = channel_event_attributes.counterparty_port_id.clone(); let connection = chain.query_connection(&connection_id, Height::zero())?; - let counterparty_channel_id = channel_open_event - .clone() - .attributes() - .counterparty_channel_id - .clone(); + let counterparty_channel_id = channel_event_attributes.counterparty_channel_id.clone(); - let port_id = channel_open_event.clone().attributes().port_id.clone(); - let channel_id = channel_open_event.attributes().channel_id.clone(); + let port_id = channel_event_attributes.port_id.clone(); + let channel_id = channel_event_attributes.channel_id.clone(); + + let version = counterparty_chain + .module_version(&port_id) + .map_err(|e| ChannelError::QueryError(counterparty_chain.id(), e))?; let counterparty_connection_id = match connection.counterparty().connection_id() { Some(x) => x.clone(), @@ -206,7 +200,7 @@ impl Channel { ), connection_delay: connection.delay_period(), //TODO detect version from event - version: Default::default(), + version: Some(version), }) } diff --git a/relayer/src/object.rs b/relayer/src/object.rs index d0b032feff..e6e5030de0 100644 --- a/relayer/src/object.rs +++ b/relayer/src/object.rs @@ -36,6 +36,32 @@ impl Client { } } +//Channel +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Channel { + /// Destination chain identifier. + pub dst_chain_id: ChainId, + + /// Source chain identifier. + pub src_chain_id: ChainId, + + /// Source channel identiier. + pub src_channel_id: ChannelId, + + /// Source port identiier. + pub src_port_id: PortId, + // pub connection_id: ConnectionId, +} + +impl Channel { + pub fn short_name(&self) -> String { + format!( + "{}/{}:{} -> {}", + self.src_channel_id, self.src_port_id, self.src_chain_id, self.dst_chain_id, + ) + } +} + /// A unidirectional path from a source chain, channel and port. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct UnidirectionalChannelPath { @@ -71,10 +97,10 @@ impl UnidirectionalChannelPath { pub enum Object { /// See [`Client`]. Client(Client), - /// See [`UnidirectionalChannelPath`]. - UnidirectionalChannelPath(UnidirectionalChannelPath), /// See [`Channel`]. Channel(Channel), + /// See [`UnidirectionalChannelPath`]. + UnidirectionalChannelPath(UnidirectionalChannelPath), } impl Object { @@ -96,41 +122,15 @@ impl From for Object { } } -impl From for Object { - fn from(p: UnidirectionalChannelPath) -> Self { - Self::UnidirectionalChannelPath(p) - } -} - impl From for Object { fn from(c: Channel) -> Self { Self::Channel(c) } } -//Channel -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Channel { - /// Destination chain identifier. - pub dst_chain_id: ChainId, - - /// Source chain identifier. - pub src_chain_id: ChainId, - - /// Source channel identiier. - pub src_channel_id: ChannelId, - - /// Source port identiier. - pub src_port_id: PortId, - // pub connection_id: ConnectionId, -} - -impl Channel { - pub fn short_name(&self) -> String { - format!( - "{}/{}:{} -> {}", - self.src_channel_id, self.src_port_id, self.src_chain_id, self.dst_chain_id, - ) +impl From for Object { + fn from(p: UnidirectionalChannelPath) -> Self { + Self::UnidirectionalChannelPath(p) } } @@ -185,7 +185,7 @@ impl Object { } /// Build the client object associated with the given channel event attributes. - pub fn for_chan_open_events( + pub fn client_from_chan_open_events( e: &Attributes, dst_chain: &dyn ChainHandle, ) -> Result { @@ -212,8 +212,8 @@ impl Object { .into()) } - /// Build the object associated with the given [`OpenInit`] event. - pub fn for_open_init_channel( + /// Build the Channel object associated with the given [`Open`] channel event. + pub fn channel_from_chan_open_events( e: &Attributes, src_chain: &dyn ChainHandle, ) -> Result { @@ -237,71 +237,6 @@ impl Object { .into()) } - /// Build the object associated with the given [`OpenTry`] event. - pub fn for_open_try_channel( - e: &Attributes, - src_chain: &dyn ChainHandle, - ) -> Result { - let channel_id = e - .channel_id() - .as_ref() - .ok_or_else(|| format!("channel_id missing in OpenTry event '{:?}'", e))?; - - let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id()); - - if dst_chain_id.is_err() { - return Err("dest chain missing in OpenTry".into()); - } - - Ok(Channel { - dst_chain_id: dst_chain_id.unwrap(), - src_chain_id: src_chain.id(), - src_channel_id: e.channel_id().clone().unwrap(), - src_port_id: e.port_id().clone(), - } - .into()) - } - - pub fn for_open_ack_channel( - e: &Attributes, - src_chain: &dyn ChainHandle, - ) -> Result { - let channel_id = e - .channel_id() - .as_ref() - .ok_or_else(|| format!("channel_id missing in OpenAck event '{:?}'", e))?; - - let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id())?; - - Ok(Channel { - dst_chain_id, - src_chain_id: src_chain.id(), - src_channel_id: e.channel_id().clone().unwrap(), - src_port_id: e.port_id().clone(), - } - .into()) - } - - pub fn for_open_confirm_channel( - e: &Attributes, - src_chain: &dyn ChainHandle, - ) -> Result { - let channel_id = e - .channel_id() - .as_ref() - .ok_or_else(|| format!("channel_id missing in OpenInit event '{:?}'", e))?; - - let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id())?; - - Ok(Channel { - dst_chain_id, - src_chain_id: src_chain.id(), - src_channel_id: e.channel_id().clone().unwrap(), - src_port_id: e.port_id().clone(), - } - .into()) - } - /// Build the object associated with the given [`SendPacket`] event. pub fn for_send_packet(e: &SendPacket, src_chain: &dyn ChainHandle) -> Result { let dst_chain_id = diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index 4e44a7eb04..3c2c65da0c 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -72,18 +72,20 @@ impl Supervisor { } } - IbcEvent::OpenInitChannel(ref open_init) => { - if let Ok(object) = - Object::for_open_init_channel(open_init.attributes(), src_chain) - { + IbcEvent::OpenInitChannel(ref _open_init) => { + if let Ok(object) = Object::channel_from_chan_open_events( + event.clone().channel_attributes().unwrap(), + src_chain, + ) { collected.per_object.entry(object).or_default().push(event); } } - IbcEvent::OpenTryChannel(ref open_try) => { - if let Ok(object) = - Object::for_open_try_channel(open_try.attributes(), src_chain) - { + IbcEvent::OpenTryChannel(ref _open_try) => { + if let Ok(object) = Object::channel_from_chan_open_events( + event.clone().channel_attributes().unwrap(), + src_chain, + ) { collected.per_object.entry(object).or_default().push(event); } } @@ -91,7 +93,7 @@ impl Supervisor { IbcEvent::OpenAckChannel(ref open_ack) => { // Create client worker here as channel end must be opened if let Ok(object) = - Object::for_chan_open_events(open_ack.attributes(), src_chain) + Object::client_from_chan_open_events(open_ack.attributes(), src_chain) { collected .per_object @@ -100,9 +102,10 @@ impl Supervisor { .push(event.clone()); } - if let Ok(channel_object) = - Object::for_open_ack_channel(open_ack.attributes(), src_chain) - { + if let Ok(channel_object) = Object::channel_from_chan_open_events( + event.clone().channel_attributes().unwrap(), + src_chain, + ) { collected .per_object .entry(channel_object) @@ -113,7 +116,7 @@ impl Supervisor { IbcEvent::OpenConfirmChannel(ref open_confirm) => { // Create client worker here as channel end must be opened if let Ok(object) = - Object::for_chan_open_events(open_confirm.attributes(), src_chain) + Object::client_from_chan_open_events(open_confirm.attributes(), src_chain) { collected .per_object @@ -121,9 +124,10 @@ impl Supervisor { .or_default() .push(event.clone()); } - if let Ok(channel_object) = - Object::for_open_confirm_channel(open_confirm.attributes(), src_chain) - { + if let Ok(channel_object) = Object::channel_from_chan_open_events( + event.clone().channel_attributes().unwrap(), + src_chain, + ) { collected .per_object .entry(channel_object) @@ -280,35 +284,21 @@ impl Supervisor { }); self.worker_for_object(path_object, chain.clone(), counterparty_chain.clone()); + } - let counterparty_chain_id = - get_counterparty_chain_for_channel(chain.as_ref(), channel.clone()).unwrap(); - - let counterparty_chain = self.registry.get_or_spawn(&counterparty_chain_id)?; - - let channel_object = Object::Channel(Channel { - dst_chain_id: counterparty_chain_id, - src_chain_id: chain.id(), - src_channel_id: channel.channel_id.clone(), - src_port_id: channel.port_id, - }); - - self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); - } else { - let counterparty_chain_id = - get_counterparty_chain_for_channel(chain.as_ref(), channel.clone()).unwrap(); + let counterparty_chain_id = + get_counterparty_chain_for_channel(chain.as_ref(), channel.clone()).unwrap(); - let counterparty_chain = self.registry.get_or_spawn(&counterparty_chain_id)?; + let counterparty_chain = self.registry.get_or_spawn(&counterparty_chain_id)?; - let channel_object = Object::Channel(Channel { - dst_chain_id: counterparty_chain_id, - src_chain_id: chain.id(), - src_channel_id: channel.channel_id.clone(), - src_port_id: channel.port_id, - }); + let channel_object = Object::Channel(Channel { + dst_chain_id: counterparty_chain_id, + src_chain_id: chain.id(), + src_channel_id: channel.channel_id.clone(), + src_port_id: channel.port_id, + }); - self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); - } + self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); Ok(()) } diff --git a/relayer/src/worker.rs b/relayer/src/worker.rs index 2cb8730254..1078635bf8 100644 --- a/relayer/src/worker.rs +++ b/relayer/src/worker.rs @@ -7,13 +7,16 @@ use tracing::{debug, error, error_span, info, trace, warn}; use ibc::{events::IbcEvent, ics02_client::events::UpdateClient}; -use crate::channel::Channel as RelayChannel; use crate::{ chain::handle::ChainHandlePair, foreign_client::{ForeignClient, ForeignClientError, MisbehaviourResults}, link::{Link, LinkParameters}, object::{Channel, Client, Object, UnidirectionalChannelPath}, }; +use crate::{ + channel::{Channel as RelayChannel, ChannelError}, + relay::MAX_ITER, +}; mod handle; pub use handle::WorkerHandle; @@ -213,16 +216,34 @@ impl Worker { b_chain.clone(), event.clone(), )?; - let result = handshake_channel.handshake_step_with_event(event.clone()); - match result { - Err(e) => { - debug!("\n Failed {:?} with error {:?} \n", event, e); - } - Ok(ev) => { - println!("{} => {:#?}\n", done, ev.clone()); + let mut counter = 0; + let mut success = false; + while counter < MAX_ITER && !success { + counter += 1; + + let result = + handshake_channel.handshake_step_with_event(event.clone()); + + match result { + Err(e) => { + debug!("\n Failed {:?} with error {:?} \n", event, e); + } + Ok(ev) => { + success = true; + println!("{} => {:#?}\n", done, ev.clone()); + } } } + // Check that the channel was created on a_chain + if !success { + return Err(ChannelError::Failed(format!( + "Failed to finish channel open init in {} iterations for {:?}", + MAX_ITER, handshake_channel + )) + .into()); + }; + first_iteration = false; } } @@ -242,16 +263,32 @@ impl Worker { handshake_channel = h; - let result = handshake_channel.handshake_step_with_state(state); - - match result { - Err(e) => { - debug!("\n Failed with error {:?} \n", e); - } - Ok(ev) => { - println!("{} => {:#?}\n", done, ev.clone()); + let mut counter = 0; + let mut success = false; + while counter < MAX_ITER && !success { + counter += 1; + + let result = handshake_channel.handshake_step_with_state(state); + + match result { + Err(e) => { + debug!("\n Failed with error {:?} \n", e); + } + Ok(ev) => { + success = true; + println!("{} => {:#?}\n", done, ev.clone()); + } } } + // Check that the channel was created on a_chain + if !success { + return Err(ChannelError::Failed(format!( + "Failed to finish channel open {} iterations for {:?}", + MAX_ITER, handshake_channel + )) + .into()); + }; + first_iteration = false; } } From 9103414812fb6c65b466e21a4b1795b53897b2a5 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Mon, 17 May 2021 08:50:31 +0200 Subject: [PATCH 23/52] Reorg and fixes --- relayer/src/chain/counterparty.rs | 21 ------- relayer/src/channel.rs | 100 ++++++++++++++++++++---------- relayer/src/connection.rs | 2 + relayer/src/object.rs | 3 - relayer/src/supervisor.rs | 25 +++----- relayer/src/worker.rs | 77 ++++++++++++----------- 6 files changed, 122 insertions(+), 106 deletions(-) diff --git a/relayer/src/chain/counterparty.rs b/relayer/src/chain/counterparty.rs index ca189162e7..8b18271fe3 100644 --- a/relayer/src/chain/counterparty.rs +++ b/relayer/src/chain/counterparty.rs @@ -96,24 +96,3 @@ pub fn get_counterparty_chain( channel_connection_client(src_chain, src_port_id, src_channel_id) .map(|c| c.client.client_state.chain_id()) } - -pub fn get_counterparty_chain_for_channel( - chain: &dyn ChainHandle, - channel: IdentifiedChannelEnd, -) -> Result { - let connection_id = channel - .channel_end - .connection_hops() - .first() - .ok_or_else(|| Error::MissingConnectionHops(channel.channel_id.clone(), chain.id()))?; - - let connection_end = chain - .query_connection(&connection_id, Height::zero()) - .map_err(|e| Error::QueryFailed(format!("{}", e)))?; - let client_id = connection_end.client_id(); - let client_state = chain - .query_client_state(&client_id, Height::zero()) - .map_err(|e| Error::QueryFailed(format!("{}", e)))?; - - Ok(client_state.chain_id()) -} diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 67270896fa..6dc5af3891 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -2,7 +2,7 @@ use anomaly::BoxError; use prost_types::Any; use serde::Serialize; use thiserror::Error; -use tracing::error; +use tracing::{debug, error}; use ibc::events::IbcEvent; use ibc::ics04_channel::channel::{ChannelEnd, Counterparty, IdentifiedChannelEnd, Order, State}; @@ -214,50 +214,52 @@ impl Channel { let a_channel = chain.query_channel(&channel.src_port_id, &channel.src_channel_id, height)?; - let connection_id = a_channel.connection_hops().first().ok_or_else(|| { + let a_connection_id = a_channel.connection_hops().first().ok_or_else(|| { WorkerChannelError::MissingConnectionHops(channel.src_channel_id.clone(), chain.id()) })?; - let connection = chain.query_connection(&connection_id, Height::zero())?; + let a_connection = chain.query_connection(&a_connection_id, Height::zero())?; let mut handshake_channel = Channel { ordering: *a_channel.ordering(), a_side: ChannelSide::new( chain.clone(), - connection.client_id().clone(), - connection_id.clone(), + a_connection.client_id().clone(), + a_connection_id.clone(), channel.src_port_id.clone(), Some(channel.src_channel_id.clone()), ), b_side: ChannelSide::new( counterparty_chain.clone(), - connection.counterparty().client_id().clone(), - connection.counterparty().connection_id().unwrap().clone(), + a_connection.counterparty().client_id().clone(), + a_connection.counterparty().connection_id().unwrap().clone(), a_channel.remote.port_id.clone(), a_channel.remote.channel_id.clone(), ), - connection_delay: connection.delay_period(), + connection_delay: a_connection.delay_period(), version: Some(a_channel.version.clone()), }; if a_channel.state_matches(&ibc::ics04_channel::channel::State::Init) && a_channel.remote.channel_id.is_none() { - let req = QueryConnectionChannelsRequest { - connection: connection_id.to_string(), - pagination: ibc_proto::cosmos::base::query::pagination::all(), - }; - - let channels: Vec = - counterparty_chain.query_connection_channels(req)?; - - for chan in channels.iter() { - if chan.channel_end.remote.channel_id.is_some() - && chan.channel_end.remote.channel_id.clone().unwrap() - == channel.src_channel_id.clone() - { - handshake_channel.b_side.channel_id = Some(chan.channel_id.clone()); - break; + if let Some(b_connection_id) = a_connection.counterparty().connection_id() { + let req = QueryConnectionChannelsRequest { + connection: b_connection_id.to_string(), + pagination: ibc_proto::cosmos::base::query::pagination::all(), + }; + + let channels: Vec = + counterparty_chain.query_connection_channels(req)?; + + for chan in channels.iter() { + if chan.channel_end.remote.channel_id.is_some() + && chan.channel_end.remote.channel_id.clone().unwrap() + == channel.src_channel_id.clone() + { + handshake_channel.b_side.channel_id = Some(chan.channel_id.clone()); + break; + } } } } @@ -443,6 +445,29 @@ impl Channel { &mut self, event: IbcEvent, ) -> Result, ChannelError> { + // highest expected state on destination + let expected_state = match event { + IbcEvent::OpenTryChannel(_) => State::Init, + IbcEvent::OpenAckChannel(_) => State::TryOpen, + IbcEvent::OpenConfirmChannel(_) => State::TryOpen, + _ => State::Uninitialized, + }; + + // TODO - consider move of this `if` into the actual build functions + // Get the channel on destination and if it exists check its state + if let Some(dst_channel_id) = self.dst_channel_id() { + let dst_channel = + self.dst_chain() + .query_channel(&self.dst_port_id(), dst_channel_id, Height::zero()); + if let Ok(counterparty_channel) = dst_channel { + if counterparty_channel.state as u32 > expected_state as u32 { + // The state of channel on destination is already higher than + // what this handshake step is trying to achieve + return Ok(vec![]); + } + }; + } + match event { IbcEvent::OpenInitChannel(_open_init) => { // There is a race here: for the same source channel s, in Init, @@ -466,6 +491,21 @@ impl Channel { &mut self, state: State, ) -> Result, ChannelError> { + // TODO - consider move of this `if` into the actual build functions + // Get the channel on destination and if it exists check its state + if let Some(dst_channel_id) = self.dst_channel_id() { + let dst_channel = + self.dst_chain() + .query_channel(&self.dst_port_id(), dst_channel_id, Height::zero()); + if let Ok(counterparty_channel) = dst_channel { + if counterparty_channel.state as u32 > state as u32 { + // The state of channel on destination is already higher than + // what this handshake step is trying to achieve + return Ok(vec![]); + } + }; + } + match state { ibc::ics04_channel::channel::State::Init => { Ok(vec![self.build_chan_open_try_and_send()?]) @@ -489,7 +529,7 @@ impl Channel { RetryResult::Retry(index) } Ok(ev) => { - println!("{} => {:#?}\n", done, ev); + debug!("{} => {:#?}\n", done, ev); RetryResult::Ok(()) } } @@ -504,7 +544,7 @@ impl Channel { RetryResult::Retry(index) } Ok(ev) => { - println!("{} => {:#?}\n", done, ev); + debug!("{} => {:#?}\n", done, ev); RetryResult::Ok(()) } } @@ -652,11 +692,13 @@ impl Channel { ) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; + // TODO - remove this as now the query ^ retuns error or.. + // consider reverting the change and keep Uninit for non existing channels // Check if a connection is expected to exist on destination chain // A channel must exist on destination chain for Ack and Confirm Tx-es to succeed if dst_channel.state_matches(&State::Uninitialized) { return Err(ChannelError::Failed( - "missing channel on source chain".to_string(), + "missing channel on destination chain".to_string(), )); } @@ -748,12 +790,6 @@ impl Channel { } pub fn build_chan_open_try_and_send(&self) -> Result { - if self.b_side.channel_id().is_some() { - return Err(ChannelError::Failed( - "Counterparty channel defined".to_string(), - )); - }; - let dst_msgs = self.build_chan_open_try()?; let events = self diff --git a/relayer/src/connection.rs b/relayer/src/connection.rs index 716916ab86..3ea3c8ba51 100644 --- a/relayer/src/connection.rs +++ b/relayer/src/connection.rs @@ -391,6 +391,8 @@ impl Connection { .query_connection(self.dst_connection_id(), ICSHeight::default()) .map_err(|e| ConnectionError::QueryError(self.dst_chain().id(), e))?; + // TODO - remove this as now the query ^ retuns error or.. + // consider reverting the change and keep Uninit for non existing connections // Check if a connection is expected to exist on destination chain // A connection must exist on destination chain for Ack and Confirm Tx-es to succeed if dst_connection.state_matches(&State::Uninitialized) { diff --git a/relayer/src/object.rs b/relayer/src/object.rs index 75c472e73f..c84e345242 100644 --- a/relayer/src/object.rs +++ b/relayer/src/object.rs @@ -50,8 +50,6 @@ pub struct Channel { /// Source port identiier. pub src_port_id: PortId, - // pub connection_id: ConnectionId, - pub clear_pending: bool, } impl Channel { @@ -234,7 +232,6 @@ impl Object { src_chain_id: src_chain.id(), src_channel_id: channel_id.clone(), src_port_id: e.port_id().clone(), - clear_pending: false, } .into()) } diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index b4c9187a93..ba6bc12a45 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -15,7 +15,7 @@ use ibc_proto::ibc::core::channel::v1::QueryChannelsRequest; use crate::{ chain::{ - counterparty::{channel_connection_client, get_counterparty_chain_for_channel}, + counterparty::channel_connection_client, handle::{ChainHandle, ChainHandlePair}, }, config::Config, @@ -234,7 +234,10 @@ impl Supervisor { channel_connection_client(chain.as_ref(), &channel.port_id, &channel.channel_id); let (client, channel) = match client_res { - Ok(conn_client) => (conn_client.client, conn_client.channel), + Ok(conn_client) => { + trace!("channel, connection, client {:?}", conn_client); + (conn_client.client, conn_client.channel) + } Err(Error::ConnectionNotOpen(..)) | Err(Error::ChannelUninitialized(..)) => { // These errors are silent. // Simply ignore the channel and return without spawning the workers. @@ -258,8 +261,6 @@ impl Supervisor { } }; - trace!("Obtained client id {:?}", client.client_id); - if self .config .find_chain(&client.client_state.chain_id()) @@ -269,11 +270,11 @@ impl Supervisor { return Ok(()); } - if channel.channel_end.is_open() { - let counterparty_chain = self - .registry - .get_or_spawn(&client.client_state.chain_id())?; + let counterparty_chain = self + .registry + .get_or_spawn(&client.client_state.chain_id())?; + if channel.channel_end.is_open() { // create the client object and spawn worker let client_object = Object::Client(Client { dst_client_id: client.client_id.clone(), @@ -295,17 +296,11 @@ impl Supervisor { self.worker_for_object(path_object, chain.clone(), counterparty_chain.clone()); } else { - let counterparty_chain_id = - get_counterparty_chain_for_channel(chain.as_ref(), channel.clone()).unwrap(); - - let counterparty_chain = self.registry.get_or_spawn(&counterparty_chain_id)?; - let channel_object = Object::Channel(Channel { - dst_chain_id: counterparty_chain_id, + dst_chain_id: counterparty_chain.clone().id(), src_chain_id: chain.id(), src_channel_id: channel.channel_id.clone(), src_port_id: channel.port_id, - clear_pending: false, }); self.worker_for_object(channel_object, chain.clone(), counterparty_chain.clone()); diff --git a/relayer/src/worker.rs b/relayer/src/worker.rs index a8cf45d1e9..93e137cfd6 100644 --- a/relayer/src/worker.rs +++ b/relayer/src/worker.rs @@ -251,49 +251,55 @@ impl Worker { } /// Run the event loop for events associated with a [`Channel`]. - fn run_channel(self, mut channel: Channel) -> Result<(), BoxError> { + fn run_channel(self, channel: Channel) -> Result<(), BoxError> { let a_chain = self.chains.a.clone(); let b_chain = self.chains.b.clone(); let mut handshake_channel; - channel.clear_pending = true; + // Flag that indicates if the worker should actively resume handshake. + // Set on start or when event based handshake fails. + let mut resume_handshake = true; loop { + thread::sleep(Duration::from_millis(200)); + if let Ok(cmd) = self.cmd_rx.try_recv() { - match cmd { + let result = match cmd { WorkerCmd::IbcEvents { batch } => { + // only take the last event in the queue + let mut last_event = None; for event in batch.events { - handshake_channel = RelayChannel::restore_from_event( - a_chain.clone(), - b_chain.clone(), - event.clone(), - )?; - - let result = + // TODO - verify the events are in increased state order + last_event = Some(event); + } + debug!("channel worker start processing {:#?}", last_event); + match last_event { + Some(event) => { + handshake_channel = RelayChannel::restore_from_event( + a_chain.clone(), + b_chain.clone(), + event.clone(), + )?; retry_with_index(retry_strategy::uni_chan_path(), |index| { handshake_channel.step_event(event.clone(), index) - }); - if let Err(retries) = result { - warn!( - "Channel worker failed to process event batch after {} retries", - retries - ); - - // Resume handshake on next iteration. - channel.clear_pending = true; - } else { - channel.clear_pending = false; + }) } + None => Ok(()), } } WorkerCmd::NewBlock { height: current_height, new_block: _, } => { - if !channel.clear_pending { + if !resume_handshake { continue; } + debug!( + "channel worker is processing block event at {:#?}", + current_height + ); + let height = current_height.decrement()?; let (mut handshake_channel, state) = RelayChannel::restore_from_state( @@ -303,21 +309,22 @@ impl Worker { height, )?; - let result = retry_with_index(retry_strategy::uni_chan_path(), |index| { + retry_with_index(retry_strategy::uni_chan_path(), |index| { handshake_channel.step_state(state, index) - }); - if let Err(retries) = result { - warn!( - "Channel worker failed to process event batch after {} retries", - retries - ); - - // Resume handshake on next iteration. - channel.clear_pending = true; - } else { - channel.clear_pending = false; - } + }) } + }; + + if let Err(retries) = result { + warn!( + "Channel worker failed to process event batch after {} retries", + retries + ); + + // Resume handshake on next iteration. + resume_handshake = true; + } else { + resume_handshake = false; } } } From 835282875882e0863333a7bd18407af4a5315cc2 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Mon, 17 May 2021 10:06:07 +0200 Subject: [PATCH 24/52] Don't spawn channel worker if it cannot advance state --- modules/src/ics04_channel/channel.rs | 3 ++ relayer/src/chain/counterparty.rs | 1 + relayer/src/object.rs | 2 +- relayer/src/supervisor.rs | 55 +++++++++++++++++++++++++--- 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/modules/src/ics04_channel/channel.rs b/modules/src/ics04_channel/channel.rs index 2f723ddcad..c59cba5c6f 100644 --- a/modules/src/ics04_channel/channel.rs +++ b/modules/src/ics04_channel/channel.rs @@ -404,6 +404,9 @@ impl State { _ => fail!(error::Kind::UnknownState, s), } } + pub fn is_open(self) -> bool { + self == State::Open + } } /// Provides a `to_string` method. diff --git a/relayer/src/chain/counterparty.rs b/relayer/src/chain/counterparty.rs index 8b18271fe3..208ef2046d 100644 --- a/relayer/src/chain/counterparty.rs +++ b/relayer/src/chain/counterparty.rs @@ -50,6 +50,7 @@ pub fn channel_connection_client( .query_channel(port_id, channel_id, Height::zero()) .map_err(|e| Error::QueryFailed(format!("{}", e)))?; + // TODO - query_channel doesn't return uninitialized for non-existing channels anymore if channel_end.state_matches(&ibc::ics04_channel::channel::State::Uninitialized) { return Err(Error::ChannelUninitialized(channel_id.clone(), chain.id())); } diff --git a/relayer/src/object.rs b/relayer/src/object.rs index c84e345242..6b907dead6 100644 --- a/relayer/src/object.rs +++ b/relayer/src/object.rs @@ -191,7 +191,7 @@ impl Object { let channel_id = e .channel_id() .as_ref() - .ok_or_else(|| format!("channel_id missing in OpenAck event '{:?}'", e))?; + .ok_or_else(|| format!("channel_id missing in channel open event '{:?}'", e))?; let client = channel_connection_client(dst_chain, e.port_id(), channel_id)?.client; if client.client_state.refresh_period().is_none() { diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index ba6bc12a45..b64614a367 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -11,7 +11,7 @@ use ibc::{ ics04_channel::channel::IdentifiedChannelEnd, ics24_host::identifier::ChainId, Height, }; -use ibc_proto::ibc::core::channel::v1::QueryChannelsRequest; +use ibc_proto::ibc::core::channel::v1::{QueryChannelsRequest, QueryConnectionChannelsRequest}; use crate::{ chain::{ @@ -31,6 +31,7 @@ use crate::{ pub mod error; pub use error::Error; +use ibc::ics04_channel::channel::State; /// The supervisor listens for events on multiple pairs of chains, /// and dispatches the events it receives to the appropriate @@ -233,10 +234,14 @@ impl Supervisor { let client_res = channel_connection_client(chain.as_ref(), &channel.port_id, &channel.channel_id); - let (client, channel) = match client_res { + let (client, connection, channel) = match client_res { Ok(conn_client) => { trace!("channel, connection, client {:?}", conn_client); - (conn_client.client, conn_client.channel) + ( + conn_client.client, + conn_client.connection, + conn_client.channel, + ) } Err(Error::ConnectionNotOpen(..)) | Err(Error::ChannelUninitialized(..)) => { // These errors are silent. @@ -274,7 +279,46 @@ impl Supervisor { .registry .get_or_spawn(&client.client_state.chain_id())?; - if channel.channel_end.is_open() { + let local_state = channel.channel_end.state; + let remote_state = if let Some(remote_channel_id) = channel.channel_end.remote.channel_id() + { + counterparty_chain + .query_channel( + channel.channel_end.remote.port_id(), + remote_channel_id, + Height::zero(), + )? + .state + } else { + let mut remote_state = State::Uninitialized; + // TODO - refactor + if let Some(remote_connection_id) = connection.end().counterparty().connection_id() { + let req = QueryConnectionChannelsRequest { + connection: remote_connection_id.to_string(), + pagination: ibc_proto::cosmos::base::query::pagination::all(), + }; + let channels = counterparty_chain.query_connection_channels(req)?; + + for remote_channel in channels.iter() { + if remote_channel.channel_end.remote.channel_id.is_some() + && remote_channel + .channel_end + .remote + .channel_id + .clone() + .unwrap() + == channel.channel_id.clone() + { + remote_state = remote_channel.channel_end.state; + break; + } + } + } + remote_state + }; + + error!("LOCAL STATE {} REMOTE STATE {}", local_state, remote_state); + if local_state.is_open() && remote_state.is_open() { // create the client object and spawn worker let client_object = Object::Client(Client { dst_client_id: client.client_id.clone(), @@ -295,7 +339,8 @@ impl Supervisor { }); self.worker_for_object(path_object, chain.clone(), counterparty_chain.clone()); - } else { + } else if remote_state as u32 <= local_state as u32 && !remote_state.is_open() { + // create worker for channel handshake that will advance the remote state let channel_object = Object::Channel(Channel { dst_chain_id: counterparty_chain.clone().id(), src_chain_id: chain.id(), From 2f125bb1194d8b860b40b9940873a9ab959bd992 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Tue, 18 May 2021 09:42:32 +0200 Subject: [PATCH 25/52] Small reorg --- relayer/src/chain/counterparty.rs | 61 +++++++++++++ relayer/src/channel.rs | 145 +++++++++++------------------- relayer/src/supervisor.rs | 56 ++---------- relayer/src/worker/handle.rs | 2 +- 4 files changed, 121 insertions(+), 143 deletions(-) diff --git a/relayer/src/chain/counterparty.rs b/relayer/src/chain/counterparty.rs index 208ef2046d..14a16e936d 100644 --- a/relayer/src/chain/counterparty.rs +++ b/relayer/src/chain/counterparty.rs @@ -12,6 +12,9 @@ use ibc::{ use crate::supervisor::Error; use super::handle::ChainHandle; +use ibc::ics04_channel::channel::{ChannelEnd, State}; +use ibc::ics24_host::identifier::ConnectionId; +use ibc_proto::ibc::core::channel::v1::QueryConnectionChannelsRequest; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ChannelConnectionClient { @@ -97,3 +100,61 @@ pub fn get_counterparty_chain( channel_connection_client(src_chain, src_port_id, src_channel_id) .map(|c| c.client.client_state.chain_id()) } + +fn channel_on_destination( + port_id: &PortId, + channel_id: &ChannelId, + counterparty_chain: &dyn ChainHandle, + remote_connection_id: &ConnectionId, +) -> Result, Error> { + let req = QueryConnectionChannelsRequest { + connection: remote_connection_id.to_string(), + pagination: ibc_proto::cosmos::base::query::pagination::all(), + }; + + let counterparty_channels = counterparty_chain + .query_connection_channels(req) + .map_err(|e| Error::QueryFailed(format!("{}", e)))?; + + for counterparty_channel in counterparty_channels.into_iter() { + let local_channel_end = &counterparty_channel.channel_end.remote; + if let Some(local_channel_id) = local_channel_end.channel_id() { + if local_channel_id == channel_id && local_channel_end.port_id() == port_id { + return Ok(Some(counterparty_channel.channel_end)); + } + } + } + Ok(None) +} + +pub fn channel_state_on_destination( + channel: IdentifiedChannelEnd, + connection: IdentifiedConnectionEnd, + counterparty_chain: &dyn ChainHandle, +) -> Result { + let counterparty_state = + if let Some(remote_channel_id) = channel.channel_end.remote.channel_id() { + counterparty_chain + .query_channel( + channel.channel_end.remote.port_id(), + remote_channel_id, + Height::zero(), + ) + .map_err(|e| Error::QueryFailed(format!("{}", e)))? + .state + } else if let Some(remote_connection_id) = connection.end().counterparty().connection_id() { + channel_on_destination( + &channel.port_id, + &channel.channel_id, + counterparty_chain, + remote_connection_id, + )? + .map_or_else( + || State::Uninitialized, + |remote_channel| remote_channel.state, + ) + } else { + State::Uninitialized + }; + Ok(counterparty_state) +} diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 6dc5af3891..ea1006c712 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -25,6 +25,7 @@ use crate::relay::MAX_ITER; use crate::supervisor::error::Error as WorkerChannelError; use std::time::Duration; +use crate::chain::counterparty::{channel_connection_client, channel_state_on_destination}; use crate::util::retry::RetryResult; use ibc_proto::ibc::core::channel::v1::QueryConnectionChannelsRequest; @@ -33,6 +34,9 @@ pub enum ChannelError { #[error("failed with underlying cause: {0}")] Failed(String), + #[error("failed due to missing local channel id")] + MissingLocalChannelId, + #[error("failed due to missing counterparty connection")] MissingCounterpartyConnection, @@ -441,91 +445,51 @@ impl Channel { ))) } - pub fn handshake_step_with_event( - &mut self, - event: IbcEvent, - ) -> Result, ChannelError> { - // highest expected state on destination - let expected_state = match event { - IbcEvent::OpenTryChannel(_) => State::Init, - IbcEvent::OpenAckChannel(_) => State::TryOpen, - IbcEvent::OpenConfirmChannel(_) => State::TryOpen, - _ => State::Uninitialized, - }; - - // TODO - consider move of this `if` into the actual build functions - // Get the channel on destination and if it exists check its state - if let Some(dst_channel_id) = self.dst_channel_id() { - let dst_channel = - self.dst_chain() - .query_channel(&self.dst_port_id(), dst_channel_id, Height::zero()); - if let Ok(counterparty_channel) = dst_channel { - if counterparty_channel.state as u32 > expected_state as u32 { - // The state of channel on destination is already higher than - // what this handshake step is trying to achieve - return Ok(vec![]); - } - }; - } - - match event { - IbcEvent::OpenInitChannel(_open_init) => { - // There is a race here: for the same source channel s, in Init, - // another chan_open_try with source s (that creates destination d) can come from the user and if it is - // executed first on the chain, before the one send by the relayer. - // In this case the relayer will create a new channel (d' != d) stuck in TryOpen whose counterparty is s - // There is no way to avoid it, we can add a check (like in handshake_step_with_state) but - // it will slow down and there will still be a window where the behavior is possible. - Ok(vec![self.build_chan_open_try_and_send()?]) - } - IbcEvent::OpenTryChannel(_open_try) => Ok(vec![self.build_chan_open_ack_and_send()?]), - IbcEvent::OpenAckChannel(_open_ack) => { - Ok(vec![self.build_chan_open_confirm_and_send()?]) - } - IbcEvent::OpenConfirmChannel(_open_confirm) => Ok(vec![]), - _ => Ok(vec![]), - } + pub fn counterparty_state(&self) -> Result { + let channel_id = self + .src_channel_id() + .ok_or(ChannelError::MissingLocalChannelId)?; + + let channel_deps = + channel_connection_client(self.src_chain().as_ref(), self.src_port_id(), channel_id) + .map_err(|_| { + ChannelError::Failed(format!( + "failed to query the channel dependecies for {}", + channel_id + )) + })?; + + channel_state_on_destination( + channel_deps.channel.clone(), + channel_deps.connection, + self.dst_chain().as_ref(), + ) + .map_err(|_| { + ChannelError::Failed(format!( + "failed to query the channel state on destination for {}", + channel_id + )) + }) } - pub fn handshake_step_with_state( - &mut self, - state: State, - ) -> Result, ChannelError> { - // TODO - consider move of this `if` into the actual build functions - // Get the channel on destination and if it exists check its state - if let Some(dst_channel_id) = self.dst_channel_id() { - let dst_channel = - self.dst_chain() - .query_channel(&self.dst_port_id(), dst_channel_id, Height::zero()); - if let Ok(counterparty_channel) = dst_channel { - if counterparty_channel.state as u32 > state as u32 { - // The state of channel on destination is already higher than - // what this handshake step is trying to achieve - return Ok(vec![]); - } - }; - } - - match state { - ibc::ics04_channel::channel::State::Init => { - Ok(vec![self.build_chan_open_try_and_send()?]) - } - ibc::ics04_channel::channel::State::TryOpen => { - Ok(vec![self.build_chan_open_ack_and_send()?]) - } - ibc::ics04_channel::channel::State::Open => { - Ok(vec![self.build_chan_open_confirm_and_send()?]) - } + pub fn handshake_step(&mut self, state: State) -> Result, ChannelError> { + // TODO - add tiebreaker when states are equal, r.g. relay only if src_chain.id < dst_chain.id + match (state, self.counterparty_state()?) { + (State::Init, State::Uninitialized) => Ok(vec![self.build_chan_open_try_and_send()?]), + (State::Init, State::Init) => Ok(vec![self.build_chan_open_try_and_send()?]), + (State::TryOpen, State::Init) => Ok(vec![self.build_chan_open_ack_and_send()?]), + (State::TryOpen, State::TryOpen) => Ok(vec![self.build_chan_open_ack_and_send()?]), + (State::Open, State::TryOpen) => Ok(vec![self.build_chan_open_confirm_and_send()?]), _ => Ok(vec![]), } } - pub fn step_event(&mut self, event: IbcEvent, index: u64) -> RetryResult<(), u64> { + pub fn step_state(&mut self, state: State, index: u64) -> RetryResult<(), u64> { let done = '🥳'; - match self.handshake_step_with_event(event.clone()) { + match self.handshake_step(state) { Err(e) => { - error!("\n Failed {:?} with error {:?} \n", event, e); + error!("\n Failed {:?} with error {:?} \n", state, e); RetryResult::Retry(index) } Ok(ev) => { @@ -535,19 +499,16 @@ impl Channel { } } - pub fn step_state(&mut self, state: State, index: u64) -> RetryResult<(), u64> { - let done = '🥳'; + pub fn step_event(&mut self, event: IbcEvent, index: u64) -> RetryResult<(), u64> { + let state = match event { + IbcEvent::OpenInitChannel(_) => State::Init, + IbcEvent::OpenTryChannel(_) => State::TryOpen, + IbcEvent::OpenAckChannel(_) => State::Open, + IbcEvent::OpenConfirmChannel(_) => State::Open, + _ => State::Uninitialized, + }; - match self.handshake_step_with_state(state) { - Err(e) => { - error!("\n Failed {:?} with error {:?} \n", state, e); - RetryResult::Retry(index) - } - Ok(ev) => { - debug!("{} => {:#?}\n", done, ev); - RetryResult::Ok(()) - } - } + self.step_state(state, index) } pub fn build_update_client_on_dst(&self, height: Height) -> Result, ChannelError> { @@ -1154,13 +1115,15 @@ fn check_destination_channel_state( // TODO: Refactor into a method let good_state = *existing_channel.state() as u32 <= *expected_channel.state() as u32; - let good_channel_ids = existing_channel.counterparty().channel_id().is_none() + let good_channel_port_ids = existing_channel.counterparty().channel_id().is_none() || existing_channel.counterparty().channel_id() - == expected_channel.counterparty().channel_id(); + == expected_channel.counterparty().channel_id() + && existing_channel.counterparty().port_id() + == expected_channel.counterparty().port_id(); // TODO: Check versions - if good_state && good_connection_hops && good_channel_ids { + if good_state && good_connection_hops && good_channel_port_ids { Ok(()) } else { Err(ChannelError::Failed(format!( diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index b64614a367..b4eda9d075 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -11,7 +11,7 @@ use ibc::{ ics04_channel::channel::IdentifiedChannelEnd, ics24_host::identifier::ChainId, Height, }; -use ibc_proto::ibc::core::channel::v1::{QueryChannelsRequest, QueryConnectionChannelsRequest}; +use ibc_proto::ibc::core::channel::v1::QueryChannelsRequest; use crate::{ chain::{ @@ -30,8 +30,8 @@ use crate::{ }; pub mod error; +use crate::chain::counterparty::channel_state_on_destination; pub use error::Error; -use ibc::ics04_channel::channel::State; /// The supervisor listens for events on multiple pairs of chains, /// and dispatches the events it receives to the appropriate @@ -134,16 +134,6 @@ impl Supervisor { .or_default() .push(event.clone()); } - if let Ok(channel_object) = Object::channel_from_chan_open_events( - event.clone().channel_attributes().unwrap(), - src_chain, - ) { - collected - .per_object - .entry(channel_object) - .or_default() - .push(event.clone()); - } } IbcEvent::SendPacket(ref packet) => { if let Ok(object) = Object::for_send_packet(packet, src_chain) { @@ -280,44 +270,10 @@ impl Supervisor { .get_or_spawn(&client.client_state.chain_id())?; let local_state = channel.channel_end.state; - let remote_state = if let Some(remote_channel_id) = channel.channel_end.remote.channel_id() - { - counterparty_chain - .query_channel( - channel.channel_end.remote.port_id(), - remote_channel_id, - Height::zero(), - )? - .state - } else { - let mut remote_state = State::Uninitialized; - // TODO - refactor - if let Some(remote_connection_id) = connection.end().counterparty().connection_id() { - let req = QueryConnectionChannelsRequest { - connection: remote_connection_id.to_string(), - pagination: ibc_proto::cosmos::base::query::pagination::all(), - }; - let channels = counterparty_chain.query_connection_channels(req)?; - - for remote_channel in channels.iter() { - if remote_channel.channel_end.remote.channel_id.is_some() - && remote_channel - .channel_end - .remote - .channel_id - .clone() - .unwrap() - == channel.channel_id.clone() - { - remote_state = remote_channel.channel_end.state; - break; - } - } - } - remote_state - }; + let remote_state = + channel_state_on_destination(channel.clone(), connection, counterparty_chain.as_ref())?; - error!("LOCAL STATE {} REMOTE STATE {}", local_state, remote_state); + error!("LOCAL STATE {} REMOTE STATE {}", local_state, remote_state); // TODO remove if local_state.is_open() && remote_state.is_open() { // create the client object and spawn worker let client_object = Object::Client(Client { @@ -325,7 +281,6 @@ impl Supervisor { dst_chain_id: chain.id(), src_chain_id: client.client_state.chain_id(), }); - self.worker_for_object(client_object, chain.clone(), counterparty_chain.clone()); // TODO: Only start the Uni worker if there are outstanding packets or ACKs. @@ -337,7 +292,6 @@ impl Supervisor { src_channel_id: channel.channel_id.clone(), src_port_id: channel.port_id, }); - self.worker_for_object(path_object, chain.clone(), counterparty_chain.clone()); } else if remote_state as u32 <= local_state as u32 && !remote_state.is_open() { // create worker for channel handshake that will advance the remote state diff --git a/relayer/src/worker/handle.rs b/relayer/src/worker/handle.rs index 3a183d6e34..4de7fc0960 100644 --- a/relayer/src/worker/handle.rs +++ b/relayer/src/worker/handle.rs @@ -23,7 +23,7 @@ impl WorkerHandle { Self { tx, thread_handle } } - /// Send a batch of packet events to the worker. + /// Send a batch of events to the worker. pub fn send_events( &self, height: Height, From 685761c2d4d2eedb5306a9ce3193cf1f2f9ba103 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Tue, 18 May 2021 10:29:00 +0200 Subject: [PATCH 26/52] Default strategy 'packets', handshake if 'all' --- ci/simple_config.toml | 2 +- docs/architecture/adr-002-ibc-relayer.md | 4 ++-- .../adr-006-hermes-v0.2-usecases.md | 2 +- guide/src/config.md | 4 ++-- guide/src/help.md | 2 +- .../relay-paths/multiple-paths.md | 2 +- relayer/src/config.rs | 11 ++++++---- relayer/src/supervisor.rs | 21 ++++++++++++++++++- .../config/fixtures/relayer_conf_example.toml | 2 +- .../tests/config/fixtures/simple_config.toml | 2 +- 10 files changed, 37 insertions(+), 15 deletions(-) diff --git a/ci/simple_config.toml b/ci/simple_config.toml index 5012fadfc7..3e0c4c4bb2 100644 --- a/ci/simple_config.toml +++ b/ci/simple_config.toml @@ -1,5 +1,5 @@ [global] -strategy = 'naive' +strategy = 'packets' log_level = 'info' [[chains]] diff --git a/docs/architecture/adr-002-ibc-relayer.md b/docs/architecture/adr-002-ibc-relayer.md index 1df200c548..53771ebfa3 100644 --- a/docs/architecture/adr-002-ibc-relayer.md +++ b/docs/architecture/adr-002-ibc-relayer.md @@ -119,7 +119,7 @@ Below is an example of a configuration file. ```toml [global] -strategy = "naive" +strategy = "packets" log_level = "error" [[chains]] @@ -200,7 +200,7 @@ pub struct Config { } pub enum Strategy { - Naive, + Packets, } pub struct GlobalConfig { diff --git a/docs/architecture/adr-006-hermes-v0.2-usecases.md b/docs/architecture/adr-006-hermes-v0.2-usecases.md index bdab7106cd..e9f50f567e 100644 --- a/docs/architecture/adr-006-hermes-v0.2-usecases.md +++ b/docs/architecture/adr-006-hermes-v0.2-usecases.md @@ -230,7 +230,7 @@ of the config file will look as follows: ```toml [global] -strategy = 'naive' +strategy = 'packets' log_level = 'error' log_json = 'false' ``` diff --git a/guide/src/config.md b/guide/src/config.md index ad32e7c2cf..77986ae300 100644 --- a/guide/src/config.md +++ b/guide/src/config.md @@ -36,7 +36,7 @@ Here is an example for the `global` section: ```toml [global] -strategy = 'naive' +strategy = 'packets' log_level = 'info' ``` @@ -101,7 +101,7 @@ Here is a full example of a configuration file with two chains configured: ```toml [global] -strategy = 'naive' +strategy = 'packets' log_level = 'error' [[chains]] diff --git a/guide/src/help.md b/guide/src/help.md index 142c8c2264..99393dacb4 100644 --- a/guide/src/help.md +++ b/guide/src/help.md @@ -156,7 +156,7 @@ Relevant snippet: ```toml [global] -strategy = 'naive' +strategy = 'packets' log_level = 'error' ``` diff --git a/guide/src/tutorials/local-chains/relay-paths/multiple-paths.md b/guide/src/tutorials/local-chains/relay-paths/multiple-paths.md index 98985ef883..2e7b5df1c0 100644 --- a/guide/src/tutorials/local-chains/relay-paths/multiple-paths.md +++ b/guide/src/tutorials/local-chains/relay-paths/multiple-paths.md @@ -11,7 +11,7 @@ the `start-multi` command. ```toml [global] - strategy = 'naive' + strategy = 'packets' log_level = 'info' [[chains]] diff --git a/relayer/src/config.rs b/relayer/src/config.rs index 7e0a212d8f..b269ae252b 100644 --- a/relayer/src/config.rs +++ b/relayer/src/config.rs @@ -68,15 +68,18 @@ impl Config { } } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub enum Strategy { - #[serde(rename = "naive")] - Naive, + #[serde(rename = "packets")] + Packets, + + #[serde(rename = "all")] + HandshakeAndPackets, } impl Default for Strategy { fn default() -> Self { - Self::Naive + Self::Packets } } diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index b4eda9d075..770f772d10 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -31,6 +31,7 @@ use crate::{ pub mod error; use crate::chain::counterparty::channel_state_on_destination; +use crate::config::Strategy; pub use error::Error; /// The supervisor listens for events on multiple pairs of chains, @@ -59,6 +60,10 @@ impl Supervisor { }) } + fn handshake_enabled(&self) -> bool { + self.config.global.strategy == Strategy::HandshakeAndPackets + } + /// Collect the events we are interested in from an [`EventBatch`], /// and maps each [`IbcEvent`] to their corresponding [`Object`]. pub fn collect_events( @@ -83,6 +88,9 @@ impl Supervisor { } IbcEvent::OpenInitChannel(ref _open_init) => { + if !self.handshake_enabled() { + continue; + } if let Ok(object) = Object::channel_from_chan_open_events( event.clone().channel_attributes().unwrap(), src_chain, @@ -92,6 +100,9 @@ impl Supervisor { } IbcEvent::OpenTryChannel(ref _open_try) => { + if !self.handshake_enabled() { + continue; + } if let Ok(object) = Object::channel_from_chan_open_events( event.clone().channel_attributes().unwrap(), src_chain, @@ -112,6 +123,10 @@ impl Supervisor { .push(event.clone()); } + if !self.handshake_enabled() { + continue; + } + if let Ok(channel_object) = Object::channel_from_chan_open_events( event.clone().channel_attributes().unwrap(), src_chain, @@ -210,6 +225,7 @@ impl Supervisor { } /// Spawns all the [`Worker`]s that will handle a given channel for a given source chain. + #[allow(clippy::suspicious_operation_groupings)] fn spawn_workers_for_channel( &mut self, chain: Box, @@ -293,7 +309,10 @@ impl Supervisor { src_port_id: channel.port_id, }); self.worker_for_object(path_object, chain.clone(), counterparty_chain.clone()); - } else if remote_state as u32 <= local_state as u32 && !remote_state.is_open() { + } else if self.handshake_enabled() + && !remote_state.is_open() + && remote_state as u32 <= local_state as u32 + { // create worker for channel handshake that will advance the remote state let channel_object = Object::Channel(Channel { dst_chain_id: counterparty_chain.clone().id(), diff --git a/relayer/tests/config/fixtures/relayer_conf_example.toml b/relayer/tests/config/fixtures/relayer_conf_example.toml index 234c133427..fbb92571ce 100644 --- a/relayer/tests/config/fixtures/relayer_conf_example.toml +++ b/relayer/tests/config/fixtures/relayer_conf_example.toml @@ -1,5 +1,5 @@ [global] -strategy = 'naive' +strategy = 'packets' log_level = 'error' [[chains]] diff --git a/relayer/tests/config/fixtures/simple_config.toml b/relayer/tests/config/fixtures/simple_config.toml index bd0bd6a8b2..ee61033cbd 100644 --- a/relayer/tests/config/fixtures/simple_config.toml +++ b/relayer/tests/config/fixtures/simple_config.toml @@ -3,7 +3,7 @@ title = "IBC Relayer Config Example" [global] -strategy = "naive" +strategy = "packets" [[chains]] id = "ibc-test" From faf73c60015803f8a173b2be22d3358ad7a313dc Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Tue, 18 May 2021 11:36:09 +0200 Subject: [PATCH 27/52] Cleanup --- guide/src/commands/queries/connection.md | 19 ++++++++-- relayer-cli/src/commands/query/connection.rs | 13 ++++++- relayer/src/chain/cosmos.rs | 8 ---- relayer/src/channel.rs | 39 ++++++++------------ 4 files changed, 42 insertions(+), 37 deletions(-) diff --git a/guide/src/commands/queries/connection.md b/guide/src/commands/queries/connection.md index 8a35fbe497..4ed695f351 100644 --- a/guide/src/commands/queries/connection.md +++ b/guide/src/commands/queries/connection.md @@ -135,8 +135,21 @@ hermes query connection channels ibc-1 connection-1 ```rust Success: [ - ChannelId( - "channel-1", - ), + PortChannelId { + channel_id: ChannelId( + "channel-0", + ), + port_id: PortId( + "transfer", + ), + }, + PortChannelId { + channel_id: ChannelId( + "channel-1", + ), + port_id: PortId( + "transfer", + ), + }, ] ``` diff --git a/relayer-cli/src/commands/query/connection.rs b/relayer-cli/src/commands/query/connection.rs index cf427e337a..6177106e9a 100644 --- a/relayer-cli/src/commands/query/connection.rs +++ b/relayer-cli/src/commands/query/connection.rs @@ -3,8 +3,8 @@ use std::sync::Arc; use abscissa_core::{Command, Options, Runnable}; use tokio::runtime::Runtime as TokioRuntime; -use ibc::ics24_host::identifier::ChainId; use ibc::ics24_host::identifier::ConnectionId; +use ibc::ics24_host::identifier::{ChainId, PortChannelId}; use ibc_proto::ibc::core::channel::v1::QueryConnectionChannelsRequest; use ibc_relayer::chain::{Chain, CosmosSdkChain}; @@ -96,7 +96,16 @@ impl Runnable for QueryConnectionChannelsCmd { .map_err(|e| Kind::Query.context(e).into()); match res { - Ok(cids) => Output::success(cids).exit(), + Ok(channels) => { + let ids: Vec = channels + .into_iter() + .map(|identified_channel| PortChannelId { + port_id: identified_channel.port_id, + channel_id: identified_channel.channel_id, + }) + .collect(); + Output::success(ids).exit() + } Err(e) => Output::error(format!("{}", e)).exit(), } } diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index 845cc121b1..ebeb241b03 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -787,14 +787,6 @@ impl Chain for CosmosSdkChain { .filter_map(|ch| IdentifiedChannelEnd::try_from(ch).ok()) .collect(); Ok(channels) - - // let vec_ids = response - // .channels - // .iter() - // .filter_map(|ic| ChannelId::from_str(ic.channel_id.as_str()).ok()) - // .collect(); - - // Ok(vec_ids) } fn query_channels( diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index ea1006c712..8daf789bdb 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -155,20 +155,12 @@ impl Channel { counterparty_chain: Box, mut channel_open_event: IbcEvent, ) -> Result { - let channel_event_attributes = match channel_open_event.channel_attributes() { - None => { - return Err(ChannelError::Failed( + let channel_event_attributes = + channel_open_event.channel_attributes().ok_or_else(|| { + ChannelError::Failed( "A channel object must be build only from a channel event ".to_string(), ) - .into()) - } - Some(attributes) => attributes, - }; - - let connection_id = channel_event_attributes.connection_id.clone(); - let counterparty_port_id = channel_event_attributes.counterparty_port_id.clone(); - let connection = chain.query_connection(&connection_id, Height::zero())?; - let counterparty_channel_id = channel_event_attributes.counterparty_channel_id.clone(); + })?; let port_id = channel_event_attributes.port_id.clone(); let channel_id = channel_event_attributes.channel_id.clone(); @@ -177,18 +169,17 @@ impl Channel { .module_version(&port_id) .map_err(|e| ChannelError::QueryError(counterparty_chain.id(), e))?; - let counterparty_connection_id = match connection.counterparty().connection_id() { - Some(x) => x.clone(), - None => { - return Err("failed due to missing counterparty connection" - .to_string() - .into()) - } - }; + let connection_id = channel_event_attributes.connection_id.clone(); + let connection = chain.query_connection(&connection_id, Height::zero())?; + let connection_counterparty = connection.counterparty(); + + let counterparty_connection_id = connection_counterparty + .connection_id() + .ok_or(ChannelError::MissingCounterpartyConnection)?; Ok(Channel { ordering: Default::default(), - //TODO how to get the order from raw tx + //TODO how to get the order from event a_side: ChannelSide::new( chain.clone(), connection.client_id().clone(), @@ -199,9 +190,9 @@ impl Channel { b_side: ChannelSide::new( counterparty_chain.clone(), connection.counterparty().client_id().clone(), - counterparty_connection_id, - counterparty_port_id, - counterparty_channel_id, + counterparty_connection_id.clone(), + channel_event_attributes.counterparty_port_id.clone(), + channel_event_attributes.counterparty_channel_id.clone(), ), connection_delay: connection.delay_period(), //TODO detect version from event From c273e46ec4f3fbd540da1c583feaf82ff26b04bd Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Tue, 18 May 2021 18:11:38 +0200 Subject: [PATCH 28/52] Add channel worker test to CI --- e2e/e2e/channel.py | 11 ++-- e2e/run.py | 133 ++++++++++++++++++++++++++--------------- relayer/src/channel.rs | 4 +- 3 files changed, 92 insertions(+), 56 deletions(-) diff --git a/e2e/e2e/channel.py b/e2e/e2e/channel.py index 49a0716012..fd1ad26aee 100644 --- a/e2e/e2e/channel.py +++ b/e2e/e2e/channel.py @@ -418,18 +418,19 @@ def handshake( c: Config, side_a: ChainId, side_b: ChainId, conn_a: ConnectionId, conn_b: ConnectionId, + port_id: PortId ) -> Tuple[ChannelId, ChannelId]: a_chan_id = chan_open_init(c, dst=side_a, src=side_b, dst_conn=conn_a) split() b_chan_id = chan_open_try( - c, dst=side_b, src=side_a, dst_conn=conn_b, dst_port=PortId('transfer'), src_port=PortId('transfer'), + c, dst=side_b, src=side_a, dst_conn=conn_b, dst_port=port_id, src_port=port_id, src_chan=a_chan_id) split() - ack_res = chan_open_ack(c, dst=side_a, src=side_b, dst_port=PortId('transfer'), src_port=PortId('transfer'), + ack_res = chan_open_ack(c, dst=side_a, src=side_b, dst_port=port_id, src_port=port_id, dst_conn=conn_a, dst_chan=a_chan_id, src_chan=b_chan_id) if ack_res != a_chan_id: @@ -438,7 +439,7 @@ def handshake( exit(1) confirm_res = chan_open_confirm( - c, dst=side_b, src=side_a, dst_port=PortId('transfer'), src_port=PortId('transfer'), + c, dst=side_b, src=side_a, dst_port=port_id, src_port=port_id, dst_conn=conn_b, dst_chan=b_chan_id, src_chan=a_chan_id) if confirm_res != b_chan_id: @@ -448,13 +449,13 @@ def handshake( split() - a_chan_end = query_channel_end(c, side_a, PortId('transfer'), a_chan_id) + a_chan_end = query_channel_end(c, side_a, port_id, a_chan_id) if a_chan_end.state != 'Open': l.error( f'Channel end with id {a_chan_id} on chain {side_a} is not in Open state, got: {a_chan_end.state}') exit(1) - b_chan_end = query_channel_end(c, side_b, PortId('transfer'), b_chan_id) + b_chan_end = query_channel_end(c, side_b, port_id, b_chan_id) if b_chan_end.state != 'Open': l.error( f'Channel end with id {b_chan_id} on chain {side_b} is not in Open state, got: {b_chan_end.state}') diff --git a/e2e/run.py b/e2e/run.py index 8ab0bd19b0..47815ef926 100755 --- a/e2e/run.py +++ b/e2e/run.py @@ -2,7 +2,7 @@ import argparse import logging as l - +from typing import Tuple from pathlib import Path import e2e.channel as channel @@ -14,42 +14,39 @@ from e2e.common import * -def loop(c: Config): - IBC_0 = ChainId('ibc-0') - IBC_1 = ChainId('ibc-1') - - TRANSFER = PortId('transfer') - IBC_0_CHANNEL = ChannelId('channel-0') - IBC_1_CHANNEL = ChannelId('channel-1') +def passive_packets( + c: Config, + ibc0: ChainId, ibc1: ChainId, port_id: PortId, + ibc0_channel_id: ChannelId, ibc1_channel_id: ChannelId): # 1. create some unreceived acks # hermes tx raw ft-transfer ibc-1 ibc-0 transfer channel-0 10000 1000 -n 2 - packet.packet_send(c, src=IBC_0, dst=IBC_1, src_port=TRANSFER, - src_channel=IBC_0_CHANNEL, amount=10000, height_offset=1000, number_msgs=2) + packet.packet_send(c, src=ibc0, dst=ibc1, src_port=port_id, + src_channel=ibc0_channel_id, amount=10000, height_offset=1000, number_msgs=2) # hermes tx raw ft-transfer ibc-0 ibc-1 transfer channel-1 10000 1000 -n 2 - packet.packet_send(c, src=IBC_1, dst=IBC_0, src_port=TRANSFER, - src_channel=IBC_1_CHANNEL, amount=10000, height_offset=1000, number_msgs=2) + packet.packet_send(c, src=ibc1, dst=ibc0 , src_port=port_id, + src_channel=ibc1_channel_id, amount=10000, height_offset=1000, number_msgs=2) sleep(5.0) # hermes tx raw packet-recv ibc-1 ibc-0 transfer channel-0 - packet.packet_recv(c, src=IBC_0, dst=IBC_1, - src_port=TRANSFER, src_channel=IBC_0_CHANNEL) + packet.packet_recv(c, src=ibc0 , dst=ibc1, + src_port=port_id, src_channel=ibc0_channel_id) # hermes tx raw packet-recv ibc-0 ibc-1 transfer channel-1 - packet.packet_recv(c, src=IBC_1, dst=IBC_0, - src_port=TRANSFER, src_channel=IBC_1_CHANNEL) + packet.packet_recv(c, src=ibc1, dst=ibc0 , + src_port=port_id, src_channel=ibc1_channel_id) # 2. create some unreceived packets # hermes tx raw ft-transfer ibc-0 ibc-1 transfer channel-1 10000 1000 -n 3 - packet.packet_send(c, src=IBC_1, dst=IBC_0, src_port=TRANSFER, - src_channel=IBC_1_CHANNEL, amount=10000, height_offset=1000, number_msgs=3) + packet.packet_send(c, src=ibc1, dst=ibc0 , src_port=port_id, + src_channel=ibc1_channel_id, amount=10000, height_offset=1000, number_msgs=3) # hermes tx raw ft-transfer ibc-1 ibc-0 transfer channel-0 10000 1000 -n 4 - packet.packet_send(c, src=IBC_0, dst=IBC_1, src_port=TRANSFER, - src_channel=IBC_0_CHANNEL, amount=10000, height_offset=1000, number_msgs=4) + packet.packet_send(c, src=ibc0 , dst=ibc1, src_port=port_id, + src_channel=ibc0_channel_id, amount=10000, height_offset=1000, number_msgs=4) sleep(10.0) @@ -57,25 +54,25 @@ def loop(c: Config): # hermes query packet unreceived-packets ibc-0 transfer channel-0 unreceived = packet.query_unreceived_packets( - c, chain=IBC_0, port=TRANSFER, channel=IBC_0_CHANNEL) + c, chain=ibc0 , port=port_id, channel=ibc0_channel_id) assert (len(unreceived) == 3), (unreceived, "unreceived packet mismatch") # hermes query packet unreceived-acks ibc-1 transfer channel-1 unreceived = packet.query_unreceived_acks( - c, chain=IBC_1, port=TRANSFER, channel=IBC_1_CHANNEL) + c, chain=ibc1, port=port_id, channel=ibc1_channel_id) assert (len(unreceived) == 2), (unreceived, "unreceived packet mismatch") # hermes query packet unreceived-packets ibc-1 transfer channel-1 unreceived = packet.query_unreceived_packets( - c, chain=IBC_1, port=TRANSFER, channel=IBC_1_CHANNEL) + c, chain=ibc1, port=port_id, channel=ibc1_channel_id) assert (len(unreceived) == 4), (unreceived, "unreceived packet mismatch") # hermes query packet unreceived-acks ibc-0 transfer channel-0 unreceived = packet.query_unreceived_acks( - c, chain=IBC_0, port=TRANSFER, channel=IBC_0_CHANNEL) + c, chain=ibc0 , port=port_id, channel=ibc0_channel_id) assert (len(unreceived) == 2), (unreceived, "unreceived packet mismatch") @@ -89,36 +86,36 @@ def loop(c: Config): # 5. wait a bit and make sure there are no pending packets # hermes tx raw ft-transfer ibc-0 ibc-1 transfer channel-1 10000 1000 -n 3 - packet.packet_send(c, src=IBC_1, dst=IBC_0, src_port=TRANSFER, - src_channel=IBC_1_CHANNEL, amount=10000, height_offset=1000, number_msgs=3) + packet.packet_send(c, src=ibc1, dst=ibc0 , src_port=port_id, + src_channel=ibc1_channel_id, amount=10000, height_offset=1000, number_msgs=3) # hermes tx raw ft-transfer ibc-1 ibc-0 transfer channel-0 10000 1000 -n 4 - packet.packet_send(c, src=IBC_0, dst=IBC_1, src_port=TRANSFER, - src_channel=IBC_0_CHANNEL, amount=10000, height_offset=1000, number_msgs=4) + packet.packet_send(c, src=ibc0, dst=ibc1, src_port=port_id, + src_channel=ibc0_channel_id, amount=10000, height_offset=1000, number_msgs=4) sleep(10.0) # hermes query packet unreceived-packets ibc-1 transfer channel-1 unreceived = packet.query_unreceived_packets( - c, chain=IBC_1, port=TRANSFER, channel=IBC_1_CHANNEL) + c, chain=ibc1, port=port_id, channel=ibc1_channel_id) assert (len(unreceived) == 0), (unreceived, "unreceived packet mismatch") # hermes query packet unreceived-acks ibc-1 transfer channel-1 unreceived = packet.query_unreceived_acks( - c, chain=IBC_1, port=TRANSFER, channel=IBC_1_CHANNEL) + c, chain=ibc1, port=port_id, channel=ibc1_channel_id) assert (len(unreceived) == 0), (unreceived, "unreceived packet mismatch") # hermes query packet unreceived-packets ibc-0 transfer channel-0 unreceived = packet.query_unreceived_packets( - c, chain=IBC_0, port=TRANSFER, channel=IBC_0_CHANNEL) + c, chain=ibc0 , port=port_id, channel=ibc0_channel_id) assert (len(unreceived) == 0), (unreceived, "unreceived packet mismatch") # hermes query packet unreceived-acks ibc-0 transfer channel-0 unreceived = packet.query_unreceived_acks( - c, chain=IBC_0, port=TRANSFER, channel=IBC_0_CHANNEL) + c, chain=ibc0 , port=port_id, channel=ibc0_channel_id) assert (len(unreceived) == 0), (unreceived, "unreceived packet mismatch") @@ -126,48 +123,78 @@ def loop(c: Config): proc.kill() -def raw(c: Config): - IBC_0 = ChainId('ibc-0') - IBC_1 = ChainId('ibc-1') - - ibc0_client_id = client.create_update_query_client(c, IBC_0, IBC_1) +def raw(c: Config, ibc0: ChainId, ibc1: ChainId, port_id: PortId) -> Tuple[ ClientId, ConnectionId, ChannelId, ClientId, ConnectionId, ChannelId]: + ibc0_client_id = client.create_update_query_client(c, ibc0, ibc1) # Allocate first IDs on ibc-1 - ibc1_client_id = client.create_update_query_client(c, IBC_1, IBC_0) + ibc1_client_id = client.create_update_query_client(c, ibc1, ibc0) ibc1_conn_id = connection.conn_init( - c, IBC_1, IBC_0, ibc1_client_id, ibc0_client_id) + c, ibc1, ibc0 , ibc1_client_id, ibc0_client_id) ibc1_chan_id = channel.chan_open_init( - c, dst=IBC_1, src=IBC_0, dst_conn=ibc1_conn_id) + c, dst=ibc1, src=ibc0 , dst_conn=ibc1_conn_id) - ibc1_client_id = client.create_update_query_client(c, IBC_1, IBC_0) + ibc1_client_id = client.create_update_query_client(c, ibc1, ibc0) split() ibc0_conn_id, ibc1_conn_id = connection.handshake( - c, IBC_0, IBC_1, ibc0_client_id, ibc1_client_id) + c, ibc0, ibc1, ibc0_client_id, ibc1_client_id) split() ibc0_chan_id, ibc1_chan_id = channel.handshake( - c, IBC_0, IBC_1, ibc0_conn_id, ibc1_conn_id) + c, ibc0, ibc1, ibc0_conn_id, ibc1_conn_id, port_id) split() - packet.ping_pong(c, IBC_0, IBC_1, ibc0_chan_id, ibc1_chan_id) + packet.ping_pong(c, ibc0, ibc1, ibc0_chan_id, ibc1_chan_id) split() sleep(5) - packet.timeout(c, IBC_0, IBC_1, ibc0_chan_id, ibc1_chan_id) + packet.timeout(c, ibc0, ibc1, ibc0_chan_id, ibc1_chan_id) split() # The ChannelCloseInit message is currently denied by Gaia, # and requires a patch to be accepted. - # channel.close(c, IBC_0, IBC_1, ibc0_conn_id, + # channel.close(c, ibc0 , ibc1, ibc0_conn_id, # ibc1_conn_id, ibc0_chan_id, ibc1_chan_id) + return ibc0_client_id, ibc0_conn_id, ibc0_chan_id, ibc1_client_id, ibc1_conn_id, ibc1_chan_id + +def passive_channel(c: Config, + ibc1: ChainId, ibc0: ChainId, + ibc1_conn_id: ConnectionId, port_id: PortId): + + # 1. create a channel in Init state + ibc1_chan_id = channel.chan_open_init(c, dst=ibc1, src=ibc0, dst_conn=ibc1_conn_id) + + sleep(2.0) + + # 2. start relaying, wait for channel handshake to finish + proc = relayer.start(c) + sleep(10.0) + + # 3. verify channel state on both chains + ibc1_chan_end = channel.query_channel_end(c, ibc1, port_id, ibc1_chan_id) + if ibc1_chan_end.state != 'Open': + l.error( + f'Channel end with id {ibc1_chan_id} on chain {ibc1} is not in Open state, got: {ibc1_chan_end.state}') + proc.kill() + exit(1) + + ibc0_chan_id = ibc1_chan_end.remote.channel_id + ibc0_chan_end = channel.query_channel_end(c, ibc0, port_id, ibc0_chan_id) + if ibc0_chan_end.state != 'Open': + l.error( + f'Channel end with id {ibc0_chan_id} on chain {ibc0} is not in Open state, got: {ibc0_chan_end.state}') + proc.kill() + exit(1) + + # 4. All good, stop the relayer + proc.kill() def main(): parser = argparse.ArgumentParser( @@ -206,8 +233,18 @@ def main(): format='%(asctime)s [%(levelname)8s] %(message)s', datefmt='%Y-%m-%d %H:%M:%S') - raw(config) - loop(config) + ibc0 = ChainId('ibc-0') + ibc1 = ChainId('ibc-1') + port_id = PortId('transfer') + + ibc0_client_id, ibc0_conn_id, ibc0_chan_id, ibc1_client_id, ibc1_conn_id, ibc1_chan_id = raw(config, ibc0 , ibc1, port_id) + sleep(2.0) + + passive_packets(config, ibc0, ibc1, port_id, ibc0_chan_id, ibc1_chan_id) + sleep(2.0) + + passive_channel(config, ibc1, ibc0, ibc1_conn_id, port_id) + sleep(2.0) if __name__ == "__main__": diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 8daf789bdb..d86f27fb28 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -235,9 +235,7 @@ impl Channel { version: Some(a_channel.version.clone()), }; - if a_channel.state_matches(&ibc::ics04_channel::channel::State::Init) - && a_channel.remote.channel_id.is_none() - { + if a_channel.state_matches(&State::Init) && a_channel.remote.channel_id.is_none() { if let Some(b_connection_id) = a_connection.counterparty().connection_id() { let req = QueryConnectionChannelsRequest { connection: b_connection_id.to_string(), From 4bb561ee5bbb80dada14c8700a07310f504839e5 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Tue, 18 May 2021 18:28:34 +0200 Subject: [PATCH 29/52] Change the CI config file to relay all --- ci/simple_config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/simple_config.toml b/ci/simple_config.toml index 3e0c4c4bb2..3e9b3b551e 100644 --- a/ci/simple_config.toml +++ b/ci/simple_config.toml @@ -1,5 +1,5 @@ [global] -strategy = 'packets' +strategy = 'all' log_level = 'info' [[chains]] From ac07abcc6af0db22c490d2311a90a4ea4ac48c2b Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Tue, 18 May 2021 19:08:10 +0200 Subject: [PATCH 30/52] Update changelog --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0afec248d7..bec15e6acc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,13 @@ ## Unreleased -> Nothing yet, +### FEATURES + +- [ibc-relayer] + - Add support for event based channel relaying ([#822]) + +[#822]: https://github.com/informalsystems/ibc-rs/issues/822 + ## v0.3.1 *May 14h, 2021* From bf203993de640dee147b653812fd4029471735c2 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Wed, 19 May 2021 11:23:11 +0200 Subject: [PATCH 31/52] Read strategy and chain ids from config file --- e2e/run.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/e2e/run.py b/e2e/run.py index 47815ef926..bac5fbab6e 100755 --- a/e2e/run.py +++ b/e2e/run.py @@ -4,6 +4,7 @@ import logging as l from typing import Tuple from pathlib import Path +import toml import e2e.channel as channel import e2e.client as client @@ -168,6 +169,7 @@ def passive_channel(c: Config, ibc1: ChainId, ibc0: ChainId, ibc1_conn_id: ConnectionId, port_id: PortId): + # 1. create a channel in Init state ibc1_chan_id = channel.chan_open_init(c, dst=ibc1, src=ibc0, dst_conn=ibc1_conn_id) @@ -177,21 +179,21 @@ def passive_channel(c: Config, proc = relayer.start(c) sleep(10.0) - # 3. verify channel state on both chains - ibc1_chan_end = channel.query_channel_end(c, ibc1, port_id, ibc1_chan_id) - if ibc1_chan_end.state != 'Open': - l.error( - f'Channel end with id {ibc1_chan_id} on chain {ibc1} is not in Open state, got: {ibc1_chan_end.state}') - proc.kill() - exit(1) + strategy = toml.load(c.config_file)['global']['strategy'] + # 3. verify channel state on both chains, should be 'Open' for 'all' strategy, 'Init' otherwise + ibc1_chan_end = channel.query_channel_end(c, ibc1, port_id, ibc1_chan_id) ibc0_chan_id = ibc1_chan_end.remote.channel_id ibc0_chan_end = channel.query_channel_end(c, ibc0, port_id, ibc0_chan_id) - if ibc0_chan_end.state != 'Open': - l.error( - f'Channel end with id {ibc0_chan_id} on chain {ibc0} is not in Open state, got: {ibc0_chan_end.state}') - proc.kill() - exit(1) + + if strategy == 'all': + assert (ibc0_chan_end.state == 'Open'), (ibc0_chan_end, "state is not Open") + assert (ibc1_chan_end.state == 'Open'), (ibc1_chan_end, "state is not Open") + elif strategy == 'packets': + assert (ibc1_chan_end.state == 'Init'), (ibc1_chan_end, "state is not Init") + + proc.kill() + exit(1) # 4. All good, stop the relayer proc.kill() @@ -233,8 +235,10 @@ def main(): format='%(asctime)s [%(levelname)8s] %(message)s', datefmt='%Y-%m-%d %H:%M:%S') - ibc0 = ChainId('ibc-0') - ibc1 = ChainId('ibc-1') + chains = toml.load(config.config_file)['chains'] + + ibc0 = chains[0]['id'] + ibc1 = chains[1]['id'] port_id = PortId('transfer') ibc0_client_id, ibc0_conn_id, ibc0_chan_id, ibc1_client_id, ibc1_conn_id, ibc1_chan_id = raw(config, ibc0 , ibc1, port_id) From 1f7f6a2ed00dba03ca0d3839a8ef01517c17e45f Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Wed, 19 May 2021 15:04:56 +0200 Subject: [PATCH 32/52] Install toml in CI --- ci/relayer.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/relayer.Dockerfile b/ci/relayer.Dockerfile index 6a81c49b66..0c23fd949e 100644 --- a/ci/relayer.Dockerfile +++ b/ci/relayer.Dockerfile @@ -7,7 +7,7 @@ LABEL maintainer="hello@informal.systems" ARG RELEASE # Add Python 3 -RUN apt-get update -y && apt-get install python3 -y +RUN apt-get update -y && apt-get install python3 -y && apt-get install python3-toml -y # Copy relayer executable COPY ./hermes /usr/bin/hermes From 68cd510a52d32cdd5a566d9766bf6b2c0f0c16a0 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Thu, 20 May 2021 09:16:28 +0200 Subject: [PATCH 33/52] Fix stray exit(1) in e2e --- e2e/run.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/e2e/run.py b/e2e/run.py index bac5fbab6e..6e0ceded51 100755 --- a/e2e/run.py +++ b/e2e/run.py @@ -192,9 +192,6 @@ def passive_channel(c: Config, elif strategy == 'packets': assert (ibc1_chan_end.state == 'Init'), (ibc1_chan_end, "state is not Init") - proc.kill() - exit(1) - # 4. All good, stop the relayer proc.kill() From 8c47d96172aa0f028197f0132116f33581fdb53e Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Fri, 21 May 2021 10:04:37 +0200 Subject: [PATCH 34/52] Change back query to return Uninitialized, fix only the caller/CLI --- relayer-cli/src/commands/query/channel.rs | 13 +++++++++- relayer-cli/src/commands/query/connection.rs | 13 +++++++++- relayer/src/chain/cosmos.rs | 25 ++++---------------- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/relayer-cli/src/commands/query/channel.rs b/relayer-cli/src/commands/query/channel.rs index cf6a667207..74c53f41a9 100644 --- a/relayer-cli/src/commands/query/channel.rs +++ b/relayer-cli/src/commands/query/channel.rs @@ -9,6 +9,7 @@ use ibc_relayer::chain::{Chain, CosmosSdkChain}; use crate::conclude::Output; use crate::prelude::*; +use ibc::ics04_channel::channel::State; #[derive(Clone, Command, Debug, Options)] pub struct QueryChannelEndCmd { @@ -48,7 +49,17 @@ impl Runnable for QueryChannelEndCmd { let height = ibc::Height::new(chain.id().version(), self.height.unwrap_or(0_u64)); let res = chain.query_channel(&self.port_id, &self.channel_id, height); match res { - Ok(ce) => Output::success(ce).exit(), + Ok(channel_end) => { + if channel_end.state_matches(&State::Uninitialized) { + Output::error(format!( + "port '{}' & channel '{}' does not exist", + self.port_id, self.channel_id + )) + .exit() + } else { + Output::success(channel_end).exit() + } + } Err(e) => Output::error(format!("{}", e)).exit(), } } diff --git a/relayer-cli/src/commands/query/connection.rs b/relayer-cli/src/commands/query/connection.rs index 6177106e9a..251ae04824 100644 --- a/relayer-cli/src/commands/query/connection.rs +++ b/relayer-cli/src/commands/query/connection.rs @@ -11,6 +11,7 @@ use ibc_relayer::chain::{Chain, CosmosSdkChain}; use crate::conclude::Output; use crate::error::{Error, Kind}; use crate::prelude::*; +use ibc::ics03_connection::connection::State; #[derive(Clone, Command, Debug, Options)] pub struct QueryConnectionEndCmd { @@ -48,7 +49,17 @@ impl Runnable for QueryConnectionEndCmd { let height = ibc::Height::new(chain.id().version(), self.height.unwrap_or(0_u64)); let res = chain.query_connection(&self.connection_id, height); match res { - Ok(ce) => Output::success(ce).exit(), + Ok(connection_end) => { + if connection_end.state_matches(&State::Uninitialized) { + Output::error(format!( + "connection '{}' does not exist", + self.connection_id + )) + .exit() + } else { + Output::success(connection_end).exit() + } + } Err(e) => Output::error(format!("{}", e)).exit(), } } diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index ebeb241b03..e7b805b8a5 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -26,10 +26,8 @@ use ibc::ics02_client::client_consensus::{ }; use ibc::ics02_client::client_state::{AnyClientState, IdentifiedAnyClientState}; use ibc::ics02_client::events as ClientEvents; -use ibc::ics03_connection::connection::{ConnectionEnd, State as ConnectionState}; -use ibc::ics04_channel::channel::{ - ChannelEnd, IdentifiedChannelEnd, QueryPacketEventDataRequest, State as ChannelState, -}; +use ibc::ics03_connection::connection::ConnectionEnd; +use ibc::ics04_channel::channel::{ChannelEnd, IdentifiedChannelEnd, QueryPacketEventDataRequest}; use ibc::ics04_channel::events as ChannelEvents; use ibc::ics04_channel::packet::{PacketMsgType, Sequence}; use ibc::ics07_tendermint::client_state::{AllowUpdate, ClientState}; @@ -747,14 +745,7 @@ impl Chain for CosmosSdkChain { let connection_end = ConnectionEnd::decode_vec(&res.value) .map_err(|e| Kind::Query(format!("connection '{}'", connection_id)).context(e))?; - match connection_end.state() { - ConnectionState::Uninitialized => { - Err(Kind::Query(format!("connection '{}'", connection_id)) - .context("connection does not exist") - .into()) - } - _ => Ok(connection_end), - } + Ok(connection_end) } fn query_connection_channels( @@ -833,15 +824,7 @@ impl Chain for CosmosSdkChain { Kind::Query(format!("port '{}' & channel '{}'", port_id, channel_id)).context(e) })?; - match channel_end.state() { - ChannelState::Uninitialized => Err(Kind::Query(format!( - "port '{}' & channel '{}'", - port_id, channel_id - )) - .context("channel does not exist") - .into()), - _ => Ok(channel_end), - } + Ok(channel_end) } /// Queries the packet commitment hashes associated with a channel. From c0028e495010fcb7c5ab50748373b73b2440a09c Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Fri, 21 May 2021 12:20:35 +0200 Subject: [PATCH 35/52] Remove unwraps --- e2e/run.py | 2 +- modules/src/ics04_channel/events.rs | 62 ++++++++++++++++++- relayer/src/link.rs | 96 ++++++++++++----------------- 3 files changed, 102 insertions(+), 58 deletions(-) diff --git a/e2e/run.py b/e2e/run.py index 5b6f29ab2f..e401ce7331 100755 --- a/e2e/run.py +++ b/e2e/run.py @@ -181,7 +181,7 @@ def passive_channel(c: Config, # 2. start relaying, wait for channel handshake to finish proc = relayer.start(c) - sleep(10.0) + sleep(15.0) strategy = toml.load(c.config_file)['global']['strategy'] diff --git a/modules/src/ics04_channel/events.rs b/modules/src/ics04_channel/events.rs index 1ffb901541..dea2c10da9 100644 --- a/modules/src/ics04_channel/events.rs +++ b/modules/src/ics04_channel/events.rs @@ -545,6 +545,18 @@ impl SendPacket { pub fn set_height(&mut self, height: Height) { self.height = height; } + pub fn src_port_id(&self) -> &PortId { + &self.packet.source_port + } + pub fn src_channel_id(&self) -> &ChannelId { + &self.packet.source_channel + } + pub fn dst_port_id(&self) -> &PortId { + &self.packet.destination_port + } + pub fn dst_channel_id(&self) -> &ChannelId { + &self.packet.destination_channel + } } impl TryFrom for SendPacket { @@ -583,6 +595,18 @@ impl ReceivePacket { pub fn set_height(&mut self, height: Height) { self.height = height; } + pub fn src_port_id(&self) -> &PortId { + &self.packet.source_port + } + pub fn src_channel_id(&self) -> &ChannelId { + &self.packet.source_channel + } + pub fn dst_port_id(&self) -> &PortId { + &self.packet.destination_port + } + pub fn dst_channel_id(&self) -> &ChannelId { + &self.packet.destination_channel + } } impl TryFrom for ReceivePacket { @@ -623,6 +647,18 @@ impl WriteAcknowledgement { pub fn set_height(&mut self, height: Height) { self.height = height; } + pub fn src_port_id(&self) -> &PortId { + &self.packet.source_port + } + pub fn src_channel_id(&self) -> &ChannelId { + &self.packet.source_channel + } + pub fn dst_port_id(&self) -> &PortId { + &self.packet.destination_port + } + pub fn dst_channel_id(&self) -> &ChannelId { + &self.packet.destination_channel + } } impl TryFrom for WriteAcknowledgement { @@ -666,6 +702,12 @@ impl AcknowledgePacket { pub fn set_height(&mut self, height: Height) { self.height = height; } + pub fn src_port_id(&self) -> &PortId { + &self.packet.source_port + } + pub fn src_channel_id(&self) -> &ChannelId { + &self.packet.source_channel + } } impl TryFrom for AcknowledgePacket { @@ -700,7 +742,7 @@ impl TimeoutPacket { self.height } pub fn set_height(&mut self, height: Height) { - self.height = height + self.height = height; } pub fn src_port_id(&self) -> &PortId { &self.packet.source_port @@ -708,6 +750,12 @@ impl TimeoutPacket { pub fn src_channel_id(&self) -> &ChannelId { &self.packet.source_channel } + pub fn dst_port_id(&self) -> &PortId { + &self.packet.destination_port + } + pub fn dst_channel_id(&self) -> &ChannelId { + &self.packet.destination_channel + } } impl TryFrom for TimeoutPacket { @@ -745,6 +793,18 @@ impl TimeoutOnClosePacket { pub fn set_height(&mut self, height: Height) { self.height = height; } + pub fn src_port_id(&self) -> &PortId { + &self.packet.source_port + } + pub fn src_channel_id(&self) -> &ChannelId { + &self.packet.source_channel + } + pub fn dst_port_id(&self) -> &PortId { + &self.packet.destination_port + } + pub fn dst_channel_id(&self) -> &ChannelId { + &self.packet.destination_channel + } } impl TryFrom for TimeoutOnClosePacket { diff --git a/relayer/src/link.rs b/relayer/src/link.rs index 57d931550b..366cca8c6d 100644 --- a/relayer/src/link.rs +++ b/relayer/src/link.rs @@ -252,12 +252,22 @@ impl RelayPath { &self.channel.dst_port_id() } - pub fn src_channel_id(&self) -> Option<&ChannelId> { - self.channel.src_channel_id() + pub fn src_channel_id(&self) -> Result<&ChannelId, LinkError> { + self.channel.src_channel_id().ok_or_else(|| { + LinkError::Failed(format!( + "channel_id on source chain '{}' is 'None'", + self.src_chain.id() + )) + }) } - pub fn dst_channel_id(&self) -> Option<&ChannelId> { - self.channel.dst_channel_id() + pub fn dst_channel_id(&self) -> Result<&ChannelId, LinkError> { + self.channel.dst_channel_id().ok_or_else(|| { + LinkError::Failed(format!( + "channel_id on destination chain '{}' is 'None'", + self.dst_chain.id() + )) + }) } pub fn channel(&self) -> &Channel { @@ -265,28 +275,16 @@ impl RelayPath { } fn src_channel(&self, height: Height) -> Result { - let src_channel_id = self.src_channel_id().ok_or_else(|| { - LinkError::Failed(format!( - "channel_id on source chain '{}' is 'None'", - self.src_chain.id() - )) - })?; Ok(self .src_chain() - .query_channel(self.src_port_id(), src_channel_id, height) + .query_channel(self.src_port_id(), self.src_channel_id()?, height) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?) } fn dst_channel(&self, height: Height) -> Result { - let dst_channel_id = self.src_channel_id().ok_or_else(|| { - LinkError::Failed(format!( - "channel_id on destination chain '{}' is 'None'", - self.dst_chain.id() - )) - })?; Ok(self .dst_chain() - .query_channel(self.dst_port_id(), dst_channel_id, height) + .query_channel(self.dst_port_id(), self.dst_channel_id()?, height) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?) } @@ -341,8 +339,7 @@ impl RelayPath { } fn build_chan_close_confirm_from_event(&self, event: &IbcEvent) -> Result { - assert!(self.src_channel_id().is_some()); - let src_channel_id = self.src_channel_id().unwrap(); + let src_channel_id = self.src_channel_id()?; let proofs = self .src_chain() .build_channel_proofs(self.src_port_id(), src_channel_id, event.height()) @@ -364,32 +361,37 @@ impl RelayPath { fn filter_events(&self, events: &[IbcEvent]) -> Vec { let mut result = vec![]; + let src_channel_id = if let Ok(some_id) = self.src_channel_id() { + some_id + } else { + return vec![]; + }; + for event in events.iter() { match event { IbcEvent::SendPacket(send_packet_ev) => { - if self.src_channel_id() == Some(&send_packet_ev.packet.source_channel) - && self.src_port_id() == &send_packet_ev.packet.source_port + if src_channel_id == send_packet_ev.src_channel_id() + && self.src_port_id() == send_packet_ev.src_port_id() { result.push(event.clone()); } } IbcEvent::WriteAcknowledgement(write_ack_ev) => { - if self.channel.src_channel_id() - == Some(&write_ack_ev.packet.destination_channel) - && self.channel.src_port_id() == &write_ack_ev.packet.destination_port + if src_channel_id == write_ack_ev.dst_channel_id() + && self.src_port_id() == write_ack_ev.dst_port_id() { result.push(event.clone()); } } IbcEvent::CloseInitChannel(chan_close_ev) => { - if self.channel.src_channel_id() == Some(chan_close_ev.channel_id()) - && self.channel.src_port_id() == chan_close_ev.port_id() + if src_channel_id == chan_close_ev.channel_id() + && self.src_port_id() == chan_close_ev.port_id() { result.push(event.clone()); } } IbcEvent::TimeoutPacket(timeout_ev) => { - if self.channel.src_channel_id() == Some(timeout_ev.src_channel_id()) + if src_channel_id == timeout_ev.src_channel_id() && self.channel.src_port_id() == timeout_ev.src_port_id() { result.push(event.clone()); @@ -844,8 +846,7 @@ impl RelayPath { ) -> Result<(Vec, Height), LinkError> { let mut events_result = vec![]; - assert!(self.src_channel_id().is_some()); - let src_channel_id = self.src_channel_id().unwrap(); + let src_channel_id = self.src_channel_id()?; // Query packet commitments on source chain that have not been acknowledged let pc_request = QueryPacketCommitmentsRequest { @@ -869,13 +870,10 @@ impl RelayPath { commit_sequences ); - assert!(self.src_channel_id().is_some()); - let dst_channel_id = self.dst_channel_id().unwrap(); - // Get the packets that have not been received on destination chain let request = QueryUnreceivedPacketsRequest { port_id: self.dst_port_id().to_string(), - channel_id: dst_channel_id.to_string(), + channel_id: self.dst_channel_id()?.to_string(), packet_commitment_sequences: commit_sequences, }; @@ -898,15 +896,12 @@ impl RelayPath { return Ok((events_result, query_height)); } - assert!(self.src_channel_id().is_some()); - assert!(self.dst_channel_id().is_some()); - let query = QueryTxRequest::Packet(QueryPacketEventDataRequest { event_id: IbcEventType::SendPacket, source_port_id: self.src_port_id().clone(), - source_channel_id: self.src_channel_id().unwrap().clone(), + source_channel_id: src_channel_id.clone(), destination_port_id: self.dst_port_id().clone(), - destination_channel_id: self.dst_channel_id().unwrap().clone(), + destination_channel_id: self.dst_channel_id()?.clone(), sequences, height: query_height, }); @@ -932,10 +927,8 @@ impl RelayPath { ) -> Result<(Vec, Height), LinkError> { let mut events_result = vec![]; - assert!(self.src_channel_id().is_some()); - let src_channel_id = self.src_channel_id().unwrap(); - assert!(self.dst_channel_id().is_some()); - let dst_channel_id = self.dst_channel_id().unwrap(); + let src_channel_id = self.src_channel_id()?; + let dst_channel_id = self.dst_channel_id()?; // Get the sequences of packets that have been acknowledged on source let pc_request = QueryPacketAcknowledgementsRequest { @@ -1090,15 +1083,12 @@ impl RelayPath { &self, event: &WriteAcknowledgement, ) -> Result, LinkError> { - assert!(self.src_channel_id().is_some()); - let dst_channel_id = self.dst_channel_id().unwrap(); - let packet = event.packet.clone(); let acked = self.dst_chain() .query_unreceived_acknowledgement(QueryUnreceivedAcksRequest { port_id: self.dst_port_id().to_string(), - channel_id: dst_channel_id.to_string(), + channel_id: self.dst_channel_id()?.to_string(), packet_ack_sequences: vec![packet.sequence.into()], })?; if acked.is_empty() { @@ -1138,8 +1128,7 @@ impl RelayPath { packet: &Packet, height: Height, ) -> Result, LinkError> { - assert!(self.src_channel_id().is_some()); - let dst_channel_id = self.dst_channel_id().unwrap(); + let dst_channel_id = self.dst_channel_id()?; let (packet_type, next_sequence_received) = if self.ordered_channel() { let next_seq = self @@ -1555,8 +1544,7 @@ impl Link { } pub fn is_closed(&self) -> Result { - assert!(self.a_to_b.src_channel_id().is_some()); - let a_channel_id = self.a_to_b.src_channel_id().unwrap(); + let a_channel_id = self.a_to_b.src_channel_id()?; let a_channel = self .a_to_b @@ -1571,11 +1559,7 @@ impl Link { )) })?; - if self.a_to_b.dst_channel_id().is_none() { - return Ok(a_channel.state_matches(&ChannelState::Closed)); - } - - let b_channel_id = self.a_to_b.dst_channel_id().unwrap(); + let b_channel_id = self.a_to_b.dst_channel_id()?; let b_channel = self .a_to_b From ebc158110f9054f173e479832ec346be98991e30 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Fri, 21 May 2021 12:29:45 +0200 Subject: [PATCH 36/52] Update changelog --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5e24da643..a84905aac3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## Unreleased + +### FEATURES + +- [ibc-relayer] + - Add support for event based channel relaying ([#822]) + + +[#822]: https://github.com/informalsystems/ibc-rs/issues/822 + ## v0.3.2 *May 21st, 2021* From 6c4b44aab6ce917616882ec3fa2c48e6d2e4c85d Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Fri, 21 May 2021 14:36:44 +0200 Subject: [PATCH 37/52] Cleanup more unwraps --- CHANGELOG.md | 8 -- relayer/src/channel.rs | 163 +++++++++++++++++++------------- relayer/src/supervisor/error.rs | 4 + relayer/src/worker/channel.rs | 9 +- 4 files changed, 103 insertions(+), 81 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a84905aac3..60f7370415 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,14 +20,6 @@ Docker images to Docker Hub. ### FEATURES -- [ibc-relayer] - - Add support for event based channel relaying ([#822]) - -[#822]: https://github.com/informalsystems/ibc-rs/issues/822 - - -## Unreleased - - [ibc-relayer-cli] - Add a `--key` option to the tx raw ft-transfer command to override the account used for sending messages ([#963]) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 0e9fe81481..7362224aa3 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -37,6 +37,9 @@ pub enum ChannelError { #[error("failed due to missing local channel id")] MissingLocalChannelId, + #[error("failed due to missing counterparty channel id")] + MissingCounterpartyChannelId, + #[error("failed due to missing counterparty connection")] MissingCounterpartyConnection, @@ -200,6 +203,8 @@ impl Channel { }) } + /// Recreates a 'Channel' object from the worker's object built from chain state scanning. + /// The channel must exist on chain and its connection must be initialized on both chains. pub fn restore_from_state( chain: Box, counterparty_chain: Box, @@ -214,6 +219,17 @@ impl Channel { })?; let a_connection = chain.query_connection(&a_connection_id, Height::zero())?; + let b_connection_id = a_connection + .counterparty() + .connection_id() + .cloned() + .ok_or_else(|| { + WorkerChannelError::ChannelConnectionUninitialized( + channel.src_channel_id.clone(), + chain.id(), + a_connection.counterparty(), + ) + })?; let mut handshake_channel = Channel { ordering: *a_channel.ordering(), @@ -227,7 +243,7 @@ impl Channel { b_side: ChannelSide::new( counterparty_chain.clone(), a_connection.counterparty().client_id().clone(), - a_connection.counterparty().connection_id().unwrap().clone(), + b_connection_id.clone(), a_channel.remote.port_id.clone(), a_channel.remote.channel_id.clone(), ), @@ -236,20 +252,17 @@ impl Channel { }; if a_channel.state_matches(&State::Init) && a_channel.remote.channel_id.is_none() { - if let Some(b_connection_id) = a_connection.counterparty().connection_id() { - let req = QueryConnectionChannelsRequest { - connection: b_connection_id.to_string(), - pagination: ibc_proto::cosmos::base::query::pagination::all(), - }; - - let channels: Vec = - counterparty_chain.query_connection_channels(req)?; - - for chan in channels.iter() { - if chan.channel_end.remote.channel_id.is_some() - && chan.channel_end.remote.channel_id.clone().unwrap() - == channel.src_channel_id.clone() - { + let req = QueryConnectionChannelsRequest { + connection: b_connection_id.to_string(), + pagination: ibc_proto::cosmos::base::query::pagination::all(), + }; + + let channels: Vec = + counterparty_chain.query_connection_channels(req)?; + + for chan in channels.iter() { + if let Some(remote_channel_id) = chan.channel_end.remote.channel_id() { + if remote_channel_id == &channel.src_channel_id { handshake_channel.b_side.channel_id = Some(chan.channel_id.clone()); break; } @@ -435,6 +448,7 @@ impl Channel { } pub fn counterparty_state(&self) -> Result { + // Source channel ID must be specified let channel_id = self .src_channel_id() .ok_or(ChannelError::MissingLocalChannelId)?; @@ -606,10 +620,16 @@ impl Channel { /// Retrieves the channel from destination and compares against the expected channel /// built from the message type (`msg_type`) and options (`opts`). /// If the expected and the destination channels are compatible, it returns the expected channel + /// Source and destination channel IDs must be specified. fn validated_expected_channel( &self, msg_type: ChannelMsgType, ) -> Result { + // Destination channel ID must be specified + let dst_channel_id = self + .dst_channel_id() + .ok_or(ChannelError::MissingCounterpartyChannelId)?; + // If there is a channel present on the destination chain, it should look like this: let counterparty = Counterparty::new(self.src_port_id().clone(), self.src_channel_id().cloned()); @@ -631,17 +651,12 @@ impl Channel { ); // Retrieve existing channel - assert!(self.dst_channel_id().is_some()); let dst_channel = self .dst_chain() - .query_channel( - self.dst_port_id(), - self.dst_channel_id().unwrap(), - Height::default(), - ) + .query_channel(self.dst_port_id(), dst_channel_id, Height::default()) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; - // Check if a connection is expected to exist on destination chain + // Check if a channel is expected to exist on destination chain // A channel must exist on destination chain for Ack and Confirm Tx-es to succeed if dst_channel.state_matches(&State::Uninitialized) { return Err(ChannelError::Failed( @@ -650,7 +665,7 @@ impl Channel { } check_destination_channel_state( - self.dst_channel_id().cloned().unwrap(), + dst_channel_id.clone(), dst_channel, dst_expected_channel.clone(), )?; @@ -659,11 +674,15 @@ impl Channel { } pub fn build_chan_open_try(&self) -> Result, ChannelError> { - assert!(self.src_channel_id().is_some()); - let src_channel_id = self.src_channel_id().unwrap(); + // Source channel ID must be specified + let src_channel_id = self + .src_channel_id() + .ok_or(ChannelError::MissingLocalChannelId)?; + + // Channel must exist on source let src_channel = self .src_chain() - .query_channel(self.src_port_id(), src_channel_id, Height::default()) + .query_channel(self.src_port_id(), &src_channel_id, Height::default()) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?; if src_channel.counterparty().port_id() != self.dst_port_id() { @@ -677,9 +696,8 @@ impl Channel { ))); } - // Retrieve the connection - let _dst_connection = self - .dst_chain() + // Connection must exist on destination + self.dst_chain() .query_connection(self.dst_connection_id(), Height::default()) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; @@ -697,7 +715,7 @@ impl Channel { let mut msgs = self.build_update_client_on_dst(proofs.height())?; let counterparty = - Counterparty::new(self.src_port_id().clone(), Some(src_channel_id.clone())); + Counterparty::new(self.src_port_id().clone(), self.src_channel_id().cloned()); let channel = ChannelEnd::new( State::TryOpen, @@ -765,20 +783,24 @@ impl Channel { } pub fn build_chan_open_ack(&self) -> Result, ChannelError> { + // Source and destination channel IDs must be specified + let src_channel_id = self + .src_channel_id() + .ok_or(ChannelError::MissingLocalChannelId)?; + let dst_channel_id = self + .dst_channel_id() + .ok_or(ChannelError::MissingCounterpartyChannelId)?; + // Check that the destination chain will accept the message - let _dst_expected_channel = self.validated_expected_channel(ChannelMsgType::OpenAck)?; - assert!(self.src_channel_id().is_some()); - let src_channel_id = self.src_channel_id().unwrap(); - assert!(self.dst_channel_id().is_some()); + self.validated_expected_channel(ChannelMsgType::OpenAck)?; - let _src_channel = self - .src_chain() + // Channel must exist on source + self.src_chain() .query_channel(self.src_port_id(), src_channel_id, Height::default()) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?; - // Retrieve the connection - let _dst_connection = self - .dst_chain() + // Connection must exist on destination + self.dst_chain() .query_connection(self.dst_connection_id(), Height::default()) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; @@ -812,7 +834,7 @@ impl Channel { // Build the domain type message let new_msg = MsgChannelOpenAck { port_id: self.dst_port_id().clone(), - channel_id: self.dst_channel_id().unwrap().clone(), + channel_id: dst_channel_id.clone(), counterparty_channel_id: src_channel_id.clone(), counterparty_version: self.src_version()?, proofs, @@ -852,21 +874,24 @@ impl Channel { } pub fn build_chan_open_confirm(&self) -> Result, ChannelError> { - // Check that the destination chain will accept the message - let _dst_expected_channel = self.validated_expected_channel(ChannelMsgType::OpenConfirm)?; + // Source and destination channel IDs must be specified + let src_channel_id = self + .src_channel_id() + .ok_or(ChannelError::MissingLocalChannelId)?; + let dst_channel_id = self + .dst_channel_id() + .ok_or(ChannelError::MissingCounterpartyChannelId)?; - assert!(self.src_channel_id().is_some()); - let src_channel_id = self.src_channel_id().unwrap(); - assert!(self.dst_channel_id().is_some()); + // Check that the destination chain will accept the message + self.validated_expected_channel(ChannelMsgType::OpenConfirm)?; - let _src_channel = self - .src_chain() + // Channel must exist on source + self.src_chain() .query_channel(self.src_port_id(), src_channel_id, Height::default()) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?; - // Retrieve the connection - let _dst_connection = self - .dst_chain() + // Connection must exist on destination + self.dst_chain() .query_connection(self.dst_connection_id(), Height::default()) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; @@ -895,7 +920,7 @@ impl Channel { // Build the domain type message let new_msg = MsgChannelOpenConfirm { port_id: self.dst_port_id().clone(), - channel_id: self.dst_channel_id().unwrap().clone(), + channel_id: dst_channel_id.clone(), proofs, signer, }; @@ -933,11 +958,13 @@ impl Channel { } pub fn build_chan_close_init(&self) -> Result, ChannelError> { - assert!(self.dst_channel_id().is_some()); - let dst_channel_id = self.dst_channel_id().unwrap(); + // Destination channel ID must be specified + let dst_channel_id = self + .dst_channel_id() + .ok_or(ChannelError::MissingCounterpartyChannelId)?; - let _channel = self - .dst_chain() + // Channel must exist on destination + self.dst_chain() .query_channel(self.dst_port_id(), dst_channel_id, Height::default()) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; @@ -989,22 +1016,24 @@ impl Channel { } pub fn build_chan_close_confirm(&self) -> Result, ChannelError> { - // Check that the destination chain will accept the message - let _dst_expected_channel = - self.validated_expected_channel(ChannelMsgType::CloseConfirm)?; + // Source and destination channel IDs must be specified + let src_channel_id = self + .src_channel_id() + .ok_or(ChannelError::MissingLocalChannelId)?; + let dst_channel_id = self + .dst_channel_id() + .ok_or(ChannelError::MissingCounterpartyChannelId)?; - assert!(self.src_channel_id().is_some()); - let src_channel_id = self.src_channel_id().unwrap(); - assert!(self.dst_channel_id().is_some()); + // Check that the destination chain will accept the message + self.validated_expected_channel(ChannelMsgType::CloseConfirm)?; - let _src_channel = self - .src_chain() + // Channel must exist on source + self.src_chain() .query_channel(self.src_port_id(), src_channel_id, Height::default()) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?; - // Retrieve the connection - let _dst_connection = self - .dst_chain() + // Connection must exist on destination + self.dst_chain() .query_connection(self.dst_connection_id(), Height::default()) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; @@ -1033,7 +1062,7 @@ impl Channel { // Build the domain type message let new_msg = MsgChannelCloseConfirm { port_id: self.dst_port_id().clone(), - channel_id: self.dst_channel_id().unwrap().clone(), + channel_id: dst_channel_id.clone(), proofs, signer, }; diff --git a/relayer/src/supervisor/error.rs b/relayer/src/supervisor/error.rs index 78f72a87a9..89d664a32e 100644 --- a/relayer/src/supervisor/error.rs +++ b/relayer/src/supervisor/error.rs @@ -1,5 +1,6 @@ use thiserror::Error; +use ibc::ics03_connection::connection::Counterparty; use ibc::ics24_host::identifier::{ChainId, ChannelId, ConnectionId}; #[derive(Clone, Debug, Error, PartialEq, Eq)] @@ -7,6 +8,9 @@ pub enum Error { #[error("channel {0} on chain {1} is not open")] ChannelUninitialized(ChannelId, ChainId), + #[error("channel {0} on chain {1} has a connection with uninitialized counterparty {:2}")] + ChannelConnectionUninitialized(ChannelId, ChainId, Counterparty), + #[error("connection {0} (underlying channel {1}) on chain {2} is not open")] ConnectionNotOpen(ConnectionId, ChannelId, ChainId), diff --git a/relayer/src/worker/channel.rs b/relayer/src/worker/channel.rs index 69bece7c5e..41097b29b8 100644 --- a/relayer/src/worker/channel.rs +++ b/relayer/src/worker/channel.rs @@ -47,7 +47,7 @@ impl ChannelWorker { // there can be up to two event for this channel, e.g. init and try. // process the last event, the one with highest "rank". let last_event = batch.events.last(); - debug!("channel worker start processing {:#?}", last_event); + debug!("channel worker starts processing {:#?}", last_event); match last_event { Some(event) => { handshake_channel = RelayChannel::restore_from_event( @@ -70,7 +70,7 @@ impl ChannelWorker { continue; } debug!( - "channel worker is processing block event at {:#?}", + "channel worker starts processing block event at {:#?}", current_height ); @@ -90,10 +90,7 @@ impl ChannelWorker { }; if let Err(retries) = result { - warn!( - "Channel worker failed to process event batch after {} retries", - retries - ); + warn!("Channel worker failed after {} retries", retries); // Resume handshake on next iteration. resume_handshake = true; From d9fcdd01bf724e030922ad1c7b3c6bfcdd834128 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Fri, 21 May 2021 23:04:42 +0200 Subject: [PATCH 38/52] add more tests to e2e --- e2e/e2e/channel.py | 93 ++++++++++++++++++++++++++++++++++++ e2e/run.py | 37 +++----------- relayer/src/supervisor.rs | 4 +- relayer/src/worker/client.rs | 2 +- 4 files changed, 102 insertions(+), 34 deletions(-) diff --git a/e2e/e2e/channel.py b/e2e/e2e/channel.py index fd1ad26aee..ab094d3a91 100644 --- a/e2e/e2e/channel.py +++ b/e2e/e2e/channel.py @@ -1,8 +1,10 @@ from typing import Optional, Tuple +import toml from .cmd import * from .common import * +import e2e.relayer as relayer @dataclass class TxChanOpenInitRes: @@ -476,3 +478,94 @@ def query_channel_end(c: Config, chain_id: ChainId, port: PortId, chan_id: Chann l.debug(f'Status of channel end {chan_id}: {res}') return res + + +# ============================================================================= +# Passive CHANNEL relayer tests +# ============================================================================= + +def verify_state(c: Config, + ibc1: ChainId, ibc0: ChainId, + ibc1_chan_id: ChannelId, port_id: PortId): + + strategy = toml.load(c.config_file)['global']['strategy'] + # verify channel state on both chains, should be 'Open' for 'all' strategy, 'Init' otherwise + + if strategy == 'all': + for i in range(20): + sleep(2.0) + ibc1_chan_end = query_channel_end(c, ibc1, port_id, ibc1_chan_id) + ibc0_chan_id = ibc1_chan_end.remote.channel_id + ibc0_chan_end = query_channel_end(c, ibc0, port_id, ibc0_chan_id) + if ibc0_chan_end.state == 'Open' and ibc1_chan_end.state == 'Open': + break + else: + assert (ibc0_chan_end.state == 'Open'), (ibc0_chan_end, "state is not Open") + assert (ibc1_chan_end.state == 'Open'), (ibc1_chan_end, "state is not Open") + + elif strategy == 'packets': + sleep(8.0) + ibc1_chan_end = query_channel_end(c, ibc1, port_id, ibc1_chan_id) + assert (ibc1_chan_end.state == 'Init'), (ibc1_chan_end, "state is not Init") + + +def passive_channel_start_then_init(c: Config, + ibc1: ChainId, ibc0: ChainId, + ibc1_conn_id: ConnectionId, port_id: PortId): + + # 1. start hermes + proc = relayer.start(c) + sleep(2.0) + + # 2. create a channel in Init state and wait for hermes to finish handshake + ibc1_chan_id = chan_open_init(c, dst=ibc1, src=ibc0, dst_conn=ibc1_conn_id) + sleep(10.0) + + # 3. verify channel state on both chains + verify_state(c, ibc1, ibc0, ibc1_chan_id, port_id) + + # 4. All good, stop the relayer + proc.kill() + + +def passive_channel_init_then_start(c: Config, + ibc1: ChainId, ibc0: ChainId, + ibc1_conn_id: ConnectionId, port_id: PortId): + + # 1. create a channel in Init state + ibc1_chan_id = chan_open_init(c, dst=ibc1, src=ibc0, dst_conn=ibc1_conn_id) + sleep(2.0) + + # 2. start relaying, wait for channel handshake to finish + proc = relayer.start(c) + sleep(10.0) + + # 3. verify channel state on both chains + verify_state(c, ibc1, ibc0, ibc1_chan_id, port_id) + + # 4. All good, stop the relayer + proc.kill() + + +def passive_channel_try_then_start(c: Config, + ibc1: ChainId, + ibc0: ChainId, + ibc1_conn_id: ConnectionId, + ibc0_conn_id: ConnectionId, + port_id: PortId): + + # 1. create a channel in Try state + ibc1_chan_id = chan_open_init(c, dst=ibc1, src=ibc0, dst_conn=ibc1_conn_id) + sleep(2.0) + ibc0_chan_id = chan_open_try(c, dst=ibc0, src=ibc1, dst_conn=ibc0_conn_id, src_port=port_id, dst_port=port_id, src_chan=ibc1_chan_id) + sleep(2.0) + + # 2. start relaying, wait for channel handshake to finish + proc = relayer.start(c) + sleep(10.0) + + # 3. verify channel state on both chains + verify_state(c, ibc1, ibc0, ibc1_chan_id, port_id) + + # 4. All good, stop the relayer + proc.kill() diff --git a/e2e/run.py b/e2e/run.py index e401ce7331..8a83ebcf30 100755 --- a/e2e/run.py +++ b/e2e/run.py @@ -169,36 +169,6 @@ def raw(c: Config, ibc0: ChainId, ibc1: ChainId, port_id: PortId) -> Tuple[ Clie return ibc0_client_id, ibc0_conn_id, ibc0_chan_id, ibc1_client_id, ibc1_conn_id, ibc1_chan_id -def passive_channel(c: Config, - ibc1: ChainId, ibc0: ChainId, - ibc1_conn_id: ConnectionId, port_id: PortId): - - - # 1. create a channel in Init state - ibc1_chan_id = channel.chan_open_init(c, dst=ibc1, src=ibc0, dst_conn=ibc1_conn_id) - - sleep(2.0) - - # 2. start relaying, wait for channel handshake to finish - proc = relayer.start(c) - sleep(15.0) - - strategy = toml.load(c.config_file)['global']['strategy'] - - # 3. verify channel state on both chains, should be 'Open' for 'all' strategy, 'Init' otherwise - ibc1_chan_end = channel.query_channel_end(c, ibc1, port_id, ibc1_chan_id) - ibc0_chan_id = ibc1_chan_end.remote.channel_id - ibc0_chan_end = channel.query_channel_end(c, ibc0, port_id, ibc0_chan_id) - - if strategy == 'all': - assert (ibc0_chan_end.state == 'Open'), (ibc0_chan_end, "state is not Open") - assert (ibc1_chan_end.state == 'Open'), (ibc1_chan_end, "state is not Open") - elif strategy == 'packets': - assert (ibc1_chan_end.state == 'Init'), (ibc1_chan_end, "state is not Init") - - # 4. All good, stop the relayer - proc.kill() - def main(): parser = argparse.ArgumentParser( description='Test all relayer commands, end-to-end') @@ -248,9 +218,14 @@ def main(): passive_packets(config, ibc0, ibc1, port_id, ibc0_chan_id, ibc1_chan_id) sleep(2.0) - passive_channel(config, ibc1, ibc0, ibc1_conn_id, port_id) + channel.passive_channel_start_then_init(config, ibc1, ibc0, ibc1_conn_id, port_id) sleep(2.0) + channel.passive_channel_init_then_start(config, ibc1, ibc0, ibc1_conn_id, port_id) + sleep(2.0) + + channel.passive_channel_try_then_start(config, ibc1, ibc0, ibc1_conn_id, ibc0_conn_id, port_id) + sleep(2.0) if __name__ == "__main__": main() diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index c51d931819..a3ab70efd4 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -284,7 +284,7 @@ impl Supervisor { let remote_state = channel_state_on_destination(channel.clone(), connection, counterparty_chain.as_ref())?; - error!("LOCAL STATE {} REMOTE STATE {}", local_state, remote_state); // TODO remove + debug!("local state is: {}, remote state is: {}", local_state, remote_state); if local_state.is_open() && remote_state.is_open() { // create the client object and spawn worker let client_object = Object::Client(Client { @@ -293,7 +293,7 @@ impl Supervisor { src_chain_id: client.client_state.chain_id(), }); self.workers - .get_or_spawn(client_object, chain.clone(), counterparty_chain.clone()); + .get_or_spawn(client_object, counterparty_chain.clone(), chain.clone()); // TODO: Only start the Uni worker if there are outstanding packets or ACKs. // https://github.com/informalsystems/ibc-rs/issues/901 diff --git a/relayer/src/worker/client.rs b/relayer/src/worker/client.rs index 9e5c848ac6..979b0b21f5 100644 --- a/relayer/src/worker/client.rs +++ b/relayer/src/worker/client.rs @@ -33,8 +33,8 @@ impl ClientWorker { pub fn run(self) -> Result<(), BoxError> { let mut client = ForeignClient::restore( &self.client.dst_client_id, - self.chains.a.clone(), self.chains.b.clone(), + self.chains.a.clone(), ); info!( From 1627991620a4cceb8c4b49cf2ce06390ae699f25 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Fri, 21 May 2021 23:11:50 +0200 Subject: [PATCH 39/52] Format --- relayer/src/supervisor.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index a3ab70efd4..81d3d26007 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -284,7 +284,10 @@ impl Supervisor { let remote_state = channel_state_on_destination(channel.clone(), connection, counterparty_chain.as_ref())?; - debug!("local state is: {}, remote state is: {}", local_state, remote_state); + debug!( + "local state is: {}, remote state is: {}", + local_state, remote_state + ); if local_state.is_open() && remote_state.is_open() { // create the client object and spawn worker let client_object = Object::Client(Client { From 6ee11106f26c2283c9b5a7aeb07dfcdba1bc8ca9 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Fri, 21 May 2021 23:39:24 +0200 Subject: [PATCH 40/52] error fmt --- relayer/src/channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 7362224aa3..4d6b927dee 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -491,7 +491,7 @@ impl Channel { match self.handshake_step(state) { Err(e) => { - error!("\n Failed {:?} with error {:?} \n", state, e); + error!("Failed {:?} with error {}", state, e); RetryResult::Retry(index) } Ok(ev) => { From 3a99fc64876a782f11b20f4f8c2ba38d86ad88c1 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Mon, 24 May 2021 19:42:26 +0200 Subject: [PATCH 41/52] Small reorder --- relayer/src/object.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relayer/src/object.rs b/relayer/src/object.rs index 6b907dead6..edffeff287 100644 --- a/relayer/src/object.rs +++ b/relayer/src/object.rs @@ -108,9 +108,9 @@ impl Object { /// Returns `false` otherwise. pub fn notify_new_block(&self, src_chain_id: &ChainId) -> bool { match self { - Object::UnidirectionalChannelPath(p) => p.src_chain_id == *src_chain_id, Object::Client(_) => false, Object::Channel(c) => c.src_chain_id == *src_chain_id, + Object::UnidirectionalChannelPath(p) => p.src_chain_id == *src_chain_id, } } } From 11a27debc228a477ff0089f30d41cbce56f9e45d Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Tue, 25 May 2021 14:35:05 +0200 Subject: [PATCH 42/52] cargo fmt --- relayer/src/channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 3cd42e28ca..6a15fc7fe8 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -1,8 +1,8 @@ #![allow(clippy::borrowed_box)] -use std::time::Duration; use anomaly::BoxError; use prost_types::Any; use serde::Serialize; +use std::time::Duration; use thiserror::Error; use tracing::{debug, error}; From 29bcb5aee2f8b3c7c876d45853f43356cf23ab17 Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Tue, 25 May 2021 18:27:05 +0200 Subject: [PATCH 43/52] Small refactor - removed config_example.toml - documented the `strategy` field in the default config.toml - fix for clippy suspicious_operation_groupings exception --- config.toml | 7 +++-- config_example.toml | 58 --------------------------------------- guide/src/help.md | 2 +- relayer/src/object.rs | 6 ++-- relayer/src/supervisor.rs | 5 ++-- 5 files changed, 11 insertions(+), 67 deletions(-) delete mode 100644 config_example.toml diff --git a/config.toml b/config.toml index 2904ee82d5..b1c1078193 100644 --- a/config.toml +++ b/config.toml @@ -1,6 +1,9 @@ [global] -strategy = 'naive' -log_level = 'error' +# Valid strategies: +# 'packets': restricts relaying to packets only, or +# 'all': relay from all types of events +strategy = 'packets' +log_level = 'info' [[chains]] id = 'ibc-0' diff --git a/config_example.toml b/config_example.toml deleted file mode 100644 index 12f4dff667..0000000000 --- a/config_example.toml +++ /dev/null @@ -1,58 +0,0 @@ -[global] -strategy = 'naive' -log_level = 'error' - -[[chains]] -id = 'ibc-0' -rpc_addr = 'http://localhost:26657' -grpc_addr = 'http://localhost:9090' -websocket_addr = 'ws://localhost:26657/websocket' -rpc_timeout = '10s' -account_prefix = 'cosmos' -key_name = 'testkey' -store_prefix = 'ibc' -gas = 3000000 -fee_denom = 'stake' -fee_amount = 10 -clock_drift = '5s' -trusting_period = '14days' - -[chains.trust_threshold] -numerator = '1' -denominator = '3' - -[[chains]] -id = 'ibc-1' -rpc_addr = 'http://localhost:26557' -grpc_addr = 'http://localhost:9091' -websocket_addr = 'ws://localhost:26557/websocket' -rpc_timeout = '10s' -account_prefix = 'cosmos' -key_name = 'testkey' -store_prefix = 'ibc' -gas = 3000000 -fee_denom = 'stake' -fee_amount = 10 -clock_drift = '5s' -trusting_period = '14days' - -[chains.trust_threshold] -numerator = '1' -denominator = '3' - -[[connections]] -a_chain = 'ibc-0' -b_chain = 'ibc-1' -delay = '10s' - -[[connections.paths]] -a_port = 'transfer' -b_port = 'transfer' - -[[connections]] -a_chain = 'ibc-0' -b_chain = 'ibc-1' - -[[connections.paths]] -a_port = 'transfer' -b_port = 'transfer' \ No newline at end of file diff --git a/guide/src/help.md b/guide/src/help.md index 99393dacb4..02468038a7 100644 --- a/guide/src/help.md +++ b/guide/src/help.md @@ -88,7 +88,7 @@ the `profiling` feature and the [log level][log-level] should be `info` level or #### Example output for `tx raw conn-init` command ``` -hermes -c config_example.toml tx raw conn-init ibc-0 ibc-1 07-tendermint-0 07-tendermint-0 +hermes -c config.toml tx raw conn-init ibc-0 ibc-1 07-tendermint-0 07-tendermint-0 ``` ``` diff --git a/relayer/src/object.rs b/relayer/src/object.rs index 40482698af..dc4fd3bc04 100644 --- a/relayer/src/object.rs +++ b/relayer/src/object.rs @@ -38,7 +38,7 @@ impl Client { } } -//Channel +/// Channel #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Channel { /// Destination chain identifier. @@ -47,10 +47,10 @@ pub struct Channel { /// Source chain identifier. pub src_chain_id: ChainId, - /// Source channel identiier. + /// Source channel identifier. pub src_channel_id: ChannelId, - /// Source port identiier. + /// Source port identifier. pub src_port_id: PortId, } diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index fd191a493f..35b4b33565 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -220,7 +220,6 @@ impl Supervisor { } /// Spawns all the [`Worker`]s that will handle a given channel for a given source chain. - #[allow(clippy::suspicious_operation_groupings)] fn spawn_workers_for_channel( &mut self, chain: Box, @@ -309,9 +308,9 @@ impl Supervisor { }); self.workers .get_or_spawn(path_object, chain.clone(), counterparty_chain.clone()); - } else if self.handshake_enabled() - && !remote_state.is_open() + } else if !remote_state.is_open() && remote_state as u32 <= local_state as u32 + && self.handshake_enabled() { // create worker for channel handshake that will advance the remote state let channel_object = Object::Channel(Channel { From 9053cb136e82845156aa0b49ab2eb2fc5700f56a Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Tue, 25 May 2021 19:20:34 +0200 Subject: [PATCH 44/52] Minor supervisor refactoring to reuse source/destination terminology. --- relayer-cli/src/commands/query/connection.rs | 8 +++++--- relayer/src/chain/counterparty.rs | 11 ++++++----- relayer/src/supervisor.rs | 18 +++++++++++------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/relayer-cli/src/commands/query/connection.rs b/relayer-cli/src/commands/query/connection.rs index 251ae04824..e549fa2f62 100644 --- a/relayer-cli/src/commands/query/connection.rs +++ b/relayer-cli/src/commands/query/connection.rs @@ -3,15 +3,17 @@ use std::sync::Arc; use abscissa_core::{Command, Options, Runnable}; use tokio::runtime::Runtime as TokioRuntime; -use ibc::ics24_host::identifier::ConnectionId; -use ibc::ics24_host::identifier::{ChainId, PortChannelId}; +use ibc::{ + ics03_connection::connection::State, + ics24_host::identifier::ConnectionId, + ics24_host::identifier::{ChainId, PortChannelId}, +}; use ibc_proto::ibc::core::channel::v1::QueryConnectionChannelsRequest; use ibc_relayer::chain::{Chain, CosmosSdkChain}; use crate::conclude::Output; use crate::error::{Error, Kind}; use crate::prelude::*; -use ibc::ics03_connection::connection::State; #[derive(Clone, Command, Debug, Options)] pub struct QueryConnectionEndCmd { diff --git a/relayer/src/chain/counterparty.rs b/relayer/src/chain/counterparty.rs index 67f35000fb..958bc9b2ff 100644 --- a/relayer/src/chain/counterparty.rs +++ b/relayer/src/chain/counterparty.rs @@ -4,17 +4,16 @@ use tracing::trace; use ibc::{ ics02_client::client_state::{ClientState, IdentifiedAnyClientState}, ics03_connection::connection::IdentifiedConnectionEnd, - ics04_channel::channel::IdentifiedChannelEnd, + ics04_channel::channel::{ChannelEnd, IdentifiedChannelEnd, State}, + ics24_host::identifier::ConnectionId, ics24_host::identifier::{ChainId, ChannelId, PortId}, Height, }; +use ibc_proto::ibc::core::channel::v1::QueryConnectionChannelsRequest; use crate::supervisor::Error; use super::handle::ChainHandle; -use ibc::ics04_channel::channel::{ChannelEnd, State}; -use ibc::ics24_host::identifier::ConnectionId; -use ibc_proto::ibc::core::channel::v1::QueryConnectionChannelsRequest; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ChannelConnectionClient { @@ -37,6 +36,8 @@ impl ChannelConnectionClient { } } +/// Returns the [`ChannelConnectionClient`] associated with the +/// provided port and channel id. pub fn channel_connection_client( chain: &dyn ChainHandle, port_id: &PortId, @@ -53,7 +54,7 @@ pub fn channel_connection_client( .query_channel(port_id, channel_id, Height::zero()) .map_err(|e| Error::QueryFailed(format!("{}", e)))?; - if channel_end.state_matches(&ibc::ics04_channel::channel::State::Uninitialized) { + if channel_end.state_matches(&State::Uninitialized) { return Err(Error::ChannelUninitialized(channel_id.clone(), chain.id())); } diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index 35b4b33565..498c9516e9 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -279,15 +279,19 @@ impl Supervisor { .registry .get_or_spawn(&client.client_state.chain_id())?; - let local_state = channel.channel_end.state; - let remote_state = + let chan_state_src = channel.channel_end.state; + let chan_state_dst = channel_state_on_destination(channel.clone(), connection, counterparty_chain.as_ref())?; debug!( - "local state is: {}, remote state is: {}", - local_state, remote_state + "channel {} on chain {} is: {}; state on dest. chain ({}) is: {}", + channel.channel_id, + chain.id(), + chan_state_src, + counterparty_chain.id(), + chan_state_dst ); - if local_state.is_open() && remote_state.is_open() { + if chan_state_src.is_open() && chan_state_dst.is_open() { // create the client object and spawn worker let client_object = Object::Client(Client { dst_client_id: client.client_id.clone(), @@ -308,8 +312,8 @@ impl Supervisor { }); self.workers .get_or_spawn(path_object, chain.clone(), counterparty_chain.clone()); - } else if !remote_state.is_open() - && remote_state as u32 <= local_state as u32 + } else if !chan_state_dst.is_open() + && chan_state_dst as u32 <= chan_state_src as u32 && self.handshake_enabled() { // create worker for channel handshake that will advance the remote state From d92fc8bef9a7242796d369d35b80bf8fd463b738 Mon Sep 17 00:00:00 2001 From: Romain Ruetschi Date: Wed, 26 May 2021 10:29:11 +0200 Subject: [PATCH 45/52] Fix post-merge compile error --- relayer/src/channel.rs | 2 +- relayer/src/link.rs | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 6a15fc7fe8..9cacbf5b61 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -63,7 +63,7 @@ pub struct ChannelSide { client_id: ClientId, connection_id: ConnectionId, port_id: PortId, - pub channel_id: Option, + channel_id: Option, } impl ChannelSide { diff --git a/relayer/src/link.rs b/relayer/src/link.rs index 525d4070b7..9b164ac97e 100644 --- a/relayer/src/link.rs +++ b/relayer/src/link.rs @@ -745,7 +745,7 @@ impl RelayPath { self.dst_chain() .query_unreceived_packets(QueryUnreceivedPacketsRequest { port_id: self.dst_port_id().to_string(), - channel_id: self.dst_channel_id().to_string(), + channel_id: self.dst_channel_id()?.to_string(), packet_commitment_sequences: vec![packet.sequence.into()], })?; @@ -758,7 +758,7 @@ impl RelayPath { let (bytes, _) = self.src_chain().build_packet_proofs( PacketMsgType::Recv, self.src_port_id(), - self.src_channel_id(), + self.src_channel_id()?, packet.sequence, Height::zero(), )?; @@ -780,7 +780,7 @@ impl RelayPath { self.dst_chain() .query_unreceived_acknowledgement(QueryUnreceivedAcksRequest { port_id: self.dst_port_id().to_string(), - channel_id: self.dst_channel_id().to_string(), + channel_id: self.dst_channel_id()?.to_string(), packet_ack_sequences: vec![packet.sequence.into()], })?; @@ -1519,12 +1519,17 @@ impl RelayPath { impl fmt::Display for RelayPath { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let channel_id = self + .src_channel_id() + .map(ToString::to_string) + .unwrap_or_else(|_| "None".to_string()); + write!( f, "{}:{}/{} -> {}", self.src_chain().id(), self.src_port_id(), - self.src_channel_id(), + channel_id, self.dst_chain().id() ) } From 8cad2c39ffdc1eee2ad2db3ee6d408ae0d434dfc Mon Sep 17 00:00:00 2001 From: Romain Ruetschi Date: Wed, 26 May 2021 10:34:39 +0200 Subject: [PATCH 46/52] Return Option<&ChannelId> instead of &Option --- modules/src/ics04_channel/events.rs | 28 ++++++++++++++-------------- relayer/src/channel.rs | 8 ++++---- relayer/src/object.rs | 2 -- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/modules/src/ics04_channel/events.rs b/modules/src/ics04_channel/events.rs index ef8730dc81..5debf0d2c3 100644 --- a/modules/src/ics04_channel/events.rs +++ b/modules/src/ics04_channel/events.rs @@ -166,8 +166,8 @@ impl Attributes { pub fn port_id(&self) -> &PortId { &self.port_id } - pub fn channel_id(&self) -> &Option { - &self.channel_id + pub fn channel_id(&self) -> Option<&ChannelId> { + self.channel_id.as_ref() } } @@ -191,8 +191,8 @@ impl OpenInit { pub fn attributes(&self) -> &Attributes { &self.0 } - pub fn channel_id(&self) -> &Option { - &self.0.channel_id + pub fn channel_id(&self) -> Option<&ChannelId> { + self.0.channel_id.as_ref() } pub fn port_id(&self) -> &PortId { &self.0.port_id @@ -241,8 +241,8 @@ impl OpenTry { pub fn attributes(&self) -> &Attributes { &self.0 } - pub fn channel_id(&self) -> &Option { - &self.0.channel_id + pub fn channel_id(&self) -> Option<&ChannelId> { + self.0.channel_id.as_ref() } pub fn port_id(&self) -> &PortId { &self.0.port_id @@ -291,8 +291,8 @@ impl OpenAck { pub fn attributes(&self) -> &Attributes { &self.0 } - pub fn channel_id(&self) -> &Option { - &self.0.channel_id + pub fn channel_id(&self) -> Option<&ChannelId> { + self.0.channel_id.as_ref() } pub fn port_id(&self) -> &PortId { &self.0.port_id @@ -304,8 +304,8 @@ impl OpenAck { self.0.height = height; } - pub fn counterparty_channel_id(&self) -> &Option { - &self.0.counterparty_channel_id + pub fn counterparty_channel_id(&self) -> Option<&ChannelId> { + self.0.counterparty_channel_id.as_ref() } } @@ -345,8 +345,8 @@ impl OpenConfirm { pub fn attributes(&self) -> &Attributes { &self.0 } - pub fn channel_id(&self) -> &Option { - &self.0.channel_id + pub fn channel_id(&self) -> Option<&ChannelId> { + self.0.channel_id.as_ref() } pub fn port_id(&self) -> &PortId { &self.0.port_id @@ -466,8 +466,8 @@ impl std::fmt::Display for CloseInit { pub struct CloseConfirm(Attributes); impl CloseConfirm { - pub fn channel_id(&self) -> &Option { - &self.0.channel_id + pub fn channel_id(&self) -> Option<&ChannelId> { + self.0.channel_id.as_ref() } pub fn height(&self) -> Height { self.0.height diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 9cacbf5b61..00636bb5b7 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -1107,10 +1107,10 @@ impl Channel { pub fn extract_channel_id(event: &IbcEvent) -> Result<&ChannelId, ChannelError> { match event { - IbcEvent::OpenInitChannel(ev) => ev.channel_id().as_ref(), - IbcEvent::OpenTryChannel(ev) => ev.channel_id().as_ref(), - IbcEvent::OpenAckChannel(ev) => ev.channel_id().as_ref(), - IbcEvent::OpenConfirmChannel(ev) => ev.channel_id().as_ref(), + IbcEvent::OpenInitChannel(ev) => ev.channel_id(), + IbcEvent::OpenTryChannel(ev) => ev.channel_id(), + IbcEvent::OpenAckChannel(ev) => ev.channel_id(), + IbcEvent::OpenConfirmChannel(ev) => ev.channel_id(), _ => None, } .ok_or_else(|| ChannelError::Failed("cannot extract channel_id from result".to_string())) diff --git a/relayer/src/object.rs b/relayer/src/object.rs index dc4fd3bc04..f408d56f7a 100644 --- a/relayer/src/object.rs +++ b/relayer/src/object.rs @@ -192,7 +192,6 @@ impl Object { ) -> Result { let channel_id = e .channel_id() - .as_ref() .ok_or_else(|| format!("channel_id missing in channel open event '{:?}'", e))?; let client = channel_connection_client(chain, e.port_id(), channel_id)?.client; @@ -220,7 +219,6 @@ impl Object { ) -> Result { let channel_id = e .channel_id() - .as_ref() .ok_or_else(|| format!("channel_id missing in OpenInit event '{:?}'", e))?; let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id()); From f375b35cf3ee6654484ec2fa423c9c6829d0fad1 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Wed, 26 May 2021 12:39:53 +0200 Subject: [PATCH 47/52] Review comments --- relayer/src/channel.rs | 47 +++++++++++++--------------- relayer/src/object.rs | 9 ++---- relayer/src/supervisor.rs | 25 +++++---------- relayer/src/worker/channel.rs | 9 +++--- relayer/src/worker/retry_strategy.rs | 2 +- relayer/src/worker/uni_chan_path.rs | 2 +- 6 files changed, 39 insertions(+), 55 deletions(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 00636bb5b7..65996b0e31 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -262,10 +262,10 @@ impl Channel { let channels: Vec = counterparty_chain.query_connection_channels(req)?; - for chan in channels.iter() { + for chan in channels { if let Some(remote_channel_id) = chan.channel_end.remote.channel_id() { if remote_channel_id == &channel.src_channel_id { - handshake_channel.b_side.channel_id = Some(chan.channel_id.clone()); + handshake_channel.b_side.channel_id = Some(chan.channel_id); break; } } @@ -389,23 +389,20 @@ impl Channel { while counter < MAX_RETRIES { counter += 1; - assert!(self.src_channel_id().is_some()); - assert!(self.dst_channel_id().is_some()); - + let src_channel_id = self + .src_channel_id() + .ok_or(ChannelError::MissingLocalChannelId)?; + let dst_channel_id = self + .dst_channel_id() + .ok_or(ChannelError::MissingCounterpartyChannelId)?; // Continue loop if query error - let a_channel = a_chain.query_channel( - &self.src_port_id(), - &self.src_channel_id().unwrap(), - Height::zero(), - ); + let a_channel = + a_chain.query_channel(&self.src_port_id(), &src_channel_id, Height::zero()); if a_channel.is_err() { continue; } - let b_channel = b_chain.query_channel( - &self.dst_port_id(), - &self.dst_channel_id().unwrap(), - Height::zero(), - ); + let b_channel = + b_chain.query_channel(&self.dst_port_id(), &dst_channel_id, Height::zero()); if b_channel.is_err() { continue; } @@ -658,7 +655,7 @@ impl Channel { // Retrieve existing channel let dst_channel = self .dst_chain() - .query_channel(self.dst_port_id(), dst_channel_id, Height::default()) + .query_channel(self.dst_port_id(), dst_channel_id, Height::zero()) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; // Check if a channel is expected to exist on destination chain @@ -687,7 +684,7 @@ impl Channel { // Channel must exist on source let src_channel = self .src_chain() - .query_channel(self.src_port_id(), &src_channel_id, Height::default()) + .query_channel(self.src_port_id(), &src_channel_id, Height::zero()) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?; if src_channel.counterparty().port_id() != self.dst_port_id() { @@ -703,7 +700,7 @@ impl Channel { // Connection must exist on destination self.dst_chain() - .query_connection(self.dst_connection_id(), Height::default()) + .query_connection(self.dst_connection_id(), Height::zero()) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; let query_height = self @@ -801,12 +798,12 @@ impl Channel { // Channel must exist on source self.src_chain() - .query_channel(self.src_port_id(), src_channel_id, Height::default()) + .query_channel(self.src_port_id(), src_channel_id, Height::zero()) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?; // Connection must exist on destination self.dst_chain() - .query_connection(self.dst_connection_id(), Height::default()) + .query_connection(self.dst_connection_id(), Height::zero()) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; let query_height = self @@ -892,12 +889,12 @@ impl Channel { // Channel must exist on source self.src_chain() - .query_channel(self.src_port_id(), src_channel_id, Height::default()) + .query_channel(self.src_port_id(), src_channel_id, Height::zero()) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?; // Connection must exist on destination self.dst_chain() - .query_connection(self.dst_connection_id(), Height::default()) + .query_connection(self.dst_connection_id(), Height::zero()) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; let query_height = self @@ -970,7 +967,7 @@ impl Channel { // Channel must exist on destination self.dst_chain() - .query_channel(self.dst_port_id(), dst_channel_id, Height::default()) + .query_channel(self.dst_port_id(), dst_channel_id, Height::zero()) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; let signer = self.dst_chain().get_signer().map_err(|e| { @@ -1034,12 +1031,12 @@ impl Channel { // Channel must exist on source self.src_chain() - .query_channel(self.src_port_id(), src_channel_id, Height::default()) + .query_channel(self.src_port_id(), src_channel_id, Height::zero()) .map_err(|e| ChannelError::QueryError(self.src_chain().id(), e))?; // Connection must exist on destination self.dst_chain() - .query_connection(self.dst_connection_id(), Height::default()) + .query_connection(self.dst_connection_id(), Height::zero()) .map_err(|e| ChannelError::QueryError(self.dst_chain().id(), e))?; let query_height = self diff --git a/relayer/src/object.rs b/relayer/src/object.rs index f408d56f7a..087473936b 100644 --- a/relayer/src/object.rs +++ b/relayer/src/object.rs @@ -221,14 +221,11 @@ impl Object { .channel_id() .ok_or_else(|| format!("channel_id missing in OpenInit event '{:?}'", e))?; - let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id()); - - if dst_chain_id.is_err() { - return Err("dest chain missing in init".into()); - } + let dst_chain_id = get_counterparty_chain(src_chain, channel_id, &e.port_id()) + .map_err(|_| "dest chain missing in init".to_string())?; Ok(Channel { - dst_chain_id: dst_chain_id.unwrap(), + dst_chain_id, src_chain_id: src_chain.id(), src_channel_id: channel_id.clone(), src_port_id: e.port_id().clone(), diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index 498c9516e9..e12317e324 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -82,27 +82,16 @@ impl Supervisor { } } - IbcEvent::OpenInitChannel(ref _open_init) => { + IbcEvent::OpenInitChannel(..) | IbcEvent::OpenTryChannel(..) => { if !self.handshake_enabled() { continue; } - if let Ok(object) = Object::channel_from_chan_open_events( - event.clone().channel_attributes().unwrap(), - src_chain, - ) { - collected.per_object.entry(object).or_default().push(event); - } - } - - IbcEvent::OpenTryChannel(ref _open_try) => { - if !self.handshake_enabled() { - continue; - } - if let Ok(object) = Object::channel_from_chan_open_events( - event.clone().channel_attributes().unwrap(), - src_chain, - ) { - collected.per_object.entry(object).or_default().push(event); + if let Some(attributes) = event.clone().channel_attributes() { + if let Ok(object) = + Object::channel_from_chan_open_events(attributes, src_chain) + { + collected.per_object.entry(object).or_default().push(event); + } } } diff --git a/relayer/src/worker/channel.rs b/relayer/src/worker/channel.rs index 41097b29b8..3714845a53 100644 --- a/relayer/src/worker/channel.rs +++ b/relayer/src/worker/channel.rs @@ -55,9 +55,10 @@ impl ChannelWorker { b_chain.clone(), event.clone(), )?; - retry_with_index(retry_strategy::uni_chan_path(), |index| { - handshake_channel.step_event(event.clone(), index) - }) + retry_with_index( + retry_strategy::worker_default_strategy(), + |index| handshake_channel.step_event(event.clone(), index), + ) } None => Ok(()), } @@ -83,7 +84,7 @@ impl ChannelWorker { height, )?; - retry_with_index(retry_strategy::uni_chan_path(), |index| { + retry_with_index(retry_strategy::worker_default_strategy(), |index| { handshake_channel.step_state(state, index) }) } diff --git a/relayer/src/worker/retry_strategy.rs b/relayer/src/worker/retry_strategy.rs index 56f56b10de..be71a6f15e 100644 --- a/relayer/src/worker/retry_strategy.rs +++ b/relayer/src/worker/retry_strategy.rs @@ -6,7 +6,7 @@ const DELAY_INCR: Duration = Duration::from_millis(100); const INITIAL_DELAY: Duration = Duration::from_millis(200); const MAX_RETRY_DURATION: Duration = Duration::from_secs(2); -pub fn uni_chan_path() -> impl Iterator { +pub fn worker_default_strategy() -> impl Iterator { let strategy = ConstantGrowth::new(INITIAL_DELAY, DELAY_INCR); clamp_total(strategy, MAX_DELAY, MAX_RETRY_DURATION) } diff --git a/relayer/src/worker/uni_chan_path.rs b/relayer/src/worker/uni_chan_path.rs index 89d7a11028..6a5243edf2 100644 --- a/relayer/src/worker/uni_chan_path.rs +++ b/relayer/src/worker/uni_chan_path.rs @@ -55,7 +55,7 @@ impl UniChanPathWorker { loop { thread::sleep(Duration::from_millis(200)); - let result = retry_with_index(retry_strategy::uni_chan_path(), |index| { + let result = retry_with_index(retry_strategy::worker_default_strategy(), |index| { Self::step(rx.try_recv().ok(), &mut link, index) }); From c0b507f345d605f8903f1ef9888b2f72be7018e2 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Wed, 26 May 2021 12:47:19 +0200 Subject: [PATCH 48/52] Remove todos --- relayer/src/channel.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 65996b0e31..e3ebc7f6a2 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -183,8 +183,10 @@ impl Channel { .ok_or(ChannelError::MissingCounterpartyConnection)?; Ok(Channel { + // The event does not include the channel ordering. + // The message handlers `build_chan_open..` determine the order included in the handshake + // message from channel query. ordering: Default::default(), - //TODO how to get the order from event a_side: ChannelSide::new( chain.clone(), connection.client_id().clone(), @@ -200,7 +202,8 @@ impl Channel { channel_event_attributes.counterparty_channel_id.clone(), ), connection_delay: connection.delay_period(), - //TODO detect version from event + // The event does not include the version. + // The message handlers `build_chan_open..` determine the version from channel query. version: Some(version), }) } From d901b50afcf5e4b7363f682a6be4d9391e1d999e Mon Sep 17 00:00:00 2001 From: Romain Ruetschi Date: Wed, 26 May 2021 13:25:37 +0200 Subject: [PATCH 49/52] Update docs/architecture/adr-002-ibc-relayer.md --- docs/architecture/adr-002-ibc-relayer.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/architecture/adr-002-ibc-relayer.md b/docs/architecture/adr-002-ibc-relayer.md index 53771ebfa3..0b279da269 100644 --- a/docs/architecture/adr-002-ibc-relayer.md +++ b/docs/architecture/adr-002-ibc-relayer.md @@ -200,6 +200,7 @@ pub struct Config { } pub enum Strategy { + All, Packets, } From 3ffc73937f0f4bdd9c85482a9a90292619521702 Mon Sep 17 00:00:00 2001 From: Romain Ruetschi Date: Wed, 26 May 2021 13:30:55 +0200 Subject: [PATCH 50/52] Remove unecessary &mut self --- modules/src/events.rs | 2 +- relayer/src/channel.rs | 2 +- relayer/src/supervisor.rs | 13 +++++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/modules/src/events.rs b/modules/src/events.rs index cf1d3e476f..3277469251 100644 --- a/modules/src/events.rs +++ b/modules/src/events.rs @@ -188,7 +188,7 @@ impl IbcEvent { } } - pub fn channel_attributes(&mut self) -> Option<&ChannelAttributes> { + pub fn channel_attributes(&self) -> Option<&ChannelAttributes> { match self { IbcEvent::OpenInitChannel(ev) => Some(ev.attributes()), IbcEvent::OpenTryChannel(ev) => Some(ev.attributes()), diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index e3ebc7f6a2..e48552a3ff 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -158,7 +158,7 @@ impl Channel { pub fn restore_from_event( chain: Box, counterparty_chain: Box, - mut channel_open_event: IbcEvent, + channel_open_event: IbcEvent, ) -> Result { let channel_event_attributes = channel_open_event.channel_attributes().ok_or_else(|| { diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index e12317e324..f0fb7e8d9c 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -86,12 +86,13 @@ impl Supervisor { if !self.handshake_enabled() { continue; } - if let Some(attributes) = event.clone().channel_attributes() { - if let Ok(object) = - Object::channel_from_chan_open_events(attributes, src_chain) - { - collected.per_object.entry(object).or_default().push(event); - } + + let object = event + .channel_attributes() + .map(|attr| Object::channel_from_chan_open_events(attr, src_chain)); + + if let Some(Ok(object)) = object { + collected.per_object.entry(object).or_default().push(event); } } From 86ab51f94f84228b00156c69119976bbc2fd4490 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Wed, 26 May 2021 14:49:08 +0200 Subject: [PATCH 51/52] Set packet relaying strategy in CI, tweek sleeps to speed up CI --- ci/simple_config.toml | 2 +- docs/architecture/adr-002-ibc-relayer.md | 26 +----------------------- e2e/e2e/channel.py | 18 ++++++++-------- e2e/run.py | 10 ++++----- 4 files changed, 14 insertions(+), 42 deletions(-) diff --git a/ci/simple_config.toml b/ci/simple_config.toml index 3e9b3b551e..3e0c4c4bb2 100644 --- a/ci/simple_config.toml +++ b/ci/simple_config.toml @@ -1,5 +1,5 @@ [global] -strategy = 'all' +strategy = 'packets' log_level = 'info' [[chains]] diff --git a/docs/architecture/adr-002-ibc-relayer.md b/docs/architecture/adr-002-ibc-relayer.md index 53771ebfa3..fd6b895870 100644 --- a/docs/architecture/adr-002-ibc-relayer.md +++ b/docs/architecture/adr-002-ibc-relayer.md @@ -152,31 +152,6 @@ log_level = "error" gas_price = "0.025stake" trusting_period = "336h" -[[connections]] - -[connections.src] - client_id = "clB1" - connection_id = "connAtoB" - -[connections.dest] - client_id = "clA1" - connection_id = "connBtoA" - -[[connections.paths]] - src_port = "portA1" - dest_port = "portB1" - direction = "unidirectional" - -[[connections.paths]] - src_port = "portA2" - dest_port = "portB2" - direction = "bidirectional" - -[[connections.paths]] - src_port = "portA3" - dest_port = "portB3" - src_channel = "chan3-on-A" - dest_channel = "chan3-on-B" ``` The main sections of the configuration file are: - `global`: @@ -201,6 +176,7 @@ pub struct Config { pub enum Strategy { Packets, + HandshakeAndPackets, } pub struct GlobalConfig { diff --git a/e2e/e2e/channel.py b/e2e/e2e/channel.py index ab094d3a91..b75672907a 100644 --- a/e2e/e2e/channel.py +++ b/e2e/e2e/channel.py @@ -492,6 +492,7 @@ def verify_state(c: Config, # verify channel state on both chains, should be 'Open' for 'all' strategy, 'Init' otherwise if strategy == 'all': + sleep(10.0) for i in range(20): sleep(2.0) ibc1_chan_end = query_channel_end(c, ibc1, port_id, ibc1_chan_id) @@ -504,7 +505,7 @@ def verify_state(c: Config, assert (ibc1_chan_end.state == 'Open'), (ibc1_chan_end, "state is not Open") elif strategy == 'packets': - sleep(8.0) + sleep(5.0) ibc1_chan_end = query_channel_end(c, ibc1, port_id, ibc1_chan_id) assert (ibc1_chan_end.state == 'Init'), (ibc1_chan_end, "state is not Init") @@ -517,11 +518,10 @@ def passive_channel_start_then_init(c: Config, proc = relayer.start(c) sleep(2.0) - # 2. create a channel in Init state and wait for hermes to finish handshake + # 2. create a channel in Init state ibc1_chan_id = chan_open_init(c, dst=ibc1, src=ibc0, dst_conn=ibc1_conn_id) - sleep(10.0) - # 3. verify channel state on both chains + # 3. wait for channel handshake to finish and verify channel state on both chains verify_state(c, ibc1, ibc0, ibc1_chan_id, port_id) # 4. All good, stop the relayer @@ -536,11 +536,10 @@ def passive_channel_init_then_start(c: Config, ibc1_chan_id = chan_open_init(c, dst=ibc1, src=ibc0, dst_conn=ibc1_conn_id) sleep(2.0) - # 2. start relaying, wait for channel handshake to finish + # 2. start relaying proc = relayer.start(c) - sleep(10.0) - # 3. verify channel state on both chains + # 3. wait for channel handshake to finish and verify channel state on both chains verify_state(c, ibc1, ibc0, ibc1_chan_id, port_id) # 4. All good, stop the relayer @@ -560,11 +559,10 @@ def passive_channel_try_then_start(c: Config, ibc0_chan_id = chan_open_try(c, dst=ibc0, src=ibc1, dst_conn=ibc0_conn_id, src_port=port_id, dst_port=port_id, src_chan=ibc1_chan_id) sleep(2.0) - # 2. start relaying, wait for channel handshake to finish + # 2. start relaying proc = relayer.start(c) - sleep(10.0) - # 3. verify channel state on both chains + # 3. wait for channel handshake to finish and verify channel state on both chains verify_state(c, ibc1, ibc0, ibc1_chan_id, port_id) # 4. All good, stop the relayer diff --git a/e2e/run.py b/e2e/run.py index 8a83ebcf30..d75fdc25bc 100755 --- a/e2e/run.py +++ b/e2e/run.py @@ -77,15 +77,13 @@ def passive_packets( assert (len(unreceived) == 2), (unreceived, "unreceived packet mismatch") - sleep(5.0) - # 4. start relaying - it should clear the unreceived packets proc = relayer.start(c) - sleep(5.0) - - # 5. wait a bit and make sure there are no pending packets + # 5. wait for the relayer to initialize and pick up pending packets + sleep(10.0) + # 6. verify that there are no pending packets # hermes tx raw ft-transfer ibc-0 ibc-1 transfer channel-1 10000 1000 -n 3 packet.packet_send(c, src=ibc1, dst=ibc0 , src_port=port_id, src_channel=ibc1_channel_id, amount=10000, height_offset=1000, number_msgs=3) @@ -124,7 +122,7 @@ def passive_packets( assert (len(unreceived) == 0), (unreceived, "unreceived acks mismatch (expected 0)") - # 6. All good, stop the relayer + # 7.Stop the relayer proc.kill() From 1c76c2612a522dff25cb284eda3aa9771fc6af2b Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Wed, 26 May 2021 14:53:01 +0200 Subject: [PATCH 52/52] Small doc fix --- docs/architecture/adr-002-ibc-relayer.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/architecture/adr-002-ibc-relayer.md b/docs/architecture/adr-002-ibc-relayer.md index 53d14228fa..fd6b895870 100644 --- a/docs/architecture/adr-002-ibc-relayer.md +++ b/docs/architecture/adr-002-ibc-relayer.md @@ -175,7 +175,6 @@ pub struct Config { } pub enum Strategy { - All, Packets, HandshakeAndPackets, }