Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: 77 user story channel Implementing openack handshake #203

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

27 changes: 12 additions & 15 deletions contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
153 changes: 151 additions & 2 deletions contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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 = 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(),
Expand Down Expand Up @@ -188,9 +190,93 @@ impl<'a> ValidateChannel for CwIbcCoreContext<'a> {
fn validate_channel_open_ack(
&self,
deps: DepsMut,
info: MessageInfo,
message: &MsgChannelOpenAck,
) -> Result<Response, ContractError> {
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 = 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(),
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(
Expand Down Expand Up @@ -466,4 +552,67 @@ impl<'a> ExecuteChannel for CwIbcCoreContext<'a> {
}
}
}

fn execute_channel_open_ack(
&self,
deps: DepsMut,
message: Reply,
) -> Result<Response, ContractError> {
match message.result {
cosmwasm_std::SubMsgResult::Ok(res) => match res.data {
Some(res) => {
let data = from_binary::<cosmwasm_std::IbcEndpoint>(&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)
.add_attribute("method", "execute_channel_open_ack"))
}
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 },
})
}
}
}
}
Original file line number Diff line number Diff line change
@@ -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<cosmwasm_std::IbcChannelConnectMsg, ContractError> {
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<Response, ContractError> {
match message.result {
cosmwasm_std::SubMsgResult::Ok(res) => match res.data {
Some(res) => {
let data = from_binary::<cosmwasm_std::IbcEndpoint>(&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,
}),
})
}
}
}
}
7 changes: 4 additions & 3 deletions contracts/cosmwasm-vm/cw-ibc-core/src/ics04_channel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -36,6 +34,7 @@ use ibc::core::{
ContextError,
};
use ibc::events::IbcEventType;
pub use msg::LightClientMessage;
use std::str::FromStr;
pub use traits::*;

Expand All @@ -44,4 +43,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;
Loading