From f89884e98078f604a8e37b30da57ab7ef8e4af9b Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Jan 2021 10:53:48 +0100 Subject: [PATCH 01/14] Add new ibc message type --- packages/std/src/results/cosmos_msg.rs | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/packages/std/src/results/cosmos_msg.rs b/packages/std/src/results/cosmos_msg.rs index ce941f6090..1d5c9ad3af 100644 --- a/packages/std/src/results/cosmos_msg.rs +++ b/packages/std/src/results/cosmos_msg.rs @@ -26,6 +26,8 @@ where type_url: String, data: Binary, }, + #[cfg(feature = "stargate")] + Ibc(IbcMsg), Wasm(WasmMsg), } @@ -105,6 +107,28 @@ pub enum WasmMsg { }, } +/// These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts +/// (contracts that directly speak the IBC protocol via 6 entry points) +#[cfg(feature = "stargate")] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum IbcMsg { + /// Sends an IBC packet with given data over the existing channel. + /// Data should be encoded in a format defined by the channel version, + /// and the module on the other side should know how to parse this. + SendPacket { + channel_id: String, + data: Binary, + timeout_height: u64, + version: u64, + }, + /// This will close an existing channel that is owned by this contract. + /// Port is auto-assigned to the contracts' ibc port + CloseChannel { + channel_id: String, + } +} + impl From for CosmosMsg { fn from(msg: BankMsg) -> Self { CosmosMsg::Bank(msg) @@ -124,6 +148,13 @@ impl From for CosmosMsg } } +#[cfg(feature = "stargate")] +impl From for CosmosMsg { + fn from(msg: IbcMsg) -> Self { + CosmosMsg::Ibc(msg) + } +} + #[cfg(test)] mod tests { use super::*; From 737f58bbb963d09c3ad7e392a414ff175ffffd77 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Jan 2021 10:56:43 +0100 Subject: [PATCH 02/14] Fix build with stargate feature (mock querier) --- packages/std/src/mock.rs | 4 ++++ packages/std/src/results/cosmos_msg.rs | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/std/src/mock.rs b/packages/std/src/mock.rs index 4e3c55e9b3..080f6281bf 100644 --- a/packages/std/src/mock.rs +++ b/packages/std/src/mock.rs @@ -232,6 +232,10 @@ impl MockQuerier { QueryRequest::Custom(custom_query) => (*self.custom_handler)(custom_query), QueryRequest::Staking(staking_query) => self.staking.query(staking_query), QueryRequest::Wasm(msg) => self.wasm.query(msg), + #[cfg(feature = "stargate")] + QueryRequest::Stargate { .. } => SystemResult::Err(SystemError::UnsupportedRequest { + kind: "Stargate".to_string(), + }), } } } diff --git a/packages/std/src/results/cosmos_msg.rs b/packages/std/src/results/cosmos_msg.rs index 1d5c9ad3af..bfb4bb612a 100644 --- a/packages/std/src/results/cosmos_msg.rs +++ b/packages/std/src/results/cosmos_msg.rs @@ -124,9 +124,7 @@ pub enum IbcMsg { }, /// This will close an existing channel that is owned by this contract. /// Port is auto-assigned to the contracts' ibc port - CloseChannel { - channel_id: String, - } + CloseChannel { channel_id: String }, } impl From for CosmosMsg { From d1ce179d06cb84319f8071fc108c2f396208adfe Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Jan 2021 11:09:57 +0100 Subject: [PATCH 03/14] Add some basic IbcQuery types --- packages/std/src/ibc.rs | 36 ++++++++++++++++++++++++++ packages/std/src/lib.rs | 1 + packages/std/src/mock.rs | 4 +++ packages/std/src/query.rs | 11 ++++++++ packages/std/src/results/cosmos_msg.rs | 2 ++ 5 files changed, 54 insertions(+) create mode 100644 packages/std/src/ibc.rs diff --git a/packages/std/src/ibc.rs b/packages/std/src/ibc.rs new file mode 100644 index 0000000000..4114224e69 --- /dev/null +++ b/packages/std/src/ibc.rs @@ -0,0 +1,36 @@ +#![cfg(feature = "stargate")] +// The CosmosMsg variants are defined in results/cosmos_msg.rs +// The rest of the IBC related functionality is defined here + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +/// These are queries to the various IBC modules to see the state of the contract's +/// IBC connection. These will return errors if the contract is not "ibc enabled" +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum IbcQuery { + /// Gets the Port ID the current contract is bound to. + /// Returns PortIdResponse + PortId {}, + /// Lists all (portID, channelID) pairs that are bound to a given port + /// If port_id is omitted, list all channels bound to the contract's port. + ListChannels { port_id: Option }, + // TODO: Add more +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct PortIdResponse { + pub port_id: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct ListChannelsResponse { + pub channels: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct ChannelPair { + pub port_id: String, + pub channel_id: String, +} diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 530c97af43..cd0349d7f9 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -9,6 +9,7 @@ mod coins; mod deps; mod entry_points; mod errors; +mod ibc; #[cfg(feature = "iterator")] mod iterator; mod math; diff --git a/packages/std/src/mock.rs b/packages/std/src/mock.rs index 080f6281bf..0c62a84f5c 100644 --- a/packages/std/src/mock.rs +++ b/packages/std/src/mock.rs @@ -236,6 +236,10 @@ impl MockQuerier { QueryRequest::Stargate { .. } => SystemResult::Err(SystemError::UnsupportedRequest { kind: "Stargate".to_string(), }), + #[cfg(feature = "stargate")] + QueryRequest::Ibc(_) => SystemResult::Err(SystemError::UnsupportedRequest { + kind: "Ibc".to_string(), + }), } } } diff --git a/packages/std/src/query.rs b/packages/std/src/query.rs index 4bbeab1f4f..43a1f727cf 100644 --- a/packages/std/src/query.rs +++ b/packages/std/src/query.rs @@ -4,6 +4,8 @@ use serde::{Deserialize, Serialize}; use crate::addresses::HumanAddr; use crate::binary::Binary; use crate::coins::Coin; +#[cfg(feature = "stargate")] +use crate::ibc::IbcQuery; use crate::math::Decimal; use crate::types::Empty; @@ -24,6 +26,8 @@ pub enum QueryRequest { /// this is the expected protobuf message type (not any), binary encoded data: Binary, }, + #[cfg(feature = "stargate")] + Ibc(IbcQuery), Wasm(WasmQuery), } @@ -106,6 +110,13 @@ impl From for QueryRequest { } } +#[cfg(feature = "stargate")] +impl From for QueryRequest { + fn from(msg: IbcQuery) -> Self { + QueryRequest::Ibc(msg) + } +} + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct BalanceResponse { diff --git a/packages/std/src/results/cosmos_msg.rs b/packages/std/src/results/cosmos_msg.rs index bfb4bb612a..b00e77b2db 100644 --- a/packages/std/src/results/cosmos_msg.rs +++ b/packages/std/src/results/cosmos_msg.rs @@ -120,6 +120,8 @@ pub enum IbcMsg { channel_id: String, data: Binary, timeout_height: u64, + // TODO: does the cosmos sdk support timestamp based timeouts? + timeout_timestamp: u64, version: u64, }, /// This will close an existing channel that is owned by this contract. From bf7d66d6cee750f36fe0c47275983bdf4db8ff55 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Jan 2021 11:15:26 +0100 Subject: [PATCH 04/14] Add some basic IbcQuery types --- packages/std/src/ibc_exports.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 packages/std/src/ibc_exports.rs diff --git a/packages/std/src/ibc_exports.rs b/packages/std/src/ibc_exports.rs new file mode 100644 index 0000000000..e69de29bb2 From 223b9e5a230616f2758eed2d00d6b8450325d0f2 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Jan 2021 11:33:21 +0100 Subject: [PATCH 05/14] Add more ibc types --- packages/std/src/exports.rs | 2 +- packages/std/src/ibc.rs | 95 +++++++++++++- packages/std/src/ibc_exports.rs | 215 ++++++++++++++++++++++++++++++++ packages/std/src/lib.rs | 7 ++ 4 files changed, 316 insertions(+), 3 deletions(-) diff --git a/packages/std/src/exports.rs b/packages/std/src/exports.rs index e9ec2fd5f4..34106a0c0b 100644 --- a/packages/std/src/exports.rs +++ b/packages/std/src/exports.rs @@ -251,7 +251,7 @@ where } /// Makes all bridges to external dependencies (i.e. Wasm imports) that are injected by the VM -fn make_dependencies() -> OwnedDeps { +pub(crate) fn make_dependencies() -> OwnedDeps { OwnedDeps { storage: ExternalStorage::new(), api: ExternalApi::new(), diff --git a/packages/std/src/ibc.rs b/packages/std/src/ibc.rs index 4114224e69..64687f7f16 100644 --- a/packages/std/src/ibc.rs +++ b/packages/std/src/ibc.rs @@ -15,7 +15,16 @@ pub enum IbcQuery { PortId {}, /// Lists all (portID, channelID) pairs that are bound to a given port /// If port_id is omitted, list all channels bound to the contract's port. + /// Returns ListChannelsResponse. ListChannels { port_id: Option }, + /// Lists all information for a (portID, channelID) pair. + /// If port_id is omitted, it will default to the contract's own channel. + /// (To save a PortId{} call) + /// Returns ChannelResponse. + Channel { + channel_id: String, + port_id: Option, + }, // TODO: Add more } @@ -26,11 +35,93 @@ pub struct PortIdResponse { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct ListChannelsResponse { - pub channels: Vec, + pub channels: Vec, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct ChannelPair { +pub struct ChannelResponse { + pub channel: IbcChannel, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct IbcEndpoint { pub port_id: String, pub channel_id: String, } + +// These are various messages used in the callbacks + +/// IbcChannel defines all information on a channel. +/// This is generally used in the hand-shake process, but can be queried directly. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct IbcChannel { + pub endpoint: IbcEndpoint, + pub counterparty_endpoint: IbcEndpoint, + pub order: Order, + pub version: String, + /// CounterpartyVersion can be None when not known this context, yet + pub counterparty_version: Option, + /// The connection upon which this channel was created. If this is a multi-hop + /// channel, we only expose the first hop. + pub connection_id: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct IbcPacket { + /// The raw data send from the other side in the packet + pub data: Binary, + /// identifies the channel and port on the sending chain. + pub src: IbcEndpoint, + /// identifies the channel and port on the receiving chain. + pub dest: IbcEndpoint, + /// The sequence number of the packet on the given channel + pub sequence: u64, + /// block height after which the packet times out + pub timeout_height: u64, + /// block timestamp (in nanoseconds) after which the packet times out + pub timeout_timestamp: u64, + // the version that the client is currently on + pub version: u64, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct IbcAcknowledgement { + pub acknowledgement: Binary, + pub original_packet: IbcPacket, +} + +// type IBCPacketReceiveResponse struct { +// // Acknowledgement contains the data to acknowledge the ibc packet execution +// Acknowledgement []byte `json:"acknowledgement"` +// // Messages comes directly from the contract and is it's request for action +// Messages []CosmosMsg `json:"messages,omitempty"` +// // log message to return over abci interface +// Attributes []cosmwasmv1.EventAttribute `json:"attributes"` +// } +// +// type IBCPacketAcknowledgementResponse struct { +// Messages []CosmosMsg `json:"messages"` +// Attributes []cosmwasmv1.EventAttribute `json:"attributes"` +// } +// +// type IBCPacketTimeoutResponse struct { +// Messages []CosmosMsg `json:"messages"` +// Attributes []cosmwasmv1.EventAttribute `json:"attributes"` +// } +// +// type IBCChannelOpenResponse struct { +// // Success contains a boolean if the channel would be accepted +// Success bool `json:"result"` +// // Reason optional description why it was not accepted +// Reason string `json:"reason"` +// } +// +// type IBCChannelConnectResponse struct { +// Messages []CosmosMsg `json:"messages"` +// Attributes []cosmwasmv1.EventAttribute `json:"attributes"` +// } +// +// type IBCChannelCloseResponse struct { +// Messages []CosmosMsg `json:"messages"` +// Attributes []cosmwasmv1.EventAttribute `json:"attributes"` +// } diff --git a/packages/std/src/ibc_exports.rs b/packages/std/src/ibc_exports.rs index e69de29bb2..e7d3e23892 100644 --- a/packages/std/src/ibc_exports.rs +++ b/packages/std/src/ibc_exports.rs @@ -0,0 +1,215 @@ +#![cfg(feature = "stargate")] +use std::fmt; +use std::vec::Vec; + +use schemars::JsonSchema; +use serde::{de::DeserializeOwned, Serialize}; + +use crate::deps::OwnedDeps; +use crate::imports::{ExternalApi, ExternalQuerier, ExternalStorage}; +use crate::memory::{alloc, consume_region, release_buffer, Region}; +use crate::results::{ + ContractResult, HandleResponse, InitResponse, MigrateResponse, QueryResponse, +}; +use crate::serde::{from_slice, to_vec}; +use crate::types::Env; +use crate::{Deps, DepsMut, MessageInfo}; + +// TODO: replace with https://doc.rust-lang.org/std/ops/trait.Try.html once stabilized +macro_rules! r#try_into_contract_result { + ($expr:expr) => { + match $expr { + Ok(val) => val, + Err(err) => { + return ContractResult::Err(err.to_string()); + } + } + }; + ($expr:expr,) => { + $crate::try_into_contract_result!($expr) + }; +} + +/// do_init should be wrapped in an external "C" export, containing a contract-specific function as arg +/// +/// - `M`: message type for request +/// - `C`: custom response message type (see CosmosMsg) +/// - `E`: error type for responses +pub fn do_init( + init_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, + env_ptr: u32, + info_ptr: u32, + msg_ptr: u32, +) -> u32 +where + M: DeserializeOwned + JsonSchema, + C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, + E: ToString, +{ + let res = _do_init( + init_fn, + env_ptr as *mut Region, + info_ptr as *mut Region, + msg_ptr as *mut Region, + ); + let v = to_vec(&res).unwrap(); + release_buffer(v) as u32 +} + +/// do_handle should be wrapped in an external "C" export, containing a contract-specific function as arg +/// +/// - `M`: message type for request +/// - `C`: custom response message type (see CosmosMsg) +/// - `E`: error type for responses +pub fn do_handle( + handle_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, + env_ptr: u32, + info_ptr: u32, + msg_ptr: u32, +) -> u32 +where + M: DeserializeOwned + JsonSchema, + C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, + E: ToString, +{ + let res = _do_handle( + handle_fn, + env_ptr as *mut Region, + info_ptr as *mut Region, + msg_ptr as *mut Region, + ); + let v = to_vec(&res).unwrap(); + release_buffer(v) as u32 +} + +/// do_migrate should be wrapped in an external "C" export, containing a contract-specific function as arg +/// +/// - `M`: message type for request +/// - `C`: custom response message type (see CosmosMsg) +/// - `E`: error type for responses +pub fn do_migrate( + migrate_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, + env_ptr: u32, + info_ptr: u32, + msg_ptr: u32, +) -> u32 +where + M: DeserializeOwned + JsonSchema, + C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, + E: ToString, +{ + let res = _do_migrate( + migrate_fn, + env_ptr as *mut Region, + info_ptr as *mut Region, + msg_ptr as *mut Region, + ); + let v = to_vec(&res).unwrap(); + release_buffer(v) as u32 +} + +/// do_query should be wrapped in an external "C" export, containing a contract-specific function as arg +/// +/// - `M`: message type for request +/// - `E`: error type for responses +pub fn do_query( + query_fn: &dyn Fn(Deps, Env, M) -> Result, + env_ptr: u32, + msg_ptr: u32, +) -> u32 +where + M: DeserializeOwned + JsonSchema, + E: ToString, +{ + let res = _do_query(query_fn, env_ptr as *mut Region, msg_ptr as *mut Region); + let v = to_vec(&res).unwrap(); + release_buffer(v) as u32 +} + +fn _do_init( + init_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, + env_ptr: *mut Region, + info_ptr: *mut Region, + msg_ptr: *mut Region, +) -> ContractResult> +where + M: DeserializeOwned + JsonSchema, + C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, + E: ToString, +{ + let env: Vec = unsafe { consume_region(env_ptr) }; + let info: Vec = unsafe { consume_region(info_ptr) }; + let msg: Vec = unsafe { consume_region(msg_ptr) }; + + let env: Env = try_into_contract_result!(from_slice(&env)); + let info: MessageInfo = try_into_contract_result!(from_slice(&info)); + let msg: M = try_into_contract_result!(from_slice(&msg)); + + let mut deps = make_dependencies(); + init_fn(deps.as_mut(), env, info, msg).into() +} + +fn _do_handle( + handle_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, + env_ptr: *mut Region, + info_ptr: *mut Region, + msg_ptr: *mut Region, +) -> ContractResult> +where + M: DeserializeOwned + JsonSchema, + C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, + E: ToString, +{ + let env: Vec = unsafe { consume_region(env_ptr) }; + let info: Vec = unsafe { consume_region(info_ptr) }; + let msg: Vec = unsafe { consume_region(msg_ptr) }; + + let env: Env = try_into_contract_result!(from_slice(&env)); + let info: MessageInfo = try_into_contract_result!(from_slice(&info)); + let msg: M = try_into_contract_result!(from_slice(&msg)); + + let mut deps = make_dependencies(); + handle_fn(deps.as_mut(), env, info, msg).into() +} + +fn _do_migrate( + migrate_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, + env_ptr: *mut Region, + info_ptr: *mut Region, + msg_ptr: *mut Region, +) -> ContractResult> +where + M: DeserializeOwned + JsonSchema, + C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, + E: ToString, +{ + let env: Vec = unsafe { consume_region(env_ptr) }; + let info: Vec = unsafe { consume_region(info_ptr) }; + let msg: Vec = unsafe { consume_region(msg_ptr) }; + + let env: Env = try_into_contract_result!(from_slice(&env)); + let info: MessageInfo = try_into_contract_result!(from_slice(&info)); + let msg: M = try_into_contract_result!(from_slice(&msg)); + + let mut deps = make_dependencies(); + migrate_fn(deps.as_mut(), env, info, msg).into() +} + +fn _do_query( + query_fn: &dyn Fn(Deps, Env, M) -> Result, + env_ptr: *mut Region, + msg_ptr: *mut Region, +) -> ContractResult +where + M: DeserializeOwned + JsonSchema, + E: ToString, +{ + let env: Vec = unsafe { consume_region(env_ptr) }; + let msg: Vec = unsafe { consume_region(msg_ptr) }; + + let env: Env = try_into_contract_result!(from_slice(&env)); + let msg: M = try_into_contract_result!(from_slice(&msg)); + + let deps = make_dependencies(); + query_fn(deps.as_ref(), env, msg).into() +} diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index cd0349d7f9..59d5f1c12b 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -25,6 +25,8 @@ pub use crate::binary::{Binary, ByteArray}; pub use crate::coins::{coin, coins, has_coins, Coin}; pub use crate::deps::{Deps, DepsMut, OwnedDeps}; pub use crate::errors::{StdError, StdResult, SystemError}; +#[cfg(feature = "stargate")] +pub use crate::ibc::*; #[cfg(feature = "iterator")] pub use crate::iterator::{Order, KV}; pub use crate::math::{Decimal, Uint128}; @@ -58,6 +60,11 @@ pub use crate::exports::{do_handle, do_init, do_migrate, do_query}; #[cfg(target_arch = "wasm32")] pub use crate::imports::{ExternalApi, ExternalQuerier, ExternalStorage}; +#[cfg(all(feature = "stargate", target_arch = "wasm32"))] +mod ibc_exports; +#[cfg(all(feature = "stargate", target_arch = "wasm32"))] +pub use crate::ibc_exports::*; + // Exposed for testing only // Both unit tests and integration tests are compiled to native code, so everything in here does not need to compile to Wasm. From d465b4baff48c3cda41e89f2f70027be7d8719b8 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Jan 2021 12:21:36 +0100 Subject: [PATCH 06/14] Add two entry points for channel handshake --- packages/std/src/ibc.rs | 38 +++- packages/std/src/ibc_exports.rs | 321 +++++++++++++++++--------------- 2 files changed, 211 insertions(+), 148 deletions(-) diff --git a/packages/std/src/ibc.rs b/packages/std/src/ibc.rs index 64687f7f16..61a1440f0c 100644 --- a/packages/std/src/ibc.rs +++ b/packages/std/src/ibc.rs @@ -4,6 +4,11 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use std::fmt; + +use crate::binary::Binary; +use crate::results::{Attribute, CosmosMsg}; +use crate::types::Empty; /// These are queries to the various IBC modules to see the state of the contract's /// IBC connection. These will return errors if the contract is not "ibc enabled" @@ -57,7 +62,7 @@ pub struct IbcEndpoint { pub struct IbcChannel { pub endpoint: IbcEndpoint, pub counterparty_endpoint: IbcEndpoint, - pub order: Order, + pub order: IbcOrder, pub version: String, /// CounterpartyVersion can be None when not known this context, yet pub counterparty_version: Option, @@ -66,6 +71,15 @@ pub struct IbcChannel { pub connection_id: String, } +// TODO: check what representation we want here for encoding - string or number +/// IbcOrder defines if a channel is ORDERED or UNORDERED +#[repr(u8)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub enum IbcOrder { + Unordered = 1, + Ordered = 2, +} + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct IbcPacket { /// The raw data send from the other side in the packet @@ -90,6 +104,28 @@ pub struct IbcAcknowledgement { pub original_packet: IbcPacket, } +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct IbcConnectResponse +where + T: Clone + fmt::Debug + PartialEq + JsonSchema, +{ + pub messages: Vec>, + /// The attributes that will be emitted as part of a "wasm" event + pub attributes: Vec, +} + +impl Default for IbcConnectResponse +where + T: Clone + fmt::Debug + PartialEq + JsonSchema, +{ + fn default() -> Self { + IbcConnectResponse { + messages: vec![], + attributes: vec![], + } + } +} + // type IBCPacketReceiveResponse struct { // // Acknowledgement contains the data to acknowledge the ibc packet execution // Acknowledgement []byte `json:"acknowledgement"` diff --git a/packages/std/src/ibc_exports.rs b/packages/std/src/ibc_exports.rs index e7d3e23892..dc1299fcf5 100644 --- a/packages/std/src/ibc_exports.rs +++ b/packages/std/src/ibc_exports.rs @@ -1,19 +1,17 @@ -#![cfg(feature = "stargate")] +#![cfg(all(feature = "stargate", target_arch = "wasm32"))] use std::fmt; use std::vec::Vec; use schemars::JsonSchema; -use serde::{de::DeserializeOwned, Serialize}; +use serde::Serialize; -use crate::deps::OwnedDeps; -use crate::imports::{ExternalApi, ExternalQuerier, ExternalStorage}; -use crate::memory::{alloc, consume_region, release_buffer, Region}; -use crate::results::{ - ContractResult, HandleResponse, InitResponse, MigrateResponse, QueryResponse, -}; +use crate::exports::make_dependencies; +use crate::deps::DepsMut; +use crate::ibc::{IbcChannel, IbcConnectResponse}; +use crate::memory::{consume_region, release_buffer, Region}; +use crate::results::ContractResult; use crate::serde::{from_slice, to_vec}; use crate::types::Env; -use crate::{Deps, DepsMut, MessageInfo}; // TODO: replace with https://doc.rust-lang.org/std/ops/trait.Try.html once stabilized macro_rules! r#try_into_contract_result { @@ -30,186 +28,215 @@ macro_rules! r#try_into_contract_result { }; } -/// do_init should be wrapped in an external "C" export, containing a contract-specific function as arg +/// do_ibc_channel_open is designed for use with #[entry_point] to make a "C" extern /// -/// - `M`: message type for request -/// - `C`: custom response message type (see CosmosMsg) -/// - `E`: error type for responses -pub fn do_init( - init_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, +/// ibc_open_fn does the protocol version negotiation during channel handshake phase +pub fn do_ibc_channel_open( + ibc_open_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result<(), E>, env_ptr: u32, - info_ptr: u32, msg_ptr: u32, ) -> u32 where - M: DeserializeOwned + JsonSchema, - C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, E: ToString, { - let res = _do_init( - init_fn, - env_ptr as *mut Region, - info_ptr as *mut Region, - msg_ptr as *mut Region, - ); + let res = _do_ibc_channel_open(ibc_open_fn, env_ptr as *mut Region, msg_ptr as *mut Region); let v = to_vec(&res).unwrap(); release_buffer(v) as u32 } -/// do_handle should be wrapped in an external "C" export, containing a contract-specific function as arg -/// -/// - `M`: message type for request -/// - `C`: custom response message type (see CosmosMsg) -/// - `E`: error type for responses -pub fn do_handle( - handle_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, - env_ptr: u32, - info_ptr: u32, - msg_ptr: u32, -) -> u32 +fn _do_ibc_channel_open( + ibc_open_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result<(), E>, + env_ptr: *mut Region, + msg_ptr: *mut Region, +) -> ContractResult where - M: DeserializeOwned + JsonSchema, - C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, E: ToString, { - let res = _do_handle( - handle_fn, - env_ptr as *mut Region, - info_ptr as *mut Region, - msg_ptr as *mut Region, - ); - let v = to_vec(&res).unwrap(); - release_buffer(v) as u32 + let env: Vec = unsafe { consume_region(env_ptr) }; + let msg: Vec = unsafe { consume_region(msg_ptr) }; + + let env: Env = try_into_contract_result!(from_slice(&env)); + let msg: IbcChannel = try_into_contract_result!(from_slice(&msg)); + + let mut deps = make_dependencies(); + match ibc_open_fn(deps.as_mut(), env, msg) { + Ok(_) => ContractResult::Ok(true), + Err(e) => ContractResult::Err(e.to_string()), + } } -/// do_migrate should be wrapped in an external "C" export, containing a contract-specific function as arg +/// do_ibc_channel_connect is designed for use with #[entry_point] to make a "C" extern /// -/// - `M`: message type for request -/// - `C`: custom response message type (see CosmosMsg) -/// - `E`: error type for responses -pub fn do_migrate( - migrate_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, +/// ibc_connect_fn is a callback when a IBC channel is established (after both sides agree in open) +pub fn do_ibc_channel_connect( + ibc_connect_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, env_ptr: u32, - info_ptr: u32, msg_ptr: u32, ) -> u32 where - M: DeserializeOwned + JsonSchema, C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, E: ToString, { - let res = _do_migrate( - migrate_fn, + let res = _do_ibc_channel_connect( + ibc_connect_fn, env_ptr as *mut Region, - info_ptr as *mut Region, msg_ptr as *mut Region, ); let v = to_vec(&res).unwrap(); release_buffer(v) as u32 } -/// do_query should be wrapped in an external "C" export, containing a contract-specific function as arg -/// -/// - `M`: message type for request -/// - `E`: error type for responses -pub fn do_query( - query_fn: &dyn Fn(Deps, Env, M) -> Result, - env_ptr: u32, - msg_ptr: u32, -) -> u32 -where - M: DeserializeOwned + JsonSchema, - E: ToString, -{ - let res = _do_query(query_fn, env_ptr as *mut Region, msg_ptr as *mut Region); - let v = to_vec(&res).unwrap(); - release_buffer(v) as u32 -} - -fn _do_init( - init_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, - env_ptr: *mut Region, - info_ptr: *mut Region, - msg_ptr: *mut Region, -) -> ContractResult> -where - M: DeserializeOwned + JsonSchema, - C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, - E: ToString, -{ - let env: Vec = unsafe { consume_region(env_ptr) }; - let info: Vec = unsafe { consume_region(info_ptr) }; - let msg: Vec = unsafe { consume_region(msg_ptr) }; - - let env: Env = try_into_contract_result!(from_slice(&env)); - let info: MessageInfo = try_into_contract_result!(from_slice(&info)); - let msg: M = try_into_contract_result!(from_slice(&msg)); - - let mut deps = make_dependencies(); - init_fn(deps.as_mut(), env, info, msg).into() -} - -fn _do_handle( - handle_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, - env_ptr: *mut Region, - info_ptr: *mut Region, - msg_ptr: *mut Region, -) -> ContractResult> -where - M: DeserializeOwned + JsonSchema, - C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, - E: ToString, -{ - let env: Vec = unsafe { consume_region(env_ptr) }; - let info: Vec = unsafe { consume_region(info_ptr) }; - let msg: Vec = unsafe { consume_region(msg_ptr) }; - - let env: Env = try_into_contract_result!(from_slice(&env)); - let info: MessageInfo = try_into_contract_result!(from_slice(&info)); - let msg: M = try_into_contract_result!(from_slice(&msg)); - - let mut deps = make_dependencies(); - handle_fn(deps.as_mut(), env, info, msg).into() -} - -fn _do_migrate( - migrate_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, +fn _do_ibc_channel_connect( + ibc_connect_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, env_ptr: *mut Region, - info_ptr: *mut Region, msg_ptr: *mut Region, -) -> ContractResult> +) -> ContractResult> where - M: DeserializeOwned + JsonSchema, C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, E: ToString, { let env: Vec = unsafe { consume_region(env_ptr) }; - let info: Vec = unsafe { consume_region(info_ptr) }; let msg: Vec = unsafe { consume_region(msg_ptr) }; let env: Env = try_into_contract_result!(from_slice(&env)); - let info: MessageInfo = try_into_contract_result!(from_slice(&info)); - let msg: M = try_into_contract_result!(from_slice(&msg)); + let msg: IbcChannel = try_into_contract_result!(from_slice(&msg)); let mut deps = make_dependencies(); - migrate_fn(deps.as_mut(), env, info, msg).into() + ibc_connect_fn(deps.as_mut(), env, msg).into() } -fn _do_query( - query_fn: &dyn Fn(Deps, Env, M) -> Result, - env_ptr: *mut Region, - msg_ptr: *mut Region, -) -> ContractResult -where - M: DeserializeOwned + JsonSchema, - E: ToString, -{ - let env: Vec = unsafe { consume_region(env_ptr) }; - let msg: Vec = unsafe { consume_region(msg_ptr) }; - - let env: Env = try_into_contract_result!(from_slice(&env)); - let msg: M = try_into_contract_result!(from_slice(&msg)); - - let deps = make_dependencies(); - query_fn(deps.as_ref(), env, msg).into() -} +// /// do_handle should be wrapped in an external "C" export, containing a contract-specific function as arg +// /// +// /// - `M`: message type for request +// /// - `C`: custom response message type (see CosmosMsg) +// /// - `E`: error type for responses +// pub fn do_handle( +// handle_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, +// env_ptr: u32, +// info_ptr: u32, +// msg_ptr: u32, +// ) -> u32 +// where +// M: DeserializeOwned + JsonSchema, +// C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, +// E: ToString, +// { +// let res = _do_handle( +// handle_fn, +// env_ptr as *mut Region, +// info_ptr as *mut Region, +// msg_ptr as *mut Region, +// ); +// let v = to_vec(&res).unwrap(); +// release_buffer(v) as u32 +// } +// +// /// do_migrate should be wrapped in an external "C" export, containing a contract-specific function as arg +// /// +// /// - `M`: message type for request +// /// - `C`: custom response message type (see CosmosMsg) +// /// - `E`: error type for responses +// pub fn do_migrate( +// migrate_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, +// env_ptr: u32, +// info_ptr: u32, +// msg_ptr: u32, +// ) -> u32 +// where +// M: DeserializeOwned + JsonSchema, +// C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, +// E: ToString, +// { +// let res = _do_migrate( +// migrate_fn, +// env_ptr as *mut Region, +// info_ptr as *mut Region, +// msg_ptr as *mut Region, +// ); +// let v = to_vec(&res).unwrap(); +// release_buffer(v) as u32 +// } +// +// /// do_query should be wrapped in an external "C" export, containing a contract-specific function as arg +// /// +// /// - `M`: message type for request +// /// - `E`: error type for responses +// pub fn do_query( +// query_fn: &dyn Fn(Deps, Env, M) -> Result, +// env_ptr: u32, +// msg_ptr: u32, +// ) -> u32 +// where +// M: DeserializeOwned + JsonSchema, +// E: ToString, +// { +// let res = _do_query(query_fn, env_ptr as *mut Region, msg_ptr as *mut Region); +// let v = to_vec(&res).unwrap(); +// release_buffer(v) as u32 +// } +// +// +// fn _do_handle( +// handle_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, +// env_ptr: *mut Region, +// info_ptr: *mut Region, +// msg_ptr: *mut Region, +// ) -> ContractResult> +// where +// M: DeserializeOwned + JsonSchema, +// C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, +// E: ToString, +// { +// let env: Vec = unsafe { consume_region(env_ptr) }; +// let info: Vec = unsafe { consume_region(info_ptr) }; +// let msg: Vec = unsafe { consume_region(msg_ptr) }; +// +// let env: Env = try_into_contract_result!(from_slice(&env)); +// let info: MessageInfo = try_into_contract_result!(from_slice(&info)); +// let msg: M = try_into_contract_result!(from_slice(&msg)); +// +// let mut deps = make_dependencies(); +// handle_fn(deps.as_mut(), env, info, msg).into() +// } +// +// fn _do_migrate( +// migrate_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, +// env_ptr: *mut Region, +// info_ptr: *mut Region, +// msg_ptr: *mut Region, +// ) -> ContractResult> +// where +// M: DeserializeOwned + JsonSchema, +// C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, +// E: ToString, +// { +// let env: Vec = unsafe { consume_region(env_ptr) }; +// let info: Vec = unsafe { consume_region(info_ptr) }; +// let msg: Vec = unsafe { consume_region(msg_ptr) }; +// +// let env: Env = try_into_contract_result!(from_slice(&env)); +// let info: MessageInfo = try_into_contract_result!(from_slice(&info)); +// let msg: M = try_into_contract_result!(from_slice(&msg)); +// +// let mut deps = make_dependencies(); +// migrate_fn(deps.as_mut(), env, info, msg).into() +// } +// +// fn _do_query( +// query_fn: &dyn Fn(Deps, Env, M) -> Result, +// env_ptr: *mut Region, +// msg_ptr: *mut Region, +// ) -> ContractResult +// where +// M: DeserializeOwned + JsonSchema, +// E: ToString, +// { +// let env: Vec = unsafe { consume_region(env_ptr) }; +// let msg: Vec = unsafe { consume_region(msg_ptr) }; +// +// let env: Env = try_into_contract_result!(from_slice(&env)); +// let msg: M = try_into_contract_result!(from_slice(&msg)); +// +// let deps = make_dependencies(); +// query_fn(deps.as_ref(), env, msg).into() +// } From 7b743d94f78167a67e7c94de156dcd0a92aafdaa Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Jan 2021 12:36:57 +0100 Subject: [PATCH 07/14] Minor cleanup --- packages/std/src/ibc.rs | 36 +++++++++++++++++++++++++- packages/std/src/ibc_exports.rs | 2 +- packages/std/src/results/cosmos_msg.rs | 24 ++--------------- 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/packages/std/src/ibc.rs b/packages/std/src/ibc.rs index 61a1440f0c..dbb9d6ac37 100644 --- a/packages/std/src/ibc.rs +++ b/packages/std/src/ibc.rs @@ -10,6 +10,26 @@ use crate::binary::Binary; use crate::results::{Attribute, CosmosMsg}; use crate::types::Empty; +/// These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts +/// (contracts that directly speak the IBC protocol via 6 entry points) +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum IbcMsg { + /// Sends an IBC packet with given data over the existing channel. + /// Data should be encoded in a format defined by the channel version, + /// and the module on the other side should know how to parse this. + SendPacket { + channel_id: String, + data: Binary, + timeout_height: IbcTimeoutHeight, + timeout_timestamp: u64, + version: u64, + }, + /// This will close an existing channel that is owned by this contract. + /// Port is auto-assigned to the contracts' ibc port + CloseChannel { channel_id: String }, +} + /// These are queries to the various IBC modules to see the state of the contract's /// IBC connection. These will return errors if the contract is not "ibc enabled" #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -80,6 +100,20 @@ pub enum IbcOrder { Ordered = 2, } +// IBCTimeoutHeight Height is a monotonically increasing data type +// that can be compared against another Height for the purposes of updating and +// freezing clients. +// Ordering is (revision_number, timeout_height) +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct IbcTimeoutHeight { + /// the version that the client is currently on + /// (eg. after reseting the chain this could increment 1 as height drops to 0) + pub revision_number: u64, + /// block height after which the packet times out. + /// the height within the given revision + pub timeout_height: u64, +} + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct IbcPacket { /// The raw data send from the other side in the packet @@ -91,7 +125,7 @@ pub struct IbcPacket { /// The sequence number of the packet on the given channel pub sequence: u64, /// block height after which the packet times out - pub timeout_height: u64, + pub timeout_height: IbcTimeoutHeight, /// block timestamp (in nanoseconds) after which the packet times out pub timeout_timestamp: u64, // the version that the client is currently on diff --git a/packages/std/src/ibc_exports.rs b/packages/std/src/ibc_exports.rs index dc1299fcf5..dd8ae6ce04 100644 --- a/packages/std/src/ibc_exports.rs +++ b/packages/std/src/ibc_exports.rs @@ -5,8 +5,8 @@ use std::vec::Vec; use schemars::JsonSchema; use serde::Serialize; -use crate::exports::make_dependencies; use crate::deps::DepsMut; +use crate::exports::make_dependencies; use crate::ibc::{IbcChannel, IbcConnectResponse}; use crate::memory::{consume_region, release_buffer, Region}; use crate::results::ContractResult; diff --git a/packages/std/src/results/cosmos_msg.rs b/packages/std/src/results/cosmos_msg.rs index b00e77b2db..d3958ef876 100644 --- a/packages/std/src/results/cosmos_msg.rs +++ b/packages/std/src/results/cosmos_msg.rs @@ -5,6 +5,8 @@ use std::fmt; use crate::addresses::HumanAddr; use crate::binary::Binary; use crate::coins::Coin; +#[cfg(feature = "stargate")] +use crate::ibc::IbcMsg; use crate::types::Empty; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -107,28 +109,6 @@ pub enum WasmMsg { }, } -/// These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts -/// (contracts that directly speak the IBC protocol via 6 entry points) -#[cfg(feature = "stargate")] -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub enum IbcMsg { - /// Sends an IBC packet with given data over the existing channel. - /// Data should be encoded in a format defined by the channel version, - /// and the module on the other side should know how to parse this. - SendPacket { - channel_id: String, - data: Binary, - timeout_height: u64, - // TODO: does the cosmos sdk support timestamp based timeouts? - timeout_timestamp: u64, - version: u64, - }, - /// This will close an existing channel that is owned by this contract. - /// Port is auto-assigned to the contracts' ibc port - CloseChannel { channel_id: String }, -} - impl From for CosmosMsg { fn from(msg: BankMsg) -> Self { CosmosMsg::Bank(msg) From 121896757f841243e457a0e66702556a6902875b Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Jan 2021 13:09:55 +0100 Subject: [PATCH 08/14] Define all IBC exports --- packages/std/src/ibc.rs | 80 +++++---- packages/std/src/ibc_exports.rs | 299 +++++++++++++++++--------------- 2 files changed, 202 insertions(+), 177 deletions(-) diff --git a/packages/std/src/ibc.rs b/packages/std/src/ibc.rs index dbb9d6ac37..227d7890fd 100644 --- a/packages/std/src/ibc.rs +++ b/packages/std/src/ibc.rs @@ -138,8 +138,15 @@ pub struct IbcAcknowledgement { pub original_packet: IbcPacket, } +/// This is the return value for the majority of the ibc handlers. +/// That are able to dispatch messages / events on their own, +/// but have no meaningful return value to the calling code. +/// +/// Callbacks that have return values (like receive_packet) +/// or that cannot redispatch messages (like the handshake callbacks) +/// will use other Response types #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct IbcConnectResponse +pub struct IbcBasicResponse where T: Clone + fmt::Debug + PartialEq + JsonSchema, { @@ -148,50 +155,47 @@ where pub attributes: Vec, } -impl Default for IbcConnectResponse +impl Default for IbcBasicResponse where T: Clone + fmt::Debug + PartialEq + JsonSchema, { fn default() -> Self { - IbcConnectResponse { + IbcBasicResponse { messages: vec![], attributes: vec![], } } } -// type IBCPacketReceiveResponse struct { -// // Acknowledgement contains the data to acknowledge the ibc packet execution -// Acknowledgement []byte `json:"acknowledgement"` -// // Messages comes directly from the contract and is it's request for action -// Messages []CosmosMsg `json:"messages,omitempty"` -// // log message to return over abci interface -// Attributes []cosmwasmv1.EventAttribute `json:"attributes"` -// } -// -// type IBCPacketAcknowledgementResponse struct { -// Messages []CosmosMsg `json:"messages"` -// Attributes []cosmwasmv1.EventAttribute `json:"attributes"` -// } -// -// type IBCPacketTimeoutResponse struct { -// Messages []CosmosMsg `json:"messages"` -// Attributes []cosmwasmv1.EventAttribute `json:"attributes"` -// } -// -// type IBCChannelOpenResponse struct { -// // Success contains a boolean if the channel would be accepted -// Success bool `json:"result"` -// // Reason optional description why it was not accepted -// Reason string `json:"reason"` -// } -// -// type IBCChannelConnectResponse struct { -// Messages []CosmosMsg `json:"messages"` -// Attributes []cosmwasmv1.EventAttribute `json:"attributes"` -// } -// -// type IBCChannelCloseResponse struct { -// Messages []CosmosMsg `json:"messages"` -// Attributes []cosmwasmv1.EventAttribute `json:"attributes"` -// } +/// This is the return value for the majority of the ibc handlers. +/// That are able to dispatch messages / events on their own, +/// but have no meaningful return value to the calling code. +/// +/// Callbacks that have return values (like receive_packet) +/// or that cannot redispatch messages (like the handshake callbacks) +/// will use other Response types +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct IbcReceiveResponse +where + T: Clone + fmt::Debug + PartialEq + JsonSchema, +{ + /// The bytes we return to the contract that sent the packet. + /// This may represent a success or error of exection + pub acknowledgement: Binary, + pub messages: Vec>, + /// The attributes that will be emitted as part of a "wasm" event + pub attributes: Vec, +} + +impl Default for IbcReceiveResponse +where + T: Clone + fmt::Debug + PartialEq + JsonSchema, +{ + fn default() -> Self { + IbcReceiveResponse { + acknowledgement: Binary(vec![]), + messages: vec![], + attributes: vec![], + } + } +} diff --git a/packages/std/src/ibc_exports.rs b/packages/std/src/ibc_exports.rs index dd8ae6ce04..d0a55b0419 100644 --- a/packages/std/src/ibc_exports.rs +++ b/packages/std/src/ibc_exports.rs @@ -7,11 +7,12 @@ use serde::Serialize; use crate::deps::DepsMut; use crate::exports::make_dependencies; -use crate::ibc::{IbcChannel, IbcConnectResponse}; +use crate::ibc::{IbcBasicResponse, IbcChannel}; use crate::memory::{consume_region, release_buffer, Region}; use crate::results::ContractResult; use crate::serde::{from_slice, to_vec}; use crate::types::Env; +use crate::{IbcAcknowledgement, IbcPacket, IbcReceiveResponse}; // TODO: replace with https://doc.rust-lang.org/std/ops/trait.Try.html once stabilized macro_rules! r#try_into_contract_result { @@ -69,7 +70,7 @@ where /// /// ibc_connect_fn is a callback when a IBC channel is established (after both sides agree in open) pub fn do_ibc_channel_connect( - ibc_connect_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, + ibc_connect_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, env_ptr: u32, msg_ptr: u32, ) -> u32 @@ -87,10 +88,10 @@ where } fn _do_ibc_channel_connect( - ibc_connect_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, + ibc_connect_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, env_ptr: *mut Region, msg_ptr: *mut Region, -) -> ContractResult> +) -> ContractResult> where C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, E: ToString, @@ -105,138 +106,158 @@ where ibc_connect_fn(deps.as_mut(), env, msg).into() } -// /// do_handle should be wrapped in an external "C" export, containing a contract-specific function as arg -// /// -// /// - `M`: message type for request -// /// - `C`: custom response message type (see CosmosMsg) -// /// - `E`: error type for responses -// pub fn do_handle( -// handle_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, -// env_ptr: u32, -// info_ptr: u32, -// msg_ptr: u32, -// ) -> u32 -// where -// M: DeserializeOwned + JsonSchema, -// C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, -// E: ToString, -// { -// let res = _do_handle( -// handle_fn, -// env_ptr as *mut Region, -// info_ptr as *mut Region, -// msg_ptr as *mut Region, -// ); -// let v = to_vec(&res).unwrap(); -// release_buffer(v) as u32 -// } -// -// /// do_migrate should be wrapped in an external "C" export, containing a contract-specific function as arg -// /// -// /// - `M`: message type for request -// /// - `C`: custom response message type (see CosmosMsg) -// /// - `E`: error type for responses -// pub fn do_migrate( -// migrate_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, -// env_ptr: u32, -// info_ptr: u32, -// msg_ptr: u32, -// ) -> u32 -// where -// M: DeserializeOwned + JsonSchema, -// C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, -// E: ToString, -// { -// let res = _do_migrate( -// migrate_fn, -// env_ptr as *mut Region, -// info_ptr as *mut Region, -// msg_ptr as *mut Region, -// ); -// let v = to_vec(&res).unwrap(); -// release_buffer(v) as u32 -// } -// -// /// do_query should be wrapped in an external "C" export, containing a contract-specific function as arg -// /// -// /// - `M`: message type for request -// /// - `E`: error type for responses -// pub fn do_query( -// query_fn: &dyn Fn(Deps, Env, M) -> Result, -// env_ptr: u32, -// msg_ptr: u32, -// ) -> u32 -// where -// M: DeserializeOwned + JsonSchema, -// E: ToString, -// { -// let res = _do_query(query_fn, env_ptr as *mut Region, msg_ptr as *mut Region); -// let v = to_vec(&res).unwrap(); -// release_buffer(v) as u32 -// } -// -// -// fn _do_handle( -// handle_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, -// env_ptr: *mut Region, -// info_ptr: *mut Region, -// msg_ptr: *mut Region, -// ) -> ContractResult> -// where -// M: DeserializeOwned + JsonSchema, -// C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, -// E: ToString, -// { -// let env: Vec = unsafe { consume_region(env_ptr) }; -// let info: Vec = unsafe { consume_region(info_ptr) }; -// let msg: Vec = unsafe { consume_region(msg_ptr) }; -// -// let env: Env = try_into_contract_result!(from_slice(&env)); -// let info: MessageInfo = try_into_contract_result!(from_slice(&info)); -// let msg: M = try_into_contract_result!(from_slice(&msg)); -// -// let mut deps = make_dependencies(); -// handle_fn(deps.as_mut(), env, info, msg).into() -// } -// -// fn _do_migrate( -// migrate_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, -// env_ptr: *mut Region, -// info_ptr: *mut Region, -// msg_ptr: *mut Region, -// ) -> ContractResult> -// where -// M: DeserializeOwned + JsonSchema, -// C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, -// E: ToString, -// { -// let env: Vec = unsafe { consume_region(env_ptr) }; -// let info: Vec = unsafe { consume_region(info_ptr) }; -// let msg: Vec = unsafe { consume_region(msg_ptr) }; -// -// let env: Env = try_into_contract_result!(from_slice(&env)); -// let info: MessageInfo = try_into_contract_result!(from_slice(&info)); -// let msg: M = try_into_contract_result!(from_slice(&msg)); -// -// let mut deps = make_dependencies(); -// migrate_fn(deps.as_mut(), env, info, msg).into() -// } -// -// fn _do_query( -// query_fn: &dyn Fn(Deps, Env, M) -> Result, -// env_ptr: *mut Region, -// msg_ptr: *mut Region, -// ) -> ContractResult -// where -// M: DeserializeOwned + JsonSchema, -// E: ToString, -// { -// let env: Vec = unsafe { consume_region(env_ptr) }; -// let msg: Vec = unsafe { consume_region(msg_ptr) }; -// -// let env: Env = try_into_contract_result!(from_slice(&env)); -// let msg: M = try_into_contract_result!(from_slice(&msg)); -// -// let deps = make_dependencies(); -// query_fn(deps.as_ref(), env, msg).into() -// } +/// do_ibc_channel_close is designed for use with #[entry_point] to make a "C" extern +/// +/// ibc_close_fn is a callback when a IBC channel belonging to this contract is closed +pub fn do_ibc_channel_close( + ibc_close_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, + env_ptr: u32, + msg_ptr: u32, +) -> u32 +where + C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, + E: ToString, +{ + let res = _do_ibc_channel_close(ibc_close_fn, env_ptr as *mut Region, msg_ptr as *mut Region); + let v = to_vec(&res).unwrap(); + release_buffer(v) as u32 +} + +fn _do_ibc_channel_close( + ibc_close_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, + env_ptr: *mut Region, + msg_ptr: *mut Region, +) -> ContractResult> +where + C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, + E: ToString, +{ + let env: Vec = unsafe { consume_region(env_ptr) }; + let msg: Vec = unsafe { consume_region(msg_ptr) }; + + let env: Env = try_into_contract_result!(from_slice(&env)); + let msg: IbcChannel = try_into_contract_result!(from_slice(&msg)); + + let mut deps = make_dependencies(); + ibc_close_fn(deps.as_mut(), env, msg).into() +} + +/// do_ibc_packet_receive is designed for use with #[entry_point] to make a "C" extern +/// +/// ibc_receive_fn is called when this chain receives an IBC Packet on a channel belonging +/// to this contract +pub fn do_ibc_packet_receive( + ibc_receive_fn: &dyn Fn(DepsMut, Env, IbcPacket) -> Result, E>, + env_ptr: u32, + msg_ptr: u32, +) -> u32 +where + C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, + E: ToString, +{ + let res = _do_ibc_packet_receive( + ibc_receive_fn, + env_ptr as *mut Region, + msg_ptr as *mut Region, + ); + let v = to_vec(&res).unwrap(); + release_buffer(v) as u32 +} + +fn _do_ibc_packet_receive( + ibc_receive_fn: &dyn Fn(DepsMut, Env, IbcPacket) -> Result, E>, + env_ptr: *mut Region, + msg_ptr: *mut Region, +) -> ContractResult> +where + C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, + E: ToString, +{ + let env: Vec = unsafe { consume_region(env_ptr) }; + let msg: Vec = unsafe { consume_region(msg_ptr) }; + + let env: Env = try_into_contract_result!(from_slice(&env)); + let msg: IbcPacket = try_into_contract_result!(from_slice(&msg)); + + let mut deps = make_dependencies(); + ibc_receive_fn(deps.as_mut(), env, msg).into() +} + +/// do_ibc_packet_ack is designed for use with #[entry_point] to make a "C" extern +/// +/// ibc_ack_fn is called when this chain receives an IBC Acknowledgement for a packet +/// that this contract previously sent +pub fn do_ibc_packet_ack( + ibc_ack_fn: &dyn Fn(DepsMut, Env, IbcAcknowledgement) -> Result, E>, + env_ptr: u32, + msg_ptr: u32, +) -> u32 +where + C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, + E: ToString, +{ + let res = _do_ibc_packet_ack(ibc_ack_fn, env_ptr as *mut Region, msg_ptr as *mut Region); + let v = to_vec(&res).unwrap(); + release_buffer(v) as u32 +} + +fn _do_ibc_packet_ack( + ibc_ack_fn: &dyn Fn(DepsMut, Env, IbcAcknowledgement) -> Result, E>, + env_ptr: *mut Region, + msg_ptr: *mut Region, +) -> ContractResult> +where + C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, + E: ToString, +{ + let env: Vec = unsafe { consume_region(env_ptr) }; + let msg: Vec = unsafe { consume_region(msg_ptr) }; + + let env: Env = try_into_contract_result!(from_slice(&env)); + let msg: IbcAcknowledgement = try_into_contract_result!(from_slice(&msg)); + + let mut deps = make_dependencies(); + ibc_ack_fn(deps.as_mut(), env, msg).into() +} + +/// do_ibc_packet_timeout is designed for use with #[entry_point] to make a "C" extern +/// +/// ibc_timeout_fn is called when a packet that this contract previously sent has provably +/// timedout and will never be relayed to the calling chain. This generally behaves +/// like ick_ack_fn upon an acknowledgement containing an error. +pub fn do_ibc_packet_timeout( + ibc_timeout_fn: &dyn Fn(DepsMut, Env, IbcPacket) -> Result, E>, + env_ptr: u32, + msg_ptr: u32, +) -> u32 +where + C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, + E: ToString, +{ + let res = _do_ibc_packet_timeout( + ibc_timeout_fn, + env_ptr as *mut Region, + msg_ptr as *mut Region, + ); + let v = to_vec(&res).unwrap(); + release_buffer(v) as u32 +} + +fn _do_ibc_packet_timeout( + ibc_timeout_fn: &dyn Fn(DepsMut, Env, IbcPacket) -> Result, E>, + env_ptr: *mut Region, + msg_ptr: *mut Region, +) -> ContractResult> +where + C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, + E: ToString, +{ + let env: Vec = unsafe { consume_region(env_ptr) }; + let msg: Vec = unsafe { consume_region(msg_ptr) }; + + let env: Env = try_into_contract_result!(from_slice(&env)); + let msg: IbcPacket = try_into_contract_result!(from_slice(&msg)); + + let mut deps = make_dependencies(); + ibc_timeout_fn(deps.as_mut(), env, msg).into() +} From 5a819fbe0e42f19a8414232d70b6aeabb2cb483c Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Jan 2021 13:19:57 +0100 Subject: [PATCH 09/14] Addressed some PR comments --- packages/std/src/ibc.rs | 2 +- packages/std/src/ibc_exports.rs | 72 ++++++++++++++------------------- 2 files changed, 31 insertions(+), 43 deletions(-) diff --git a/packages/std/src/ibc.rs b/packages/std/src/ibc.rs index 227d7890fd..c511456ecd 100644 --- a/packages/std/src/ibc.rs +++ b/packages/std/src/ibc.rs @@ -93,7 +93,7 @@ pub struct IbcChannel { // TODO: check what representation we want here for encoding - string or number /// IbcOrder defines if a channel is ORDERED or UNORDERED -#[repr(u8)] +/// Values come from https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/core/channel/v1/channel.proto#L69-L80 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub enum IbcOrder { Unordered = 1, diff --git a/packages/std/src/ibc_exports.rs b/packages/std/src/ibc_exports.rs index d0a55b0419..b73a095343 100644 --- a/packages/std/src/ibc_exports.rs +++ b/packages/std/src/ibc_exports.rs @@ -31,22 +31,22 @@ macro_rules! r#try_into_contract_result { /// do_ibc_channel_open is designed for use with #[entry_point] to make a "C" extern /// -/// ibc_open_fn does the protocol version negotiation during channel handshake phase +/// contract_fn does the protocol version negotiation during channel handshake phase pub fn do_ibc_channel_open( - ibc_open_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result<(), E>, + contract_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result<(), E>, env_ptr: u32, msg_ptr: u32, ) -> u32 where E: ToString, { - let res = _do_ibc_channel_open(ibc_open_fn, env_ptr as *mut Region, msg_ptr as *mut Region); + let res = _do_ibc_channel_open(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region); let v = to_vec(&res).unwrap(); release_buffer(v) as u32 } fn _do_ibc_channel_open( - ibc_open_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result<(), E>, + contract_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result<(), E>, env_ptr: *mut Region, msg_ptr: *mut Region, ) -> ContractResult @@ -60,7 +60,7 @@ where let msg: IbcChannel = try_into_contract_result!(from_slice(&msg)); let mut deps = make_dependencies(); - match ibc_open_fn(deps.as_mut(), env, msg) { + match contract_fn(deps.as_mut(), env, msg) { Ok(_) => ContractResult::Ok(true), Err(e) => ContractResult::Err(e.to_string()), } @@ -68,9 +68,9 @@ where /// do_ibc_channel_connect is designed for use with #[entry_point] to make a "C" extern /// -/// ibc_connect_fn is a callback when a IBC channel is established (after both sides agree in open) +/// contract_fn is a callback when a IBC channel is established (after both sides agree in open) pub fn do_ibc_channel_connect( - ibc_connect_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, + contract_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, env_ptr: u32, msg_ptr: u32, ) -> u32 @@ -78,17 +78,13 @@ where C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, E: ToString, { - let res = _do_ibc_channel_connect( - ibc_connect_fn, - env_ptr as *mut Region, - msg_ptr as *mut Region, - ); + let res = _do_ibc_channel_connect(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region); let v = to_vec(&res).unwrap(); release_buffer(v) as u32 } fn _do_ibc_channel_connect( - ibc_connect_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, + contract_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, env_ptr: *mut Region, msg_ptr: *mut Region, ) -> ContractResult> @@ -103,14 +99,14 @@ where let msg: IbcChannel = try_into_contract_result!(from_slice(&msg)); let mut deps = make_dependencies(); - ibc_connect_fn(deps.as_mut(), env, msg).into() + contract_fn(deps.as_mut(), env, msg).into() } /// do_ibc_channel_close is designed for use with #[entry_point] to make a "C" extern /// -/// ibc_close_fn is a callback when a IBC channel belonging to this contract is closed +/// contract_fn is a callback when a IBC channel belonging to this contract is closed pub fn do_ibc_channel_close( - ibc_close_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, + contract_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, env_ptr: u32, msg_ptr: u32, ) -> u32 @@ -118,13 +114,13 @@ where C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, E: ToString, { - let res = _do_ibc_channel_close(ibc_close_fn, env_ptr as *mut Region, msg_ptr as *mut Region); + let res = _do_ibc_channel_close(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region); let v = to_vec(&res).unwrap(); release_buffer(v) as u32 } fn _do_ibc_channel_close( - ibc_close_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, + contract_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result, E>, env_ptr: *mut Region, msg_ptr: *mut Region, ) -> ContractResult> @@ -139,15 +135,15 @@ where let msg: IbcChannel = try_into_contract_result!(from_slice(&msg)); let mut deps = make_dependencies(); - ibc_close_fn(deps.as_mut(), env, msg).into() + contract_fn(deps.as_mut(), env, msg).into() } /// do_ibc_packet_receive is designed for use with #[entry_point] to make a "C" extern /// -/// ibc_receive_fn is called when this chain receives an IBC Packet on a channel belonging +/// contract_fn is called when this chain receives an IBC Packet on a channel belonging /// to this contract pub fn do_ibc_packet_receive( - ibc_receive_fn: &dyn Fn(DepsMut, Env, IbcPacket) -> Result, E>, + contract_fn: &dyn Fn(DepsMut, Env, IbcPacket) -> Result, E>, env_ptr: u32, msg_ptr: u32, ) -> u32 @@ -155,17 +151,13 @@ where C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, E: ToString, { - let res = _do_ibc_packet_receive( - ibc_receive_fn, - env_ptr as *mut Region, - msg_ptr as *mut Region, - ); + let res = _do_ibc_packet_receive(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region); let v = to_vec(&res).unwrap(); release_buffer(v) as u32 } fn _do_ibc_packet_receive( - ibc_receive_fn: &dyn Fn(DepsMut, Env, IbcPacket) -> Result, E>, + contract_fn: &dyn Fn(DepsMut, Env, IbcPacket) -> Result, E>, env_ptr: *mut Region, msg_ptr: *mut Region, ) -> ContractResult> @@ -180,15 +172,15 @@ where let msg: IbcPacket = try_into_contract_result!(from_slice(&msg)); let mut deps = make_dependencies(); - ibc_receive_fn(deps.as_mut(), env, msg).into() + contract_fn(deps.as_mut(), env, msg).into() } /// do_ibc_packet_ack is designed for use with #[entry_point] to make a "C" extern /// -/// ibc_ack_fn is called when this chain receives an IBC Acknowledgement for a packet +/// contract_fn is called when this chain receives an IBC Acknowledgement for a packet /// that this contract previously sent pub fn do_ibc_packet_ack( - ibc_ack_fn: &dyn Fn(DepsMut, Env, IbcAcknowledgement) -> Result, E>, + contract_fn: &dyn Fn(DepsMut, Env, IbcAcknowledgement) -> Result, E>, env_ptr: u32, msg_ptr: u32, ) -> u32 @@ -196,13 +188,13 @@ where C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, E: ToString, { - let res = _do_ibc_packet_ack(ibc_ack_fn, env_ptr as *mut Region, msg_ptr as *mut Region); + let res = _do_ibc_packet_ack(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region); let v = to_vec(&res).unwrap(); release_buffer(v) as u32 } fn _do_ibc_packet_ack( - ibc_ack_fn: &dyn Fn(DepsMut, Env, IbcAcknowledgement) -> Result, E>, + contract_fn: &dyn Fn(DepsMut, Env, IbcAcknowledgement) -> Result, E>, env_ptr: *mut Region, msg_ptr: *mut Region, ) -> ContractResult> @@ -217,16 +209,16 @@ where let msg: IbcAcknowledgement = try_into_contract_result!(from_slice(&msg)); let mut deps = make_dependencies(); - ibc_ack_fn(deps.as_mut(), env, msg).into() + contract_fn(deps.as_mut(), env, msg).into() } /// do_ibc_packet_timeout is designed for use with #[entry_point] to make a "C" extern /// -/// ibc_timeout_fn is called when a packet that this contract previously sent has provably +/// contract_fn is called when a packet that this contract previously sent has provably /// timedout and will never be relayed to the calling chain. This generally behaves /// like ick_ack_fn upon an acknowledgement containing an error. pub fn do_ibc_packet_timeout( - ibc_timeout_fn: &dyn Fn(DepsMut, Env, IbcPacket) -> Result, E>, + contract_fn: &dyn Fn(DepsMut, Env, IbcPacket) -> Result, E>, env_ptr: u32, msg_ptr: u32, ) -> u32 @@ -234,17 +226,13 @@ where C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema, E: ToString, { - let res = _do_ibc_packet_timeout( - ibc_timeout_fn, - env_ptr as *mut Region, - msg_ptr as *mut Region, - ); + let res = _do_ibc_packet_timeout(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region); let v = to_vec(&res).unwrap(); release_buffer(v) as u32 } fn _do_ibc_packet_timeout( - ibc_timeout_fn: &dyn Fn(DepsMut, Env, IbcPacket) -> Result, E>, + contract_fn: &dyn Fn(DepsMut, Env, IbcPacket) -> Result, E>, env_ptr: *mut Region, msg_ptr: *mut Region, ) -> ContractResult> @@ -259,5 +247,5 @@ where let msg: IbcPacket = try_into_contract_result!(from_slice(&msg)); let mut deps = make_dependencies(); - ibc_timeout_fn(deps.as_mut(), env, msg).into() + contract_fn(deps.as_mut(), env, msg).into() } From 5dd4e617662e45f98e2f4623015134c1ef6fe73d Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Jan 2021 13:23:52 +0100 Subject: [PATCH 10/14] Make cosmwasm-std/lib.rs exports explicit --- packages/std/src/lib.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 59d5f1c12b..6a4b627e45 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -26,7 +26,11 @@ pub use crate::coins::{coin, coins, has_coins, Coin}; pub use crate::deps::{Deps, DepsMut, OwnedDeps}; pub use crate::errors::{StdError, StdResult, SystemError}; #[cfg(feature = "stargate")] -pub use crate::ibc::*; +pub use crate::ibc::{ + ChannelResponse, IbcAcknowledgement, IbcBasicResponse, IbcChannel, IbcEndpoint, IbcMsg, + IbcOrder, IbcPacket, IbcQuery, IbcReceiveResponse, IbcTimeoutHeight, ListChannelsResponse, + PortIdResponse, +}; #[cfg(feature = "iterator")] pub use crate::iterator::{Order, KV}; pub use crate::math::{Decimal, Uint128}; @@ -63,7 +67,10 @@ pub use crate::imports::{ExternalApi, ExternalQuerier, ExternalStorage}; #[cfg(all(feature = "stargate", target_arch = "wasm32"))] mod ibc_exports; #[cfg(all(feature = "stargate", target_arch = "wasm32"))] -pub use crate::ibc_exports::*; +pub use crate::ibc_exports::{ + do_ibc_channel_close, do_ibc_channel_connect, do_ibc_channel_open, do_ibc_packet_ack, + do_ibc_packet_receive, do_ibc_packet_timeout, +}; // Exposed for testing only // Both unit tests and integration tests are compiled to native code, so everything in here does not need to compile to Wasm. From b8acfedf50f112cd25ef3de31629910719fac0df Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Jan 2021 13:34:06 +0100 Subject: [PATCH 11/14] Add Ics20Transfer to IbcMsg --- packages/std/src/ibc.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/std/src/ibc.rs b/packages/std/src/ibc.rs index c511456ecd..8112d72e76 100644 --- a/packages/std/src/ibc.rs +++ b/packages/std/src/ibc.rs @@ -6,7 +6,9 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::fmt; +use crate::addresses::HumanAddr; use crate::binary::Binary; +use crate::coins::Coin; use crate::results::{Attribute, CosmosMsg}; use crate::types::Empty; @@ -15,6 +17,20 @@ use crate::types::Empty; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum IbcMsg { + /// Sends bank tokens owned by the contract to the given address on another chain. + /// The channel must already be established between the ibctransfer module on this chain + /// and a matching module on the remote chain. + /// We cannot select the port_id, this is whatever the local chain has bound the ibctransfer + /// module to. + Ics20Transfer { + /// exisiting channel to send the tokens over + channel_id: String, + /// address on the remote chain to receive these tokens + to_address: HumanAddr, + /// packet data only supports one coin + /// https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20 + amount: Coin, + }, /// Sends an IBC packet with given data over the existing channel. /// Data should be encoded in a format defined by the channel version, /// and the module on the other side should know how to parse this. From baf6f9cd32418632572a3c844db5c3cd0328f129 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Jan 2021 13:36:43 +0100 Subject: [PATCH 12/14] Ensure stargate code is tested in the CI --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2b9f83afd9..2d2ac008d4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -96,15 +96,15 @@ jobs: - run: name: Build library for native target (all features) working_directory: ~/project/packages/std - command: cargo build --locked --features iterator,staking + command: cargo build --locked --features iterator,staking,stargate - run: name: Build library for wasm target (all features) working_directory: ~/project/packages/std - command: cargo wasm --locked --features iterator,staking + command: cargo wasm --locked --features iterator,staking,stargate - run: name: Run unit tests (all features) working_directory: ~/project/packages/std - command: cargo test --locked --features iterator,staking + command: cargo test --locked --features iterator,staking,stargate - run: name: Build and run schema generator working_directory: ~/project/packages/std From 34cd29f95025578d60712eeec2465308d3bf4529 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Jan 2021 13:53:30 +0100 Subject: [PATCH 13/14] Return empty okay for do_ibc_channel_open --- packages/std/src/ibc_exports.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/std/src/ibc_exports.rs b/packages/std/src/ibc_exports.rs index b73a095343..611588aa64 100644 --- a/packages/std/src/ibc_exports.rs +++ b/packages/std/src/ibc_exports.rs @@ -49,7 +49,7 @@ fn _do_ibc_channel_open( contract_fn: &dyn Fn(DepsMut, Env, IbcChannel) -> Result<(), E>, env_ptr: *mut Region, msg_ptr: *mut Region, -) -> ContractResult +) -> ContractResult<()> where E: ToString, { @@ -60,10 +60,7 @@ where let msg: IbcChannel = try_into_contract_result!(from_slice(&msg)); let mut deps = make_dependencies(); - match contract_fn(deps.as_mut(), env, msg) { - Ok(_) => ContractResult::Ok(true), - Err(e) => ContractResult::Err(e.to_string()), - } + contract_fn(deps.as_mut(), env, msg).into() } /// do_ibc_channel_connect is designed for use with #[entry_point] to make a "C" extern From c8b38ca00bff5a4f5d93dc5d27f12908803a5a45 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Jan 2021 17:28:52 +0100 Subject: [PATCH 14/14] Updated IbcOrder serde and serde-wasm-json --- Cargo.lock | 4 ++-- contracts/burner/Cargo.lock | 4 ++-- contracts/hackatom/Cargo.lock | 4 ++-- contracts/queue/Cargo.lock | 4 ++-- contracts/reflect/Cargo.lock | 4 ++-- contracts/staking/Cargo.lock | 4 ++-- packages/std/Cargo.toml | 2 +- packages/std/src/ibc.rs | 7 +++++-- 8 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 51e9d040f6..32a6a42d9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1071,9 +1071,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7294d94d390f1d2334697c065ea591d7074c676e2d20aa6f1df752fced29823f" +checksum = "0584333eb679085166085b536f2aa378297647618c99f27fd9e9066e9b80c752" dependencies = [ "serde", ] diff --git a/contracts/burner/Cargo.lock b/contracts/burner/Cargo.lock index e25cce5cc6..56e3864e5d 100644 --- a/contracts/burner/Cargo.lock +++ b/contracts/burner/Cargo.lock @@ -857,9 +857,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7294d94d390f1d2334697c065ea591d7074c676e2d20aa6f1df752fced29823f" +checksum = "0584333eb679085166085b536f2aa378297647618c99f27fd9e9066e9b80c752" dependencies = [ "serde", ] diff --git a/contracts/hackatom/Cargo.lock b/contracts/hackatom/Cargo.lock index fd391b2fb1..a3d787230e 100644 --- a/contracts/hackatom/Cargo.lock +++ b/contracts/hackatom/Cargo.lock @@ -868,9 +868,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7294d94d390f1d2334697c065ea591d7074c676e2d20aa6f1df752fced29823f" +checksum = "0584333eb679085166085b536f2aa378297647618c99f27fd9e9066e9b80c752" dependencies = [ "serde", ] diff --git a/contracts/queue/Cargo.lock b/contracts/queue/Cargo.lock index a29f189e61..bf6e57e8f1 100644 --- a/contracts/queue/Cargo.lock +++ b/contracts/queue/Cargo.lock @@ -857,9 +857,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7294d94d390f1d2334697c065ea591d7074c676e2d20aa6f1df752fced29823f" +checksum = "0584333eb679085166085b536f2aa378297647618c99f27fd9e9066e9b80c752" dependencies = [ "serde", ] diff --git a/contracts/reflect/Cargo.lock b/contracts/reflect/Cargo.lock index e21612f855..8f970b364e 100644 --- a/contracts/reflect/Cargo.lock +++ b/contracts/reflect/Cargo.lock @@ -867,9 +867,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7294d94d390f1d2334697c065ea591d7074c676e2d20aa6f1df752fced29823f" +checksum = "0584333eb679085166085b536f2aa378297647618c99f27fd9e9066e9b80c752" dependencies = [ "serde", ] diff --git a/contracts/staking/Cargo.lock b/contracts/staking/Cargo.lock index 80bb1bff58..261f69d009 100644 --- a/contracts/staking/Cargo.lock +++ b/contracts/staking/Cargo.lock @@ -860,9 +860,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7294d94d390f1d2334697c065ea591d7074c676e2d20aa6f1df752fced29823f" +checksum = "0584333eb679085166085b536f2aa378297647618c99f27fd9e9066e9b80c752" dependencies = [ "serde", ] diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 55935699a4..c588fc8008 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -34,7 +34,7 @@ stargate = [] [dependencies] base64 = "0.13.0" cosmwasm-derive = { path = "../derive", version = "0.13.1" } -serde-json-wasm = { version = "0.2.1" } +serde-json-wasm = { version = "0.2.2" } schemars = "0.7" serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } thiserror = "1.0" diff --git a/packages/std/src/ibc.rs b/packages/std/src/ibc.rs index 8112d72e76..c150cdae2d 100644 --- a/packages/std/src/ibc.rs +++ b/packages/std/src/ibc.rs @@ -110,10 +110,13 @@ pub struct IbcChannel { // TODO: check what representation we want here for encoding - string or number /// IbcOrder defines if a channel is ORDERED or UNORDERED /// Values come from https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/core/channel/v1/channel.proto#L69-L80 +/// Naming comes from the protobuf files and go translations. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub enum IbcOrder { - Unordered = 1, - Ordered = 2, + #[serde(rename = "ORDER_UNORDERED")] + Unordered, + #[serde(rename = "ORDER_ORDERED")] + Ordered, } // IBCTimeoutHeight Height is a monotonically increasing data type