From 4106f3f841adea335e190f64d2aa53a4f16f5aee Mon Sep 17 00:00:00 2001 From: Shanith K K Date: Tue, 4 Apr 2023 12:18:44 +0530 Subject: [PATCH 1/3] chore: Add test case for open ack handshake --- .../src/ics04_channel/chan_types.rs | 2 +- .../cw-ibc-core/src/ics04_channel/events.rs | 27 +- .../cw-ibc-core/src/ics04_channel/handler.rs | 151 ++++++- .../src/ics04_channel/handler/open_ack.rs | 137 ++++++ .../cw-ibc-core/src/ics04_channel/mod.rs | 2 + .../cosmwasm-vm/cw-ibc-core/src/traits.rs | 7 + .../cw-ibc-core/tests/channel/mod.rs | 5 +- .../{ => channel}/test_channel_closeinit.rs | 14 +- .../tests/channel/test_open_ack.rs | 407 ++++++++++++++++++ .../cw-ibc-core/tests/test_channel.rs | 10 +- 10 files changed, 728 insertions(+), 34 deletions(-) create mode 100644 contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/handler/open_ack.rs rename contracts/cosmwasm-vm/cw-ibc-core/tests/{ => channel}/test_channel_closeinit.rs (95%) create mode 100644 contracts/cosmwasm-vm/cw-ibc-core/tests/channel/test_open_ack.rs diff --git a/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/chan_types.rs b/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/chan_types.rs index 4b41ddf0d..f31e6ff30 100644 --- a/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/chan_types.rs +++ b/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/chan_types.rs @@ -2,7 +2,7 @@ use super::*; #[cw_serde] pub enum LightClientChannelMessage { - OpenTry { + ChannelVerify { proof_height: String, counterparty_prefix: Vec, proof: Vec, diff --git a/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/events.rs b/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/events.rs index ae8f862cd..c0a3a0f88 100644 --- a/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/events.rs +++ b/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/events.rs @@ -58,22 +58,19 @@ pub fn create_open_try_channel_event( } // Creates OpenAckChannel IBC Event -pub fn create_open_ack_channel_event(msg: &MsgChannelOpenAck) -> Event { +pub fn create_open_ack_channel_event( + port_id_on_a: &str, + chan_id_on_a: &str, + port_id_on_b: &str, + chan_id_on_b: &str, + connection_id: &str, +) -> Event { Event::new(IbcEventType::OpenAckChannel.as_str()) - .add_attribute(PORT_ID_ATTRIBUTE_KEY, msg.port_id_on_a.as_str()) - .add_attribute(CHANNEL_ID_ATTRIBUTE_KEY, msg.chan_id_on_a.as_str()) - .add_attribute( - COUNTERPARTY_PORT_ID_ATTRIBUTE_KEY, - PortId::default().ibc_port_id().as_str(), - ) - .add_attribute( - COUNTERPARTY_CHANNEL_ID_ATTRIBUTE_KEY, - msg.chan_id_on_b.as_str(), - ) - .add_attribute( - CONN_ID_ATTRIBUTE_KEY, - ConnectionId::default().connection_id().as_str(), - ) + .add_attribute(PORT_ID_ATTRIBUTE_KEY, port_id_on_a) + .add_attribute(CHANNEL_ID_ATTRIBUTE_KEY, chan_id_on_a) + .add_attribute(COUNTERPARTY_PORT_ID_ATTRIBUTE_KEY, port_id_on_b) + .add_attribute(COUNTERPARTY_CHANNEL_ID_ATTRIBUTE_KEY, chan_id_on_b) + .add_attribute(CONN_ID_ATTRIBUTE_KEY, connection_id) } // Creates OpenConfirmChannel IBC Event diff --git a/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/handler.rs b/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/handler.rs index fec0a92d8..60402c483 100644 --- a/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/handler.rs +++ b/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/handler.rs @@ -10,6 +10,8 @@ use self::{ pub mod close_init; use close_init::*; +pub mod open_ack; +use open_ack::*; impl<'a> ValidateChannel for CwIbcCoreContext<'a> { fn validate_channel_open_init( @@ -157,7 +159,7 @@ impl<'a> ValidateChannel for CwIbcCoreContext<'a> { let chan_end_path_on_a = self.channel_path(&port_id_on_a, &chan_id_on_a); let vector = to_vec(&expected_chan_end_on_a); - let create_client_message = LightClientChannelMessage::OpenTry { + let create_client_message = LightClientChannelMessage::ChannelVerify { proof_height: message.proof_height_on_a.to_string(), counterparty_prefix: prefix_on_a.clone().into_vec(), proof: message.proof_chan_end_on_a.clone().into(), @@ -188,9 +190,93 @@ impl<'a> ValidateChannel for CwIbcCoreContext<'a> { fn validate_channel_open_ack( &self, deps: DepsMut, + info: MessageInfo, message: &MsgChannelOpenAck, ) -> Result { - todo!() + let mut chan_end_on_a = self.get_channel_end( + deps.storage, + message.port_id_on_a.clone().into(), + message.chan_id_on_a.clone().into(), + )?; + channel_open_ack_validate(message, &chan_end_on_a)?; + let conn_end_on_a = self.connection_end( + deps.storage, + chan_end_on_a.connection_hops()[0].clone().into(), + )?; + if !conn_end_on_a.state_matches(&ConnectionState::Open) { + return Err(ContractError::IbcChannelError { + error: ChannelError::ConnectionNotOpen { + connection_id: chan_end_on_a.connection_hops()[0].clone(), + }, + }); + } + let client_id_on_a = conn_end_on_a.client_id(); + let client_state_of_b_on_a = self.client_state(deps.storage, client_id_on_a)?; + let consensus_state_of_b_on_a = + self.consensus_state(deps.storage, &client_id_on_a, &message.proof_height_on_b)?; + let prefix_on_b = conn_end_on_a.counterparty().prefix(); + let port_id_on_b = &chan_end_on_a.counterparty().port_id; + let conn_id_on_b = + conn_end_on_a + .counterparty() + .connection_id() + .ok_or(ContractError::IbcChannelError { + error: ChannelError::UndefinedConnectionCounterparty { + connection_id: chan_end_on_a.connection_hops()[0].clone(), + }, + })?; + if client_state_of_b_on_a.is_frozen() { + return Err(ContractError::IbcChannelError { + error: ChannelError::FrozenClient { + client_id: client_id_on_a.clone(), + }, + }); + } + let expected_chan_end_on_b = ChannelEnd::new( + State::TryOpen, + chan_end_on_a.ordering().clone(), + Counterparty::new( + message.port_id_on_a.clone(), + Some(message.chan_id_on_a.clone()), + ), + vec![conn_id_on_b.clone()], + message.version_on_b.clone(), + ); + let chan_end_path_on_b = self.channel_path(&port_id_on_b, &message.chan_id_on_b); + let vector = to_vec(&expected_chan_end_on_b); + let create_client_message = LightClientChannelMessage::ChannelVerify { + proof_height: message.proof_height_on_b.to_string(), + counterparty_prefix: prefix_on_b.clone().into_vec(), + proof: message.proof_chan_end_on_b.clone().into(), + root: consensus_state_of_b_on_a.clone().root().clone().into_vec(), + counterparty_chan_end_path: chan_end_path_on_b, + expected_counterparty_channel_end: vector.unwrap(), + }; + let client_type = ClientType::from(client_state_of_b_on_a.client_type()); + let light_client_address = + self.get_client_from_registry(deps.as_ref().storage, client_type)?; + let create_client_message: CosmosMsg = CosmosMsg::Wasm(cosmwasm_std::WasmMsg::Execute { + contract_addr: light_client_address, + msg: to_binary(&create_client_message).unwrap(), + funds: info.funds, + }); + let sub_msg: SubMsg = SubMsg::reply_always( + create_client_message, + EXECUTE_ON_CHANNEL_OPEN_ACK_ON_LIGHT_CLIENT, + ); + + chan_end_on_a.set_version(message.version_on_b.clone()); + chan_end_on_a.set_counterparty_channel_id(message.chan_id_on_b.clone()); + self.store_channel_end( + deps.storage, + message.port_id_on_a.clone().into(), + message.chan_id_on_a.clone().into(), + chan_end_on_a, + )?; + + Ok(Response::new() + .add_attribute("action", "Light client channel open ack call") + .add_submessage(sub_msg)) } fn validate_channel_open_confirm( @@ -466,4 +552,65 @@ impl<'a> ExecuteChannel for CwIbcCoreContext<'a> { } } } + + fn execute_channel_open_ack( + &self, + deps: DepsMut, + message: Reply, + ) -> Result { + match message.result { + cosmwasm_std::SubMsgResult::Ok(res) => match res.data { + Some(res) => { + let data = from_binary::(&res).unwrap(); + let port_id = PortId::from(IbcPortId::from_str(&data.port_id).unwrap()); + let channel_id = + ChannelId::from(IbcChannelId::from_str(&data.channel_id).unwrap()); + let mut channel_end = + self.get_channel_end(deps.storage, port_id.clone(), channel_id.clone())?; + if !channel_end.state_matches(&State::Init) { + return Err(ContractError::IbcChannelError { + error: ChannelError::InvalidChannelState { + channel_id: channel_id.ibc_channel_id().clone(), + state: channel_end.state, + }, + }); + } + channel_end.set_state(State::Open); // State Change + self.store_channel_end( + deps.storage, + port_id.clone(), + channel_id.clone(), + channel_end.clone(), + )?; + self.store_channel( + deps.storage, + port_id.ibc_port_id(), + channel_id.ibc_channel_id(), + channel_end.clone(), + )?; + + let event = create_open_ack_channel_event( + port_id.ibc_port_id().as_str(), + channel_id.ibc_channel_id().as_str(), + channel_end.counterparty().port_id().as_str(), + channel_end.counterparty().channel_id().unwrap().as_str(), + channel_end.connection_hops()[0].as_str(), + ); + Ok(Response::new().add_event(event)) + } + None => { + return Err(ContractError::IbcChannelError { + error: ChannelError::Other { + description: "Data from module is Missing".to_string(), + }, + }) + } + }, + cosmwasm_std::SubMsgResult::Err(error) => { + return Err(ContractError::IbcChannelError { + error: ChannelError::Other { description: error }, + }) + } + } + } } diff --git a/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/handler/open_ack.rs b/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/handler/open_ack.rs new file mode 100644 index 000000000..a83b1740d --- /dev/null +++ b/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/handler/open_ack.rs @@ -0,0 +1,137 @@ +use super::*; + +pub fn channel_open_ack_validate( + message: &MsgChannelOpenAck, + chan_end_on_a: &ChannelEnd, +) -> Result<(), ContractError> { + if !chan_end_on_a.state_matches(&State::Init) { + return Err(ContractError::IbcChannelError { + error: ChannelError::InvalidChannelState { + channel_id: message.chan_id_on_a.clone(), + state: chan_end_on_a.state, + }, + }); + } + + if chan_end_on_a.connection_hops().len() != 1 { + return Err(ContractError::IbcChannelError { + error: ChannelError::InvalidConnectionHopsLength { + expected: 1, + actual: chan_end_on_a.connection_hops().len(), + }, + }); + } + + Ok(()) +} + +pub fn on_chan_open_ack_submessage( + channel_end: &ChannelEnd, + port_id: &PortId, + channel_id: &ChannelId, + connection_id: &ConnectionId, +) -> Result { + let port_id = port_id.clone(); + let channel_id = channel_id.ibc_channel_id(); + let counter_party_port_id = channel_end.counterparty().port_id.clone(); + let counter_party_channel = channel_end.counterparty().channel_id().unwrap().clone(); + let endpoint = cosmwasm_std::IbcEndpoint { + port_id: port_id.to_string(), + channel_id: channel_id.to_string(), + }; + let counter_party = cosmwasm_std::IbcEndpoint { + port_id: counter_party_port_id.to_string(), + channel_id: counter_party_channel.to_string(), + }; + let ibc_order = match channel_end.ordering { + Order::Unordered => cosmwasm_std::IbcOrder::Unordered, + Order::Ordered => cosmwasm_std::IbcOrder::Ordered, + Order::None => { + return Err(ContractError::IbcChannelError { + error: ChannelError::UnknownOrderType { + type_id: "None".to_string(), + }, + }) + } + }; + let ibc_channel = cosmwasm_std::IbcChannel::new( + endpoint, + counter_party, + ibc_order, + channel_end.version.to_string(), + connection_id.connection_id().to_string(), + ); + let data = cosmwasm_std::IbcChannelConnectMsg::OpenAck { + channel: ibc_channel, + counterparty_version: channel_end.version.to_string(), + }; + Ok(data) +} + +impl<'a> CwIbcCoreContext<'a> { + pub fn execute_open_ack_from_light_client_reply( + &self, + deps: DepsMut, + info: MessageInfo, + message: Reply, + ) -> Result { + match message.result { + cosmwasm_std::SubMsgResult::Ok(res) => match res.data { + Some(res) => { + let data = from_binary::(&res).unwrap(); + let port_id = PortId::from(IbcPortId::from_str(&data.port_id).unwrap()); + let channel_id = + ChannelId::from(IbcChannelId::from_str(&data.channel_id).unwrap()); + let channel_end = + self.get_channel_end(deps.storage, port_id.clone(), channel_id.clone())?; + // Getting the module address for on channel open try call + let module_id = match self.lookup_module_by_port(deps.storage, port_id.clone()) + { + Ok(addr) => addr, + Err(error) => return Err(error), + }; + let module_id = types::ModuleId::from(module_id); + let contract_address = match self.get_route(deps.storage, module_id) { + Ok(addr) => addr, + Err(error) => return Err(error), + }; + + // Generate event for calling on channel open try in x-call + let sub_message = on_chan_open_ack_submessage( + &channel_end, + &port_id, + &channel_id, + &channel_end.connection_hops[0].clone().into(), + )?; + let data = cw_xcall::msg::ExecuteMsg::IbcChannelConnect { msg: sub_message }; + let data = to_binary(&data).unwrap(); + let on_chan_open_try = create_channel_submesssage( + contract_address.to_string(), + data, + &info, + EXECUTE_ON_CHANNEL_OPEN_ACK_ON_MODULE, + ); + + Ok(Response::new() + .add_attribute("action", "channel") + .add_attribute("method", "channel_opne_init_module_validation") + .add_submessage(on_chan_open_try)) + } + None => { + return Err(ContractError::IbcChannelError { + error: ChannelError::Other { + description: "Data from module is Missing".to_string(), + }, + }) + } + }, + cosmwasm_std::SubMsgResult::Err(error) => { + return Err(ContractError::IbcChannelError { + error: ChannelError::VerifyChannelFailed(ClientError::Other { + description: error, + }), + }) + } + } + } +} diff --git a/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/mod.rs b/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/mod.rs index 23b3b684a..eeed28e5b 100644 --- a/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/mod.rs +++ b/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/mod.rs @@ -44,4 +44,6 @@ pub use traits::*; pub const EXECUTE_ON_CHANNEL_OPEN_INIT: u64 = 41; pub const EXECUTE_ON_CHANNEL_OPEN_TRY: u64 = 42; pub const EXECUTE_ON_CHANNEL_OPEN_TRY_ON_LIGHT_CLIENT: u64 = 421; +pub const EXECUTE_ON_CHANNEL_OPEN_ACK_ON_LIGHT_CLIENT: u64 = 431; +pub const EXECUTE_ON_CHANNEL_OPEN_ACK_ON_MODULE: u64 = 432; pub const EXECUTE_ON_CHANNEL_CLOSE_INIT: u64 = 45; diff --git a/contracts/cosmwasm-vm/cw-ibc-core/src/traits.rs b/contracts/cosmwasm-vm/cw-ibc-core/src/traits.rs index 6417e1c67..e615511ce 100644 --- a/contracts/cosmwasm-vm/cw-ibc-core/src/traits.rs +++ b/contracts/cosmwasm-vm/cw-ibc-core/src/traits.rs @@ -57,6 +57,7 @@ pub trait ValidateChannel { fn validate_channel_open_ack( &self, deps: DepsMut, + info: MessageInfo, message: &MsgChannelOpenAck, ) -> Result; @@ -105,4 +106,10 @@ pub trait ExecuteChannel { message: Reply, // message: &MsgChannelOpenInit, ) -> Result; + + fn execute_channel_open_ack( + &self, + deps: DepsMut, + message: Reply, + ) -> Result; } diff --git a/contracts/cosmwasm-vm/cw-ibc-core/tests/channel/mod.rs b/contracts/cosmwasm-vm/cw-ibc-core/tests/channel/mod.rs index 635811807..b31afbc63 100644 --- a/contracts/cosmwasm-vm/cw-ibc-core/tests/channel/mod.rs +++ b/contracts/cosmwasm-vm/cw-ibc-core/tests/channel/mod.rs @@ -1,2 +1,5 @@ -pub mod test_handler; pub use super::*; + +pub mod test_channel_closeinit; +pub mod test_handler; +pub mod test_open_ack; diff --git a/contracts/cosmwasm-vm/cw-ibc-core/tests/test_channel_closeinit.rs b/contracts/cosmwasm-vm/cw-ibc-core/tests/channel/test_channel_closeinit.rs similarity index 95% rename from contracts/cosmwasm-vm/cw-ibc-core/tests/test_channel_closeinit.rs rename to contracts/cosmwasm-vm/cw-ibc-core/tests/channel/test_channel_closeinit.rs index 736646e48..e4ba670a3 100644 --- a/contracts/cosmwasm-vm/cw-ibc-core/tests/test_channel_closeinit.rs +++ b/contracts/cosmwasm-vm/cw-ibc-core/tests/channel/test_channel_closeinit.rs @@ -1,8 +1,7 @@ -pub mod setup; +use super::*; use cw_ibc_core::ics04_channel::close_init::{ channel_close_init_validate, on_chan_close_init_submessage, }; -use setup::*; use std::{str::FromStr, time::Duration}; @@ -148,18 +147,7 @@ fn test_execute_close_init_channel() { let raw = get_dummy_raw_msg_chan_close_init(); let msg = MsgChannelCloseInit::try_from(raw.clone()).unwrap(); let _store = contract.init_channel_counter(deps.as_mut().storage, u64::default()); - let module_id = ibc::core::ics26_routing::context::ModuleId::from_str("xcall").unwrap(); - let port_id = PortId::from(msg.port_id_on_a.clone()); - contract - .store_module_by_port(&mut deps.storage, port_id, module_id.clone()) - .unwrap(); - let module = Addr::unchecked("contractaddress"); - let cx_module_id = cw_ibc_core::types::ModuleId::from(module_id.clone()); - contract - .add_route(&mut deps.storage, cx_module_id.clone(), &module) - .unwrap(); let connection_id = ConnectionId::new(5); - let contract = CwIbcCoreContext::new(); let channel_id = ChannelId::from(msg.chan_id_on_a.clone()); let port_id = PortId::from(msg.port_id_on_a.clone()); let channel_end = ChannelEnd { diff --git a/contracts/cosmwasm-vm/cw-ibc-core/tests/channel/test_open_ack.rs b/contracts/cosmwasm-vm/cw-ibc-core/tests/channel/test_open_ack.rs new file mode 100644 index 000000000..0d28199c1 --- /dev/null +++ b/contracts/cosmwasm-vm/cw-ibc-core/tests/channel/test_open_ack.rs @@ -0,0 +1,407 @@ +use cw_ibc_core::ics04_channel::{ + open_ack::on_chan_open_ack_submessage, EXECUTE_ON_CHANNEL_OPEN_ACK_ON_MODULE, +}; + +use super::*; + +#[test] +#[should_panic(expected = "UndefinedConnectionCounterparty")] +fn test_validate_open_ack_channel_fail_missing_counterparty() { + let mut deps = deps(); + let contract = CwIbcCoreContext::default(); + let info = create_mock_info("channel-creater", "umlg", 2000); + let raw = get_dummy_raw_msg_chan_open_ack(10); + let msg = MsgChannelOpenAck::try_from(raw.clone()).unwrap(); + let _store = contract.init_channel_counter(deps.as_mut().storage, u64::default()); + let port_id = PortId::from(msg.port_id_on_a.clone()); + + let ss = ibc::core::ics23_commitment::commitment::CommitmentPrefix::try_from( + "hello".to_string().as_bytes().to_vec(), + ); + let counter_party = ibc::core::ics03_connection::connection::Counterparty::new( + IbcClientId::default(), + None, + ss.unwrap(), + ); + let conn_end = ConnectionEnd::new( + ibc::core::ics03_connection::connection::State::Open, + IbcClientId::default(), + counter_party, + vec![ibc::core::ics03_connection::version::Version::default()], + Duration::default(), + ); + let conn_id = ConnectionId::new(5); + let contract = CwIbcCoreContext::new(); + contract + .store_connection(deps.as_mut().storage, conn_id.clone(), conn_end.clone()) + .unwrap(); + + let channel_end = ChannelEnd { + state: State::Init, + ordering: Order::Unordered, + remote: Counterparty { + port_id: port_id.ibc_port_id().clone(), + channel_id: Some(msg.chan_id_on_b.clone()), + }, + connection_hops: vec![conn_id.connection_id().clone()], + version: Version::new("xcall".to_string()), + }; + contract + .store_channel_end( + &mut deps.storage, + port_id.clone(), + msg.chan_id_on_a.clone().into(), + channel_end, + ) + .unwrap(); + let client_state: ClientState = common::icon::icon::lightclient::v1::ClientState { + trusting_period: 2, + frozen_height: 0, + max_clock_drift: 5, + latest_height: 100, + network_section_hash: vec![1, 2, 3], + validators: vec!["hash".as_bytes().to_vec()], + } + .try_into() + .unwrap(); + + let client = to_vec(&client_state); + contract + .store_client_state(&mut deps.storage, &IbcClientId::default(), client.unwrap()) + .unwrap(); + let client_type = ClientType::from(IbcClientType::new("iconclient".to_string())); + + contract + .store_client_into_registry( + &mut deps.storage, + client_type, + "contractaddress".to_string(), + ) + .unwrap(); + let consenus_state: ConsensusState = common::icon::icon::lightclient::v1::ConsensusState { + message_root: vec![1, 2, 3, 4], + } + .try_into() + .unwrap(); + let height = msg.proof_height_on_b; + let consenus_state = to_vec(&consenus_state).unwrap(); + contract + .store_consensus_state( + &mut deps.storage, + &IbcClientId::default(), + height, + consenus_state, + ) + .unwrap(); + + contract + .validate_channel_open_ack(deps.as_mut(), info.clone(), &msg) + .unwrap(); +} + +#[test] +fn test_validate_open_ack_channel() { + let mut deps = deps(); + let contract = CwIbcCoreContext::default(); + let info = create_mock_info("channel-creater", "umlg", 2000); + let raw = get_dummy_raw_msg_chan_open_ack(10); + let msg = MsgChannelOpenAck::try_from(raw.clone()).unwrap(); + let _store = contract.init_channel_counter(deps.as_mut().storage, u64::default()); + let module_id = ibc::core::ics26_routing::context::ModuleId::from_str("xcall").unwrap(); + let port_id = PortId::from(msg.port_id_on_a.clone()); + let module = Addr::unchecked("contractaddress"); + let cx_module_id = cw_ibc_core::types::ModuleId::from(module_id.clone()); + contract + .add_route(&mut deps.storage, cx_module_id.clone(), &module) + .unwrap(); + + let ss = ibc::core::ics23_commitment::commitment::CommitmentPrefix::try_from( + "hello".to_string().as_bytes().to_vec(), + ); + let connection_id = IbcConnectionId::new(5); + let counter_party = ibc::core::ics03_connection::connection::Counterparty::new( + IbcClientId::default(), + Some(connection_id), + ss.unwrap(), + ); + let conn_end = ConnectionEnd::new( + ibc::core::ics03_connection::connection::State::Open, + IbcClientId::default(), + counter_party, + vec![ibc::core::ics03_connection::version::Version::default()], + Duration::default(), + ); + let conn_id = ConnectionId::new(5); + let contract = CwIbcCoreContext::new(); + contract + .store_connection(deps.as_mut().storage, conn_id.clone(), conn_end.clone()) + .unwrap(); + + let channel_end = ChannelEnd { + state: State::Init, + ordering: Order::Unordered, + remote: Counterparty { + port_id: port_id.ibc_port_id().clone(), + channel_id: Some(msg.chan_id_on_b.clone()), + }, + connection_hops: vec![conn_id.connection_id().clone()], + version: Version::new("xcall".to_string()), + }; + contract + .store_channel_end( + &mut deps.storage, + port_id.clone(), + msg.chan_id_on_a.clone().into(), + channel_end, + ) + .unwrap(); + + let client_state: ClientState = common::icon::icon::lightclient::v1::ClientState { + trusting_period: 2, + frozen_height: 0, + max_clock_drift: 5, + latest_height: 100, + network_section_hash: vec![1, 2, 3], + validators: vec!["hash".as_bytes().to_vec()], + } + .try_into() + .unwrap(); + + let client = to_vec(&client_state); + contract + .store_client_state(&mut deps.storage, &IbcClientId::default(), client.unwrap()) + .unwrap(); + let client_type = ClientType::from(IbcClientType::new("iconclient".to_string())); + + contract + .store_client_into_registry( + &mut deps.storage, + client_type, + "contractaddress".to_string(), + ) + .unwrap(); + let consenus_state: ConsensusState = common::icon::icon::lightclient::v1::ConsensusState { + message_root: vec![1, 2, 3, 4], + } + .try_into() + .unwrap(); + let height = msg.proof_height_on_b; + let consenus_state = to_vec(&consenus_state).unwrap(); + contract + .store_consensus_state( + &mut deps.storage, + &IbcClientId::default(), + height, + consenus_state, + ) + .unwrap(); + + let res = contract.validate_channel_open_ack(deps.as_mut(), info.clone(), &msg); + + assert_eq!(res.is_ok(), true); + assert_eq!(res.unwrap().messages[0].id, 431) +} + +#[test] +fn test_execute_open_ack_from_light_client() { + let mut deps = deps(); + let contract = CwIbcCoreContext::default(); + let info = create_mock_info("channel-creater", "umlg", 2000); + let raw = get_dummy_raw_msg_chan_open_ack(10); + let msg = MsgChannelOpenAck::try_from(raw.clone()).unwrap(); + let channel_id_on_b = ChannelId::new(0); + let ss = ibc::core::ics23_commitment::commitment::CommitmentPrefix::try_from( + "hello".to_string().as_bytes().to_vec(), + ); + let connection_id = IbcConnectionId::new(5); + let counter_party = ibc::core::ics03_connection::connection::Counterparty::new( + IbcClientId::default(), + Some(connection_id.clone()), + ss.unwrap(), + ); + let conn_end = ConnectionEnd::new( + ibc::core::ics03_connection::connection::State::Open, + IbcClientId::default(), + counter_party, + vec![ibc::core::ics03_connection::version::Version::default()], + Duration::default(), + ); + contract + .store_connection( + deps.as_mut().storage, + connection_id.clone().into(), + conn_end.clone(), + ) + .unwrap(); + let counter_party = Counterparty::new(msg.port_id_on_a.clone(), Some(msg.chan_id_on_b.clone())); + let channel_end = ChannelEnd::new( + State::Init, + Order::Unordered, + counter_party, + vec![connection_id.clone()], + Version::from_str("xcall").unwrap(), + ); + let module_id = ibc::core::ics26_routing::context::ModuleId::from_str("xcall").unwrap(); + let port_id = PortId::from(msg.port_id_on_a.clone()); + contract + .store_module_by_port(&mut deps.storage, port_id, module_id.clone()) + .unwrap(); + + let module = Addr::unchecked("contractaddress"); + let cx_module_id = cw_ibc_core::types::ModuleId::from(module_id.clone()); + contract + .add_route(&mut deps.storage, cx_module_id.clone(), &module) + .unwrap(); + + let expected_data = cosmwasm_std::IbcEndpoint { + port_id: PortId::from(msg.port_id_on_a.clone()).to_string(), + channel_id: channel_id_on_b.clone().to_string(), + }; + let response = SubMsgResponse { + data: Some(to_binary(&expected_data).unwrap()), + events: vec![Event::new("action").add_attribute("action", "channel open try execution")], + }; + let result: SubMsgResult = SubMsgResult::Ok(response); + let reply = Reply { + id: EXECUTE_ON_CHANNEL_OPEN_TRY, + result, + }; + contract + .store_channel_end( + &mut deps.storage, + PortId::from(msg.port_id_on_a.clone()), + channel_id_on_b.clone(), + channel_end.clone(), + ) + .unwrap(); + + let expected = on_chan_open_ack_submessage( + &channel_end, + &PortId::from(msg.port_id_on_a.clone()), + &channel_id_on_b.clone(), + &connection_id.into(), + ); + let data = cw_xcall::msg::ExecuteMsg::IbcChannelConnect { + msg: expected.unwrap(), + }; + let data = to_binary(&data).unwrap(); + let on_chan_open_ack = create_channel_submesssage( + "contractaddress".to_string(), + data, + &info, + EXECUTE_ON_CHANNEL_OPEN_ACK_ON_MODULE, + ); + let res = contract.execute_open_ack_from_light_client_reply(deps.as_mut(), info.clone(), reply); + assert_eq!(res.is_ok(), true); + assert_eq!(res.unwrap().messages[0], on_chan_open_ack) +} + +#[test] +fn test_execute_open_ack_channel() { + let mut deps = deps(); + let contract = CwIbcCoreContext::default(); + let raw = get_dummy_raw_msg_chan_close_init(); + let msg = MsgChannelCloseInit::try_from(raw.clone()).unwrap(); + let _store = contract.init_channel_counter(deps.as_mut().storage, u64::default()); + let connection_id = ConnectionId::new(5); + let channel_id = ChannelId::from(msg.chan_id_on_a.clone()); + let port_id = PortId::from(msg.port_id_on_a.clone()); + let channel_end = ChannelEnd { + state: State::Init, + ordering: Order::Unordered, + remote: Counterparty { + port_id: port_id.ibc_port_id().clone(), + channel_id: Some(channel_id.ibc_channel_id().clone()), + }, + connection_hops: vec![connection_id.connection_id().clone()], + version: Version::new("xcall".to_string()), + }; + contract + .store_channel_end( + &mut deps.storage, + port_id.clone(), + channel_id.clone(), + channel_end.clone(), + ) + .unwrap(); + contract + .store_channel( + deps.as_mut().storage, + port_id.ibc_port_id(), + channel_id.ibc_channel_id(), + channel_end, + ) + .unwrap(); + let expected_data = cosmwasm_std::IbcEndpoint { + port_id: port_id.ibc_port_id().clone().to_string(), + channel_id: channel_id.ibc_channel_id().clone().to_string(), + }; + let response = SubMsgResponse { + data: Some(to_binary(&expected_data).unwrap()), + events: vec![Event::new("Action").add_attribute("method", "channel_open_ack")], + }; + let result: SubMsgResult = SubMsgResult::Ok(response); + let reply = Reply { + id: EXECUTE_ON_CHANNEL_OPEN_ACK_ON_MODULE, + result, + }; + + let result = contract.execute_channel_open_ack(deps.as_mut(), reply); + assert!(result.is_ok()); +} + +#[test] +#[should_panic(expected = "InvalidChannelState")] +fn test_execute_open_ack_channel_fail_invalid_state() { + let mut deps = deps(); + let contract = CwIbcCoreContext::default(); + let raw = get_dummy_raw_msg_chan_close_init(); + let msg = MsgChannelCloseInit::try_from(raw.clone()).unwrap(); + let _store = contract.init_channel_counter(deps.as_mut().storage, u64::default()); + let connection_id = ConnectionId::new(5); + let channel_id = ChannelId::from(msg.chan_id_on_a.clone()); + let port_id = PortId::from(msg.port_id_on_a.clone()); + let channel_end = ChannelEnd { + state: State::Open, + ordering: Order::Unordered, + remote: Counterparty { + port_id: port_id.ibc_port_id().clone(), + channel_id: Some(channel_id.ibc_channel_id().clone()), + }, + connection_hops: vec![connection_id.connection_id().clone()], + version: Version::new("xcall".to_string()), + }; + contract + .store_channel_end( + &mut deps.storage, + port_id.clone(), + channel_id.clone(), + channel_end.clone(), + ) + .unwrap(); + contract + .store_channel( + deps.as_mut().storage, + port_id.ibc_port_id(), + channel_id.ibc_channel_id(), + channel_end, + ) + .unwrap(); + let expected_data = cosmwasm_std::IbcEndpoint { + port_id: port_id.ibc_port_id().clone().to_string(), + channel_id: channel_id.ibc_channel_id().clone().to_string(), + }; + let response = SubMsgResponse { + data: Some(to_binary(&expected_data).unwrap()), + events: vec![Event::new("Action").add_attribute("method", "channel_open_ack")], + }; + let result: SubMsgResult = SubMsgResult::Ok(response); + let reply = Reply { + id: EXECUTE_ON_CHANNEL_OPEN_ACK_ON_MODULE, + result, + }; + + contract + .execute_channel_open_ack(deps.as_mut(), reply) + .unwrap(); +} diff --git a/contracts/cosmwasm-vm/cw-ibc-core/tests/test_channel.rs b/contracts/cosmwasm-vm/cw-ibc-core/tests/test_channel.rs index c661adac5..8a48bb87c 100644 --- a/contracts/cosmwasm-vm/cw-ibc-core/tests/test_channel.rs +++ b/contracts/cosmwasm-vm/cw-ibc-core/tests/test_channel.rs @@ -22,7 +22,7 @@ use cw_ibc_core::{ types::{ChannelId, ConnectionId, PortId}, ChannelEnd, ConnectionEnd, IbcClientId, IbcConnectionId, Sequence, }; -use cw_ibc_core::{traits::*, IbcClientType}; +use cw_ibc_core::{traits::*, IbcClientType, IbcPortId}; use ibc::{ core::ics04_channel::{ channel::{Counterparty, Order, State}, @@ -725,7 +725,13 @@ fn create_open_ack_channel_event_test() { let proof_height = 10; let default_raw_msg = get_dummy_raw_msg_chan_open_ack(proof_height); let message = MsgChannelOpenAck::try_from(default_raw_msg.clone()).unwrap(); - let event = create_open_ack_channel_event(&message); + let event = create_open_ack_channel_event( + &message.port_id_on_a.as_str(), + &message.chan_id_on_a.as_str(), + IbcPortId::default().as_str(), + &message.chan_id_on_b.as_str(), + ConnectionId::default().connection_id().as_str(), + ); assert_eq!(IbcEventType::OpenAckChannel.as_str(), event.ty); assert_eq!("channel-0", event.attributes[1].value); From 15ba632371acd5347620ee2897b27e3a5112fda1 Mon Sep 17 00:00:00 2001 From: Shanith K K Date: Tue, 4 Apr 2023 12:26:21 +0530 Subject: [PATCH 2/3] chore: fix clippy --- .../cw-ibc-core/tests/channel/test_open_ack.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/contracts/cosmwasm-vm/cw-ibc-core/tests/channel/test_open_ack.rs b/contracts/cosmwasm-vm/cw-ibc-core/tests/channel/test_open_ack.rs index 0d28199c1..bcb8a6797 100644 --- a/contracts/cosmwasm-vm/cw-ibc-core/tests/channel/test_open_ack.rs +++ b/contracts/cosmwasm-vm/cw-ibc-core/tests/channel/test_open_ack.rs @@ -1,9 +1,8 @@ +use super::*; use cw_ibc_core::ics04_channel::{ open_ack::on_chan_open_ack_submessage, EXECUTE_ON_CHANNEL_OPEN_ACK_ON_MODULE, }; -use super::*; - #[test] #[should_panic(expected = "UndefinedConnectionCounterparty")] fn test_validate_open_ack_channel_fail_missing_counterparty() { @@ -15,13 +14,13 @@ fn test_validate_open_ack_channel_fail_missing_counterparty() { let _store = contract.init_channel_counter(deps.as_mut().storage, u64::default()); let port_id = PortId::from(msg.port_id_on_a.clone()); - let ss = ibc::core::ics23_commitment::commitment::CommitmentPrefix::try_from( + let committment = ibc::core::ics23_commitment::commitment::CommitmentPrefix::try_from( "hello".to_string().as_bytes().to_vec(), ); let counter_party = ibc::core::ics03_connection::connection::Counterparty::new( IbcClientId::default(), None, - ss.unwrap(), + committment.unwrap(), ); let conn_end = ConnectionEnd::new( ibc::core::ics03_connection::connection::State::Open, @@ -115,14 +114,14 @@ fn test_validate_open_ack_channel() { .add_route(&mut deps.storage, cx_module_id.clone(), &module) .unwrap(); - let ss = ibc::core::ics23_commitment::commitment::CommitmentPrefix::try_from( + let commitement = ibc::core::ics23_commitment::commitment::CommitmentPrefix::try_from( "hello".to_string().as_bytes().to_vec(), ); let connection_id = IbcConnectionId::new(5); let counter_party = ibc::core::ics03_connection::connection::Counterparty::new( IbcClientId::default(), Some(connection_id), - ss.unwrap(), + commitement.unwrap(), ); let conn_end = ConnectionEnd::new( ibc::core::ics03_connection::connection::State::Open, From 97e8180403c1b906133f084d5a1b881554867265 Mon Sep 17 00:00:00 2001 From: shreyasbhat0 Date: Tue, 4 Apr 2023 18:16:14 +0530 Subject: [PATCH 3/3] chore: update messages --- .../cw-ibc-core/src/ics04_channel/chan_types.rs | 13 ------------- .../cw-ibc-core/src/ics04_channel/handler.rs | 8 +++++--- .../cw-ibc-core/src/ics04_channel/mod.rs | 5 ++--- contracts/cosmwasm-vm/cw-ibc-core/src/msg.rs | 8 ++++++++ 4 files changed, 15 insertions(+), 19 deletions(-) delete mode 100644 contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/chan_types.rs diff --git a/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/chan_types.rs b/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/chan_types.rs deleted file mode 100644 index f31e6ff30..000000000 --- a/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/chan_types.rs +++ /dev/null @@ -1,13 +0,0 @@ -use super::*; - -#[cw_serde] -pub enum LightClientChannelMessage { - ChannelVerify { - proof_height: String, - counterparty_prefix: Vec, - proof: Vec, - root: Vec, - counterparty_chan_end_path: Vec, - expected_counterparty_channel_end: Vec, - }, -} diff --git a/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/handler.rs b/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/handler.rs index 60402c483..41e016960 100644 --- a/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/handler.rs +++ b/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/handler.rs @@ -159,7 +159,7 @@ impl<'a> ValidateChannel for CwIbcCoreContext<'a> { let chan_end_path_on_a = self.channel_path(&port_id_on_a, &chan_id_on_a); let vector = to_vec(&expected_chan_end_on_a); - let create_client_message = LightClientChannelMessage::ChannelVerify { + let create_client_message = LightClientMessage::VerifyChannel { proof_height: message.proof_height_on_a.to_string(), counterparty_prefix: prefix_on_a.clone().into_vec(), proof: message.proof_chan_end_on_a.clone().into(), @@ -244,7 +244,7 @@ impl<'a> ValidateChannel for CwIbcCoreContext<'a> { ); let chan_end_path_on_b = self.channel_path(&port_id_on_b, &message.chan_id_on_b); let vector = to_vec(&expected_chan_end_on_b); - let create_client_message = LightClientChannelMessage::ChannelVerify { + let create_client_message = LightClientMessage::VerifyChannel { proof_height: message.proof_height_on_b.to_string(), counterparty_prefix: prefix_on_b.clone().into_vec(), proof: message.proof_chan_end_on_b.clone().into(), @@ -596,7 +596,9 @@ impl<'a> ExecuteChannel for CwIbcCoreContext<'a> { channel_end.counterparty().channel_id().unwrap().as_str(), channel_end.connection_hops()[0].as_str(), ); - Ok(Response::new().add_event(event)) + Ok(Response::new() + .add_event(event) + .add_attribute("method", "execute_channel_open_ack")) } None => { return Err(ContractError::IbcChannelError { diff --git a/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/mod.rs b/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/mod.rs index eeed28e5b..79350dfb0 100644 --- a/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/mod.rs +++ b/contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/mod.rs @@ -4,13 +4,11 @@ pub use channel::*; pub mod events; pub use events::*; pub mod handler; -pub use handler::*; -pub mod chan_types; pub use super::*; use crate::context::CwIbcCoreContext; pub use crate::types::*; -pub use chan_types::*; pub use channel::*; +pub use handler::*; use cosmwasm_std::Event; use cosmwasm_std::Reply; @@ -36,6 +34,7 @@ use ibc::core::{ ContextError, }; use ibc::events::IbcEventType; +pub use msg::LightClientMessage; use std::str::FromStr; pub use traits::*; diff --git a/contracts/cosmwasm-vm/cw-ibc-core/src/msg.rs b/contracts/cosmwasm-vm/cw-ibc-core/src/msg.rs index 6cee0a7fe..efe1b42b9 100644 --- a/contracts/cosmwasm-vm/cw-ibc-core/src/msg.rs +++ b/contracts/cosmwasm-vm/cw-ibc-core/src/msg.rs @@ -27,6 +27,14 @@ pub enum LightClientMessage { proof_upgrade_client: Vec, proof_upgrade_consensus_state: Vec, }, + VerifyChannel { + proof_height: String, + counterparty_prefix: Vec, + proof: Vec, + root: Vec, + counterparty_chan_end_path: Vec, + expected_counterparty_channel_end: Vec, + }, } #[cw_serde]