diff --git a/Cargo.lock b/Cargo.lock index 78317fcf42..2b050e6e9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6128,8 +6128,10 @@ name = "ibc-union" version = "1.0.0" dependencies = [ "alloy", + "cosmwasm-schema 2.1.4", "cosmwasm-std 2.1.4", "cw-storage-plus 2.0.0", + "ethabi", "hex", "ibc-solidity", "ibc-union-msg", diff --git a/cosmwasm/ibc-union/core/Cargo.toml b/cosmwasm/ibc-union/core/Cargo.toml index d058278053..21caa9ecdd 100644 --- a/cosmwasm/ibc-union/core/Cargo.toml +++ b/cosmwasm/ibc-union/core/Cargo.toml @@ -17,8 +17,10 @@ library = [] [dependencies] alloy = { workspace = true, features = ["sol-types"] } +cosmwasm-schema = { workspace = true } cosmwasm-std = { workspace = true, features = ["abort"] } cw-storage-plus = { workspace = true } +ethabi = { workspace = true } hex = { workspace = true } ibc-solidity = { workspace = true, features = ["serde"] } ibc-union-msg = { workspace = true } diff --git a/cosmwasm/ibc-union/core/msg/src/lightclient.rs b/cosmwasm/ibc-union/core/msg/src/lightclient.rs index 806424455d..645e527f5b 100644 --- a/cosmwasm/ibc-union/core/msg/src/lightclient.rs +++ b/cosmwasm/ibc-union/core/msg/src/lightclient.rs @@ -22,14 +22,14 @@ pub struct MisbehaviourResponse { pub client_state: Bytes, } -#[derive(serde::Serialize, serde::Deserialize)] +#[derive(serde::Serialize, serde::Deserialize, Debug)] #[serde(deny_unknown_fields, rename_all = "snake_case")] pub struct VerifyCreationResponse { pub latest_height: u64, pub counterparty_chain_id: String, } -#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Debug, serde::Serialize, serde::Deserialize)] #[serde(deny_unknown_fields, rename_all = "snake_case")] pub enum QueryMsg { GetTimestamp { diff --git a/cosmwasm/ibc-union/core/src/lib.rs b/cosmwasm/ibc-union/core/src/lib.rs index b51210bf2f..2c95cd4ac7 100644 --- a/cosmwasm/ibc-union/core/src/lib.rs +++ b/cosmwasm/ibc-union/core/src/lib.rs @@ -3,6 +3,9 @@ pub mod contract; pub mod state; +#[cfg(test)] +mod tests; + use cosmwasm_std::{Addr, StdError}; use ibc_solidity::{ChannelState, ConnectionState}; use thiserror::Error; @@ -124,19 +127,3 @@ impl ContractErrorKind { err.strip_prefix("IBC_UNION_ERR_")?.parse().ok() } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn display() { - assert_eq!( - ContractErrorKind::ArithmeticOverflow, - ContractErrorKind::parse_from_error_message( - &ContractError::ArithmeticOverflow.to_string() - ) - .unwrap() - ) - } -} diff --git a/cosmwasm/ibc-union/core/src/tests.rs b/cosmwasm/ibc-union/core/src/tests.rs new file mode 100644 index 0000000000..1ef4f8a5a8 --- /dev/null +++ b/cosmwasm/ibc-union/core/src/tests.rs @@ -0,0 +1,143 @@ +use contract::execute; +use cosmwasm_std::{ + from_json, + testing::{message_info, mock_env, MockApi}, + Addr, Binary, DepsMut, QuerierResult, Response, StdResult, WasmQuery, +}; +use ibc_union_msg::{ + lightclient::QueryMsg as LightClientQueryMsg, + msg::{ + ExecuteMsg, MsgChannelOpenInit, MsgConnectionOpenConfirm, MsgConnectionOpenInit, + MsgConnectionOpenTry, MsgCreateClient, MsgRegisterClient, + }, +}; + +use super::*; + +mod channel; +mod client; +mod connection; + +const CLIENT_TYPE: &str = "union"; +const CLIENT_ADDRESS: &str = "unionclient"; +const SENDER: &str = "unionsender"; +const RELAYER: &str = "unionrelayer"; +const VERSION: &str = "version"; + +/// Creates a mock address from a given string. +/// Addresses are prefixed with the default [`MockApi`] prefix. +fn mock_addr(address_seed: impl Into) -> Addr { + let mock_api = MockApi::default(); + mock_api.addr_make(&Into::::into(address_seed)) +} + +fn wasm_query_handler StdResult + 'static>( + querier: F, +) -> impl Fn(&WasmQuery) -> QuerierResult + 'static { + move |msg| match msg { + WasmQuery::Smart { msg, .. } => { + let msg: LightClientQueryMsg = from_json(msg).unwrap(); + let res = querier(msg).unwrap(); + QuerierResult::Ok(cosmwasm_std::ContractResult::Ok(res)) + } + _ => panic!("Only smart queries should be possible now. Adjust this based on your needs."), + } +} + +/// Creates a mock client. +/// Uses [`mock_addr`] to convert address seeds to addresses +/// Addresses are prefixed with the default [`MockApi`] prefix. +fn register_client(deps: DepsMut) -> Result { + let register_msg = ExecuteMsg::RegisterClient(MsgRegisterClient { + client_type: CLIENT_TYPE.to_owned(), + client_address: mock_addr(CLIENT_ADDRESS).into_string(), + }); + + let sender = mock_addr(SENDER); + execute(deps, mock_env(), message_info(&sender, &[]), register_msg) +} + +fn create_client(deps: DepsMut) -> Result { + let execute_msg = ExecuteMsg::CreateClient(MsgCreateClient { + client_type: CLIENT_TYPE.to_owned(), + client_state_bytes: vec![1, 2, 3].into(), + consensus_state_bytes: vec![1, 2, 3].into(), + relayer: mock_addr(RELAYER).into_string(), + }); + + let sender = mock_addr(SENDER); + execute(deps, mock_env(), message_info(&sender, &[]), execute_msg) +} + +fn connection_open_init(deps: DepsMut) -> Result { + let msg = MsgConnectionOpenInit { + client_id: 1, + counterparty_client_id: 2, + relayer: mock_addr(RELAYER).into_string(), + }; + execute( + deps, + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ConnectionOpenInit(msg), + ) +} + +fn connection_open_try(deps: DepsMut) -> Result { + let msg = MsgConnectionOpenTry { + counterparty_client_id: 2, + counterparty_connection_id: 1, + client_id: 1, + proof_init: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + + execute( + deps, + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ConnectionOpenTry(msg), + ) +} + +fn connection_open_confirm(deps: DepsMut) -> Result { + let msg = MsgConnectionOpenConfirm { + connection_id: 1, + proof_ack: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + + execute( + deps, + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ConnectionOpenConfirm(msg), + ) +} + +fn channel_open_init(deps: DepsMut) -> Result { + let msg = MsgChannelOpenInit { + port_id: mock_addr(SENDER).to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps, + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) +} + +#[test] +fn display() { + assert_eq!( + ContractErrorKind::ArithmeticOverflow, + ContractErrorKind::parse_from_error_message(&ContractError::ArithmeticOverflow.to_string()) + .unwrap() + ) +} diff --git a/cosmwasm/ibc-union/core/src/tests/channel.rs b/cosmwasm/ibc-union/core/src/tests/channel.rs new file mode 100644 index 0000000000..7d2a3279d2 --- /dev/null +++ b/cosmwasm/ibc-union/core/src/tests/channel.rs @@ -0,0 +1,4 @@ +use super::*; + +mod ibc_channel; +mod ibc_packet; diff --git a/cosmwasm/ibc-union/core/src/tests/channel/ibc_channel.rs b/cosmwasm/ibc-union/core/src/tests/channel/ibc_channel.rs new file mode 100644 index 0000000000..5d2f3e20c1 --- /dev/null +++ b/cosmwasm/ibc-union/core/src/tests/channel/ibc_channel.rs @@ -0,0 +1,702 @@ +use contract::instantiate; +use cosmwasm_std::{testing::mock_dependencies, to_json_binary}; +use ibc_solidity::Channel; +use ibc_union_msg::{ + lightclient::VerifyCreationResponse, + msg::{ + InitMsg, MsgChannelOpenAck, MsgChannelOpenConfirm, MsgChannelOpenInit, MsgChannelOpenTry, + }, +}; + +use super::*; + +const SENDER: &str = "unionsender"; +const RELAYER: &str = "unionrelayer"; +const VERSION: &str = "version"; + +#[test] +fn channel_open_init_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + + let msg = MsgChannelOpenInit { + port_id: mock_addr(SENDER).to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) + .is_ok()); +} + +#[test] +fn channel_open_init_channel_claimed() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + + assert_eq!( + crate::state::CHANNEL_OWNER.load(&deps.storage, 1).unwrap(), + mock_addr(SENDER) + ); +} + +#[test] +fn channel_open_init_commitment_saved() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + + assert_eq!( + crate::state::CHANNELS.load(&deps.storage, 1).unwrap(), + Channel { + state: ChannelState::Init, + connection_id: 1, + counterparty_channel_id: 0, + counterparty_port_id: vec![1].into(), + version: VERSION.to_owned() + } + ); +} + +#[test] +fn channel_open_try_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + + let msg = MsgChannelOpenTry { + port_id: mock_addr(SENDER).into_string(), + channel: Channel { + state: ChannelState::TryOpen, + connection_id: 1, + counterparty_channel_id: 0, + counterparty_port_id: vec![1].into(), + version: VERSION.to_owned(), + }, + counterparty_version: VERSION.to_owned(), + proof_init: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenTry(msg), + ) + .is_ok()) +} +#[test] +fn channel_open_try_invalid_state() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + + let msg = MsgChannelOpenTry { + port_id: mock_addr(SENDER).into_string(), + channel: Channel { + state: ChannelState::Unspecified, + connection_id: 1, + counterparty_channel_id: 0, + counterparty_port_id: vec![1].into(), + version: VERSION.to_owned(), + }, + counterparty_version: VERSION.to_owned(), + proof_init: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenTry(msg), + ) + .is_err_and(|err| { + matches!( + err, + ContractError::ChannelInvalidState { + got: ChannelState::Unspecified, + expected: ChannelState::TryOpen + } + ) + })) +} + +#[test] +fn channel_open_try_channel_claimed() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + + let msg = MsgChannelOpenTry { + port_id: mock_addr(SENDER).into_string(), + channel: Channel { + state: ChannelState::TryOpen, + connection_id: 1, + counterparty_channel_id: 0, + counterparty_port_id: vec![1].into(), + version: VERSION.to_owned(), + }, + counterparty_version: VERSION.to_owned(), + proof_init: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenTry(msg), + ) + .expect("channel open try is ok"); + + assert_eq!( + crate::state::CHANNEL_OWNER.load(&deps.storage, 1).unwrap(), + mock_addr(SENDER) + ); +} + +#[test] +fn channel_open_try_commitment_saved() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + + let msg = MsgChannelOpenTry { + port_id: mock_addr(SENDER).into_string(), + channel: Channel { + state: ChannelState::TryOpen, + connection_id: 1, + counterparty_channel_id: 0, + counterparty_port_id: vec![1].into(), + version: VERSION.to_owned(), + }, + counterparty_version: VERSION.to_owned(), + proof_init: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenTry(msg), + ) + .expect("channel open try is ok"); + + assert_eq!( + crate::state::CHANNELS.load(&deps.storage, 1).unwrap(), + Channel { + state: ChannelState::TryOpen, + connection_id: 1, + counterparty_channel_id: 0, + counterparty_port_id: vec![1].into(), + version: VERSION.to_owned(), + } + ); +} + +#[test] +fn channel_open_ack_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + + let msg = MsgChannelOpenInit { + port_id: mock_addr(SENDER).to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) + .expect("channel open init is ok"); + + let msg = MsgChannelOpenAck { + channel_id: 1, + counterparty_version: VERSION.to_owned(), + counterparty_channel_id: 0, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenAck(msg) + ) + .is_ok()) +} + +#[test] +fn channel_open_ack_not_found() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + + let msg = MsgChannelOpenAck { + channel_id: 1, + counterparty_version: VERSION.to_owned(), + counterparty_channel_id: 0, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenAck(msg) + ) + .is_err_and(|err| { + match err { + ContractError::Std(err) => { + matches!(err, StdError::NotFound { .. }) + } + _ => false, + } + })) +} + +#[test] +fn channel_open_ack_commitment_saved() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + + let msg = MsgChannelOpenInit { + port_id: mock_addr(SENDER).to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) + .expect("channel open init is ok"); + + let msg = MsgChannelOpenAck { + channel_id: 1, + counterparty_version: VERSION.to_owned(), + counterparty_channel_id: 0, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenAck(msg), + ) + .expect("channel open ack is ok"); + + assert_eq!( + crate::state::CHANNELS.load(&deps.storage, 1).unwrap(), + Channel { + state: ChannelState::Open, + connection_id: 1, + counterparty_channel_id: 0, + counterparty_port_id: vec![1].into(), + version: VERSION.to_owned() + } + ); +} + +#[test] +fn channel_open_confirm_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + + let msg = MsgChannelOpenTry { + port_id: mock_addr(SENDER).into_string(), + channel: Channel { + state: ChannelState::TryOpen, + connection_id: 1, + counterparty_channel_id: 0, + counterparty_port_id: vec![1].into(), + version: VERSION.to_owned(), + }, + counterparty_version: VERSION.to_owned(), + proof_init: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenTry(msg), + ) + .expect("channel open try is ok"); + + let msg = MsgChannelOpenConfirm { + channel_id: 1, + proof_ack: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenConfirm(msg), + ) + .is_ok()) +} + +#[test] +fn channel_open_confirm_not_found() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + + let msg = MsgChannelOpenConfirm { + channel_id: 1, + proof_ack: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenConfirm(msg), + ) + .is_err_and(|err| { + match err { + ContractError::Std(err) => { + matches!(err, StdError::NotFound { .. }) + } + _ => false, + } + })) +} + +#[test] +fn channel_open_confirm_commitment_saved() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + + let msg = MsgChannelOpenTry { + port_id: mock_addr(SENDER).into_string(), + channel: Channel { + state: ChannelState::TryOpen, + connection_id: 1, + counterparty_channel_id: 0, + counterparty_port_id: vec![1].into(), + version: VERSION.to_owned(), + }, + counterparty_version: VERSION.to_owned(), + proof_init: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenTry(msg), + ) + .expect("channel open try is ok"); + + let msg = MsgChannelOpenConfirm { + channel_id: 1, + proof_ack: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenConfirm(msg), + ) + .expect("channel open confirm is ok"); + + assert_eq!( + crate::state::CHANNELS.load(&deps.storage, 1).unwrap(), + Channel { + state: ChannelState::Open, + connection_id: 1, + counterparty_channel_id: 0, + counterparty_port_id: vec![1].into(), + version: VERSION.to_owned() + } + ); +} diff --git a/cosmwasm/ibc-union/core/src/tests/channel/ibc_packet.rs b/cosmwasm/ibc-union/core/src/tests/channel/ibc_packet.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/cosmwasm/ibc-union/core/src/tests/channel/ibc_packet.rs @@ -0,0 +1 @@ + diff --git a/cosmwasm/ibc-union/core/src/tests/client.rs b/cosmwasm/ibc-union/core/src/tests/client.rs new file mode 100644 index 0000000000..7a5b3623f4 --- /dev/null +++ b/cosmwasm/ibc-union/core/src/tests/client.rs @@ -0,0 +1,3 @@ +use super::*; + +mod ibc; diff --git a/cosmwasm/ibc-union/core/src/tests/client/cometbls.rs b/cosmwasm/ibc-union/core/src/tests/client/cometbls.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/cosmwasm/ibc-union/core/src/tests/client/cometbls.rs @@ -0,0 +1 @@ + diff --git a/cosmwasm/ibc-union/core/src/tests/client/ibc.rs b/cosmwasm/ibc-union/core/src/tests/client/ibc.rs new file mode 100644 index 0000000000..07dbdade95 --- /dev/null +++ b/cosmwasm/ibc-union/core/src/tests/client/ibc.rs @@ -0,0 +1,322 @@ +use cosmwasm_std::{ + testing::{message_info, mock_dependencies, mock_env}, + to_json_binary, Addr, Event, +}; +use ibc_union_msg::{ + lightclient::{ + QueryMsg as LightClientQueryMsg, VerifyClientMessageUpdate, VerifyCreationResponse, + }, + msg::{ExecuteMsg, InitMsg, MsgUpdateClient}, +}; + +use super::*; +use crate::{ + contract::{events, execute, instantiate}, + ContractError, +}; + +const CLIENT_TYPE: &str = "union"; +const CLIENT_ADDRESS: &str = "unionclient"; +const SENDER: &str = "unionsender"; +const RELAYER: &str = "unionrelayer"; + +fn new_client_registered_event(client_type: &str, client_address: &Addr) -> Event { + Event::new(events::client::REGISTER) + .add_attribute(events::attribute::CLIENT_TYPE, client_type) + .add_attribute(events::attribute::CLIENT_ADDRESS, client_address) +} + +#[test] +fn register_client_ok() { + let mut deps = mock_dependencies(); + let res = register_client(deps.as_mut()).unwrap(); + + assert!(res + .events + .into_iter() + .any(|e| e == new_client_registered_event(CLIENT_TYPE, &mock_addr(CLIENT_ADDRESS)))); + + assert_eq!( + crate::state::CLIENT_REGISTRY + .load(&deps.storage, CLIENT_TYPE) + .unwrap() + .as_str(), + mock_addr(CLIENT_ADDRESS).to_string() + ); +} + +#[test] +fn register_client_fails_when_duplicate() { + let mut deps = mock_dependencies(); + register_client(deps.as_mut()).unwrap(); + assert_eq!( + register_client(deps.as_mut()), + Err(ContractError::ClientTypeAlreadyExists) + ); +} + +#[test] +fn create_client_ok() { + let mut deps = mock_dependencies(); + let sender = mock_addr(SENDER); + + instantiate( + deps.as_mut(), + mock_env(), + message_info(&sender, &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + msg => panic!("should not be called: {:?}", msg), + })); + + register_client(deps.as_mut()).expect("register client ok"); + assert!(create_client(deps.as_mut()).is_ok()) +} + +#[test] +fn create_client_commitments_saved() { + let mut deps = mock_dependencies(); + let sender = mock_addr(SENDER); + + instantiate( + deps.as_mut(), + mock_env(), + message_info(&sender, &[]), + InitMsg {}, + ) + .expect("instantiate ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + msg => panic!("should not be called: {:?}", msg), + })); + + register_client(deps.as_mut()).expect("register client ok"); + let res = create_client(deps.as_mut()).expect("create client ok"); + let client_id: u32 = res + .events + .iter() + .find(|event| event.ty.eq(events::client::CREATE)) + .expect("create client event exists") + .attributes + .iter() + .find(|attribute| attribute.key.eq(events::attribute::CLIENT_ID)) + .expect("client type attribute exists") + .value + .parse() + .expect("client type string is u32"); + + assert_eq!( + crate::state::CLIENT_TYPES + .load(&deps.storage, client_id) + .unwrap(), + CLIENT_TYPE + ); + assert_eq!( + crate::state::CLIENT_IMPLS + .load(&deps.storage, client_id) + .unwrap() + .as_str(), + mock_addr(CLIENT_ADDRESS).to_string() + ); + assert_eq!( + crate::state::CLIENT_STATES + .load(&deps.storage, client_id) + .unwrap(), + vec![1, 2, 3] + ); + assert_eq!( + crate::state::CLIENT_CONSENSUS_STATES + .load(&deps.storage, (client_id, 1)) + .unwrap(), + vec![1, 2, 3] + ); +} + +#[test] +fn update_client_ok() { + let mut deps = mock_dependencies(); + let sender = mock_addr(SENDER); + + instantiate( + deps.as_mut(), + mock_env(), + message_info(&sender, &[]), + InitMsg {}, + ) + .expect("instantiate ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyClientMessage { .. } => { + to_json_binary(&VerifyClientMessageUpdate { + height: 2, + consensus_state: vec![3, 2, 1].into(), + client_state: vec![3, 2, 1].into(), + }) + } + msg => panic!("should not be called: {:?}", msg), + })); + + register_client(deps.as_mut()).expect("register client ok"); + let res = create_client(deps.as_mut()).expect("create client ok"); + let client_id: u32 = res + .events + .iter() + .find(|event| event.ty.eq(events::client::CREATE)) + .expect("create client event exists") + .attributes + .iter() + .find(|attribute| attribute.key.eq(events::attribute::CLIENT_ID)) + .expect("client type attribute exists") + .value + .parse() + .expect("client type string is u32"); + + let msg = ExecuteMsg::UpdateClient(MsgUpdateClient { + client_id, + client_message: vec![3, 2, 1].into(), + relayer: mock_addr(RELAYER).into_string(), + }); + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + msg + ) + .is_ok()) +} + +#[test] +fn update_client_ko() { + let mut deps = mock_dependencies(); + let sender = mock_addr(SENDER); + + instantiate( + deps.as_mut(), + mock_env(), + message_info(&sender, &[]), + InitMsg {}, + ) + .expect("instantiate ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyClientMessage { .. } => to_json_binary(&0), + msg => panic!("should not be called: {:?}", msg), + })); + + register_client(deps.as_mut()).expect("register client ok"); + let res = create_client(deps.as_mut()).expect("create client ok"); + let client_id: u32 = res + .events + .iter() + .find(|event| event.ty.eq(events::client::CREATE)) + .expect("create client event exists") + .attributes + .iter() + .find(|attribute| attribute.key.eq(events::attribute::CLIENT_ID)) + .expect("client type attribute exists") + .value + .parse() + .expect("client type string is u32"); + + let msg = ExecuteMsg::UpdateClient(MsgUpdateClient { + client_id, + client_message: vec![3, 2, 1].into(), + relayer: mock_addr(RELAYER).into_string(), + }); + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + msg + ) + .is_err()) +} + +#[test] +fn update_client_commitments_saved() { + let mut deps = mock_dependencies(); + let sender = mock_addr(SENDER); + + instantiate( + deps.as_mut(), + mock_env(), + message_info(&sender, &[]), + InitMsg {}, + ) + .expect("instantiate ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyClientMessage { .. } => { + to_json_binary(&VerifyClientMessageUpdate { + height: 2, + consensus_state: vec![3, 2, 1].into(), + client_state: vec![3, 2, 1].into(), + }) + } + msg => panic!("should not be called: {:?}", msg), + })); + + register_client(deps.as_mut()).expect("register client ok"); + let res = create_client(deps.as_mut()).expect("create client ok"); + let client_id: u32 = res + .events + .iter() + .find(|event| event.ty.eq(events::client::CREATE)) + .expect("create client event exists") + .attributes + .iter() + .find(|attribute| attribute.key.eq(events::attribute::CLIENT_ID)) + .expect("client type attribute exists") + .value + .parse() + .expect("client type string is u32"); + + let msg = ExecuteMsg::UpdateClient(MsgUpdateClient { + client_id, + client_message: vec![3, 2, 1].into(), + relayer: mock_addr(RELAYER).into_string(), + }); + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + msg, + ) + .expect("update client ok"); + + assert_eq!( + crate::state::CLIENT_STATES + .load(&deps.storage, client_id) + .unwrap(), + vec![3, 2, 1] + ); + assert_eq!( + crate::state::CLIENT_CONSENSUS_STATES + .load(&deps.storage, (client_id, 2)) + .unwrap(), + vec![3, 2, 1] + ); +} diff --git a/cosmwasm/ibc-union/core/src/tests/connection.rs b/cosmwasm/ibc-union/core/src/tests/connection.rs new file mode 100644 index 0000000000..7a5b3623f4 --- /dev/null +++ b/cosmwasm/ibc-union/core/src/tests/connection.rs @@ -0,0 +1,3 @@ +use super::*; + +mod ibc; diff --git a/cosmwasm/ibc-union/core/src/tests/connection/ibc.rs b/cosmwasm/ibc-union/core/src/tests/connection/ibc.rs new file mode 100644 index 0000000000..00773dc051 --- /dev/null +++ b/cosmwasm/ibc-union/core/src/tests/connection/ibc.rs @@ -0,0 +1,394 @@ +use contract::instantiate; +use cosmwasm_std::{testing::mock_dependencies, to_json_binary}; +use ibc_solidity::Connection; +use ibc_union_msg::{ + lightclient::VerifyCreationResponse, + msg::{ + ExecuteMsg, InitMsg, MsgConnectionOpenAck, MsgConnectionOpenConfirm, MsgConnectionOpenInit, + MsgConnectionOpenTry, + }, +}; + +use super::*; + +#[test] +fn connection_open_init_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + let msg = MsgConnectionOpenInit { + client_id: 1, + counterparty_client_id: 2, + relayer: mock_addr(RELAYER).into_string(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ConnectionOpenInit(msg), + ) + .is_ok()) +} + +#[test] +fn connection_open_init_commitment_saved() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + connection_open_init(deps.as_mut()).expect("open connection init is ok"); + + assert_eq!( + crate::state::CONNECTIONS.load(&deps.storage, 1).unwrap(), + Connection { + state: ConnectionState::Init, + client_id: 1, + counterparty_client_id: 2, + counterparty_connection_id: 0 + } + ); +} + +#[test] +fn connection_open_try_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + let msg = MsgConnectionOpenTry { + counterparty_client_id: 2, + counterparty_connection_id: 1, + client_id: 1, + proof_init: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ConnectionOpenTry(msg), + ) + .is_ok()); +} + +#[test] +fn connection_open_try_client_not_found() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + + let msg = MsgConnectionOpenTry { + counterparty_client_id: 2, + counterparty_connection_id: 1, + client_id: 1, + proof_init: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ConnectionOpenTry(msg), + ) + .is_err_and(|err| { + match err { + ContractError::Std(err) => matches!(err, StdError::NotFound { .. }), + _ => false, + } + })); +} + +// #[test] +// fn connection_open_try_invalid_proof() { +// todo!() +// } + +#[test] +fn connection_open_try_commitment_saved() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + + let msg = MsgConnectionOpenTry { + counterparty_client_id: 2, + counterparty_connection_id: 1, + client_id: 1, + proof_init: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ConnectionOpenTry(msg), + ) + .expect("connection open try is ok"); + + assert_eq!( + crate::state::CONNECTIONS.load(&deps.storage, 1).unwrap(), + Connection { + state: ConnectionState::TryOpen, + client_id: 1, + counterparty_client_id: 2, + counterparty_connection_id: 1 + } + ); +} + +#[test] +fn connection_open_ack_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + connection_open_init(deps.as_mut()).expect("connection open init is ok"); + + let msg = MsgConnectionOpenAck { + connection_id: 1, + counterparty_connection_id: 1, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + + assert!(dbg!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ConnectionOpenAck(msg), + )) + .is_ok()) +} + +// #[test] +// fn connection_open_ack_invalid_proof() { +// todo!() +// } + +#[test] +fn connection_open_ack_commitment_saved() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + connection_open_init(deps.as_mut()).expect("connection open init is ok"); + + let msg = MsgConnectionOpenAck { + connection_id: 1, + counterparty_connection_id: 1, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ConnectionOpenAck(msg), + ) + .expect("connection open ack is ok"); + + assert_eq!( + crate::state::CONNECTIONS.load(&deps.storage, 1).unwrap(), + Connection { + state: ConnectionState::Open, + client_id: 1, + counterparty_client_id: 2, + counterparty_connection_id: 1 + } + ); +} + +#[test] +fn connection_open_confirm_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + + let msg = MsgConnectionOpenConfirm { + connection_id: 1, + proof_ack: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ConnectionOpenConfirm(msg), + ) + .is_ok()); +} + +// #[test] +// fn connection_open_confirm_invalid_proof() { +// todo!() +// } + +#[test] +fn connection_open_try_confirm_commitment_saved() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .unwrap(); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&VerifyCreationResponse { + latest_height: 1, + counterparty_chain_id: "testchain".to_owned(), + }), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + + assert_eq!( + crate::state::CONNECTIONS.load(&deps.storage, 1).unwrap(), + Connection { + state: ConnectionState::Open, + client_id: 1, + counterparty_client_id: 2, + counterparty_connection_id: 1 + } + ); +} diff --git a/cosmwasm/union-ibc/core/src/tests/channel/ibc_packet.rs b/cosmwasm/union-ibc/core/src/tests/channel/ibc_packet.rs new file mode 100644 index 0000000000..1a8c6cff34 --- /dev/null +++ b/cosmwasm/union-ibc/core/src/tests/channel/ibc_packet.rs @@ -0,0 +1,2068 @@ +use contract::instantiate; +use cosmwasm_std::{testing::mock_dependencies, to_json_binary}; +use ibc_solidity::Packet; +use ibc_union_msg::msg::{ + InitMsg, MsgBatchAcks, MsgBatchSend, MsgIntentPacketRecv, MsgPacketAcknowledgement, + MsgPacketRecv, MsgPacketTimeout, MsgSendPacket, MsgWriteAcknowledgement, +}; +use ibc_union_spec::COMMITMENT_MAGIC; + +use super::*; + +#[test] +fn send_packet_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + + let msg = MsgSendPacket { + source_channel: 1, + timeout_height: 10, + timeout_timestamp: 1000000, + data: vec![0, 1, 2].into(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketSend(msg) + ) + .is_ok()) +} + +#[test] +fn send_packet_missing_timeout() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + + let msg = MsgSendPacket { + source_channel: 1, + timeout_height: 0, + timeout_timestamp: 0, + data: vec![0, 1, 2].into(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketSend(msg), + ) + .is_err_and(|err| { matches!(err, ContractError::TimeoutMustBeSet) })) +} + +#[test] +fn send_packet_channel_does_not_exist() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + + let msg = MsgSendPacket { + source_channel: 3, + timeout_height: 10, + timeout_timestamp: 1000000, + data: vec![0, 1, 2].into(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketSend(msg), + ) + .is_err_and(|err| { + match err { + ContractError::Std(err) => matches!(err, StdError::NotFound { .. }), + _ => false, + } + })) +} + +#[test] +fn send_packet_module_is_not_channel_owner() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + + let msg = MsgSendPacket { + source_channel: 1, + timeout_height: 10, + timeout_timestamp: 1000000, + data: vec![0, 1, 2].into(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr("not module"), &[]), + ExecuteMsg::PacketSend(msg), + ) + .is_err_and(|err| { matches!(err, ContractError::Unauthorized { .. }) })) +} + +#[test] +fn recv_packet_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + + let msg = MsgPacketRecv { + packets: vec![Packet { + source_channel: 2, + destination_channel: 1, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + }], + relayer_msgs: vec![vec![1].into()], + relayer: mock_addr(RELAYER).to_string(), + proof: vec![1, 2, 3].into(), + proof_height: 1, + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketRecv(msg), + ) + .is_ok()) +} + +#[test] +fn recv_packet_invalid_channel_state() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + + let msg = MsgPacketRecv { + packets: vec![Packet { + source_channel: 2, + destination_channel: 5, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + }], + relayer_msgs: vec![vec![1].into()], + relayer: mock_addr(RELAYER).to_string(), + proof: vec![1, 2, 3].into(), + proof_height: 1, + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketRecv(msg), + ) + .is_err_and(|err| { + match err { + ContractError::Std(err) => { + matches!(err, StdError::NotFound { .. }) + } + _ => false, + } + })) +} + +#[test] +fn recv_packet_timeout_timestamp() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + + let msg = MsgPacketRecv { + packets: vec![Packet { + source_channel: 2, + destination_channel: 1, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 100, + }], + relayer_msgs: vec![vec![1].into()], + relayer: mock_addr(RELAYER).to_string(), + proof: vec![1, 2, 3].into(), + proof_height: 1, + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketRecv(msg), + ) + .is_err_and(|err| { matches!(err, ContractError::ReceivedTimedOutPacketTimestamp { .. }) })) +} + +#[test] +fn recv_packet_timeout_height() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + + let msg = MsgPacketRecv { + packets: vec![Packet { + source_channel: 2, + destination_channel: 1, + data: vec![1, 2, 3].into(), + timeout_height: 1, + timeout_timestamp: 2000000000000000000, + }], + relayer_msgs: vec![vec![1].into()], + relayer: mock_addr(RELAYER).to_string(), + proof: vec![1, 2, 3].into(), + proof_height: 1, + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketRecv(msg), + ) + .is_err_and(|err| { matches!(err, ContractError::ReceivedTimedOutPacketHeight { .. }) })) +} + +#[test] +fn recv_intent_packet_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + + let msg = MsgIntentPacketRecv { + packets: vec![Packet { + source_channel: 2, + destination_channel: 1, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + }], + market_maker_msgs: vec![vec![1, 2, 3].into()], + market_maker: mock_addr("marketmaker").into_string(), + empty_proof: vec![].into(), + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::IntentPacketRecv(msg) + ) + .is_ok()) +} + +#[test] +fn recv_intent_packet_timeout_timestamp() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + + let msg = MsgIntentPacketRecv { + packets: vec![Packet { + source_channel: 2, + destination_channel: 1, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 100, + }], + market_maker_msgs: vec![vec![1, 2, 3].into()], + market_maker: mock_addr("marketmaker").into_string(), + empty_proof: vec![].into(), + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::IntentPacketRecv(msg), + ) + .is_err_and(|err| { matches!(err, ContractError::ReceivedTimedOutPacketTimestamp { .. }) })) +} + +#[test] +fn recv_intent_packet_timeout_height() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + + let msg = MsgIntentPacketRecv { + packets: vec![Packet { + source_channel: 2, + destination_channel: 1, + data: vec![1, 2, 3].into(), + timeout_height: 1, + timeout_timestamp: 2000000000000000000, + }], + market_maker_msgs: vec![vec![1, 2, 3].into()], + market_maker: mock_addr("marketmaker").into_string(), + empty_proof: vec![].into(), + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::IntentPacketRecv(msg), + ) + .is_err_and(|err| { matches!(err, ContractError::ReceivedTimedOutPacketHeight { .. }) })) +} + +#[test] +fn acknowledge_packet_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + let msg = MsgChannelOpenInit { + port_id: mock_addr(SENDER).to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) + .expect("channel open init is okay"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + let msg = MsgChannelOpenAck { + channel_id: 2, + counterparty_version: VERSION.to_owned(), + counterparty_channel_id: 0, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenAck(msg), + ) + .expect("channel open ack is ok"); + + let msg = MsgSendPacket { + source_channel: 1, + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + data: vec![1, 2, 3].into(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketSend(msg), + ) + .expect("send packet ok"); + + let msg = MsgPacketAcknowledgement { + packets: vec![Packet { + source_channel: 1, + destination_channel: 0, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + }], + acknowledgements: vec![vec![1, 2, 3].into()], + proof: vec![1].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketAck(msg) + ) + .is_ok()) +} + +#[test] +fn acknowledge_packet_tampered() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + let msg = MsgChannelOpenInit { + port_id: mock_addr(SENDER).to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) + .expect("channel open init is okay"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + let msg = MsgChannelOpenAck { + channel_id: 2, + counterparty_version: VERSION.to_owned(), + counterparty_channel_id: 0, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenAck(msg), + ) + .expect("channel open ack is ok"); + + let msg = MsgSendPacket { + source_channel: 1, + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + data: vec![1, 2, 3].into(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketSend(msg), + ) + .expect("send packet ok"); + + let msg = MsgPacketAcknowledgement { + packets: vec![Packet { + source_channel: 1, + destination_channel: 0, + data: vec![4, 1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + }], + acknowledgements: vec![vec![1, 2, 3].into()], + proof: vec![1].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketAck(msg) + ) + .is_err_and(|err| matches!(err, ContractError::PacketCommitmentNotFound))) +} + +#[test] +fn acknowledge_packet_not_sent() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + let msg = MsgChannelOpenInit { + port_id: mock_addr(SENDER).to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) + .expect("channel open init is okay"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + let msg = MsgChannelOpenAck { + channel_id: 2, + counterparty_version: VERSION.to_owned(), + counterparty_channel_id: 0, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenAck(msg), + ) + .expect("channel open ack is ok"); + + let msg = MsgPacketAcknowledgement { + packets: vec![Packet { + source_channel: 1, + destination_channel: 0, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + }], + acknowledgements: vec![vec![1, 2, 3].into()], + proof: vec![1].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).into_string(), + }; + + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketAck(msg) + ) + .is_err_and(|err| matches!(err, ContractError::PacketCommitmentNotFound))) +} + +#[test] +fn timeout_packet_timestamp_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::VerifyNonMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::GetTimestamp { .. } => to_json_binary(&100000), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + + let msg = MsgSendPacket { + source_channel: 1, + timeout_height: 10, + timeout_timestamp: 100, + data: vec![1, 2, 3].into(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketSend(msg), + ) + .expect("send packet ok"); + + let msg = MsgPacketTimeout { + packet: Packet { + source_channel: 1, + destination_channel: 0, + data: vec![1, 2, 3].into(), + timeout_height: 10, + timeout_timestamp: 100, + }, + proof: vec![1].into(), + proof_height: 11, + relayer: mock_addr(RELAYER).into_string(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketTimeout(msg) + ) + .is_ok()) +} + +#[test] +fn timeout_packet_timestamp_timestamp_not_reached() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::VerifyNonMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::GetTimestamp { .. } => to_json_binary(&100000), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + + let msg = MsgSendPacket { + source_channel: 1, + timeout_height: 10, + timeout_timestamp: 200000, + data: vec![1, 2, 3].into(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketSend(msg), + ) + .expect("send packet ok"); + + let msg = MsgPacketTimeout { + packet: Packet { + source_channel: 1, + destination_channel: 0, + data: vec![1, 2, 3].into(), + timeout_height: 10, + timeout_timestamp: 200000, + }, + proof: vec![1].into(), + proof_height: 11, + relayer: mock_addr(RELAYER).into_string(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketTimeout(msg) + ) + .is_err_and(|err| { matches!(err, ContractError::TimeoutTimestampNotReached) })) +} + +#[test] +fn timeout_packet_height_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::VerifyNonMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::GetTimestamp { .. } => to_json_binary(&100000), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + + let msg = MsgSendPacket { + source_channel: 1, + timeout_height: 10, + timeout_timestamp: 0, + data: vec![1, 2, 3].into(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketSend(msg), + ) + .expect("send packet ok"); + + let msg = MsgPacketTimeout { + packet: Packet { + source_channel: 1, + destination_channel: 0, + data: vec![1, 2, 3].into(), + timeout_height: 10, + timeout_timestamp: 0, + }, + proof: vec![1].into(), + proof_height: 11, + relayer: mock_addr(RELAYER).into_string(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketTimeout(msg) + ) + .is_ok()) +} + +#[test] +fn timeout_packet_height_not_reached() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::VerifyNonMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::GetTimestamp { .. } => to_json_binary(&100000), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + + let msg = MsgSendPacket { + source_channel: 1, + timeout_height: 10, + timeout_timestamp: 0, + data: vec![1, 2, 3].into(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketSend(msg), + ) + .expect("send packet ok"); + + let msg = MsgPacketTimeout { + packet: Packet { + source_channel: 1, + destination_channel: 0, + data: vec![1, 2, 3].into(), + timeout_height: 10, + timeout_timestamp: 0, + }, + proof: vec![1].into(), + proof_height: 9, + relayer: mock_addr(RELAYER).into_string(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketTimeout(msg) + ) + .is_err_and(|err| { matches!(err, ContractError::TimeoutHeightNotReached) })) +} + +#[test] +fn write_acknowledgement_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::VerifyNonMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::GetTimestamp { .. } => to_json_binary(&100000), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + let msg = MsgChannelOpenInit { + port_id: mock_addr(SENDER).to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) + .expect("channel open init is okay"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + let msg = MsgChannelOpenAck { + channel_id: 2, + counterparty_version: VERSION.to_owned(), + counterparty_channel_id: 0, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenAck(msg), + ) + .expect("channel open ack is ok"); + + let msg = MsgPacketRecv { + packets: vec![Packet { + source_channel: 1, + destination_channel: 2, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + }], + relayer_msgs: vec![vec![1].into()], + relayer: mock_addr(RELAYER).to_string(), + proof: vec![1, 2, 3].into(), + proof_height: 1, + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketRecv(msg), + ) + .expect("recv packet ok"); + + let msg = MsgWriteAcknowledgement { + channel_id: 2, + packet: Packet { + source_channel: 1, + destination_channel: 2, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + }, + acknowledgement: vec![1].into(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::WriteAcknowledgement(msg), + ) + .is_ok()) +} + +#[test] +fn write_acknowledgement_module_is_not_channel_owner() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::VerifyNonMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::GetTimestamp { .. } => to_json_binary(&100000), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + let msg = MsgChannelOpenInit { + port_id: mock_addr("malicious").to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr("malicious"), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) + .expect("channel open init is okay"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + let msg = MsgChannelOpenAck { + channel_id: 2, + counterparty_version: VERSION.to_owned(), + counterparty_channel_id: 0, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr("malicious"), &[]), + ExecuteMsg::ChannelOpenAck(msg), + ) + .expect("channel open ack is ok"); + + let msg = MsgPacketRecv { + packets: vec![Packet { + source_channel: 1, + destination_channel: 2, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + }], + relayer_msgs: vec![vec![1].into()], + relayer: mock_addr(RELAYER).to_string(), + proof: vec![1, 2, 3].into(), + proof_height: 1, + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketRecv(msg), + ) + .expect("recv packet ok"); + + let msg = MsgWriteAcknowledgement { + channel_id: 2, + packet: Packet { + source_channel: 1, + destination_channel: 2, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + }, + acknowledgement: vec![1].into(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::WriteAcknowledgement(msg), + ) + .is_err_and(|err| { matches!(err, ContractError::Unauthorized { .. }) })) +} + +#[test] +fn write_acknowledgement_packet_not_received() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::VerifyNonMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::GetTimestamp { .. } => to_json_binary(&100000), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + let msg = MsgChannelOpenInit { + port_id: mock_addr(SENDER).to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) + .expect("channel open init is okay"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + let msg = MsgChannelOpenAck { + channel_id: 2, + counterparty_version: VERSION.to_owned(), + counterparty_channel_id: 0, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenAck(msg), + ) + .expect("channel open ack is ok"); + + let msg = MsgWriteAcknowledgement { + channel_id: 2, + packet: Packet { + source_channel: 1, + destination_channel: 2, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + }, + acknowledgement: vec![1].into(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::WriteAcknowledgement(msg), + ) + .is_err_and(|err| { matches!(err, ContractError::PacketNotReceived) })) +} + +#[test] +fn write_acknowledgement_already_exists() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::VerifyNonMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::GetTimestamp { .. } => to_json_binary(&100000), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + let msg = MsgChannelOpenInit { + port_id: mock_addr(SENDER).to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) + .expect("channel open init is okay"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + let msg = MsgChannelOpenAck { + channel_id: 2, + counterparty_version: VERSION.to_owned(), + counterparty_channel_id: 0, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenAck(msg), + ) + .expect("channel open ack is ok"); + + let msg = MsgPacketRecv { + packets: vec![Packet { + source_channel: 1, + destination_channel: 2, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + }], + relayer_msgs: vec![vec![1].into()], + relayer: mock_addr(RELAYER).to_string(), + proof: vec![1, 2, 3].into(), + proof_height: 1, + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketRecv(msg), + ) + .expect("recv packet ok"); + + let msg = MsgWriteAcknowledgement { + channel_id: 2, + packet: Packet { + source_channel: 1, + destination_channel: 2, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + }, + acknowledgement: vec![1].into(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::WriteAcknowledgement(msg), + ) + .is_ok()); + let msg = MsgWriteAcknowledgement { + channel_id: 2, + packet: Packet { + source_channel: 1, + destination_channel: 2, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 2000000000000000000, + }, + acknowledgement: vec![1].into(), + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::WriteAcknowledgement(msg), + ) + .is_err_and(|err| { matches!(err, ContractError::AlreadyAcknowledged) })) +} + +#[test] +fn batch_send_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::VerifyNonMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::GetTimestamp { .. } => to_json_binary(&100000), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + let msg = MsgChannelOpenInit { + port_id: mock_addr(SENDER).to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) + .expect("channel open init is okay"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + let msg = MsgChannelOpenAck { + channel_id: 2, + counterparty_version: VERSION.to_owned(), + counterparty_channel_id: 0, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenAck(msg), + ) + .expect("channel open ack is ok"); + + let msg = MsgSendPacket { + source_channel: 2, + timeout_height: 10, + timeout_timestamp: 0, + data: vec![1, 2, 3].into(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketSend(msg), + ) + .expect("send packet is ok"); + let msg = MsgSendPacket { + source_channel: 2, + timeout_height: 10, + timeout_timestamp: 0, + data: vec![4, 5, 6].into(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketSend(msg), + ) + .expect("send packet is ok"); + + let msg = MsgBatchSend { + source_channel: 2, + packets: vec![ + Packet { + source_channel: 2, + destination_channel: 0, + data: vec![4, 5, 6].into(), + timeout_height: 10, + timeout_timestamp: 0, + }, + Packet { + source_channel: 2, + destination_channel: 0, + data: vec![1, 2, 3].into(), + timeout_height: 10, + timeout_timestamp: 0, + }, + ], + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::BatchSend(msg) + ) + .is_ok()) +} + +#[test] +fn batch_send_packet_not_sent() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::VerifyNonMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::GetTimestamp { .. } => to_json_binary(&100000), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + let msg = MsgChannelOpenInit { + port_id: mock_addr(SENDER).to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) + .expect("channel open init is okay"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + let msg = MsgChannelOpenAck { + channel_id: 2, + counterparty_version: VERSION.to_owned(), + counterparty_channel_id: 0, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenAck(msg), + ) + .expect("channel open ack is ok"); + + let msg = MsgBatchSend { + source_channel: 2, + packets: vec![ + Packet { + source_channel: 2, + destination_channel: 0, + data: vec![4, 5, 6].into(), + timeout_height: 10, + timeout_timestamp: 0, + }, + Packet { + source_channel: 2, + destination_channel: 0, + data: vec![1, 2, 3].into(), + timeout_height: 10, + timeout_timestamp: 0, + }, + ], + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::BatchSend(msg) + ) + .is_err_and(|err| { matches!(err, ContractError::PacketCommitmentNotFound) })) +} + +#[test] +fn batch_acks_ok() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::VerifyNonMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::GetTimestamp { .. } => to_json_binary(&100000), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + let msg = MsgChannelOpenInit { + port_id: mock_addr(SENDER).to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) + .expect("channel open init is okay"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + let msg = MsgChannelOpenAck { + channel_id: 2, + counterparty_version: VERSION.to_owned(), + counterparty_channel_id: 0, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenAck(msg), + ) + .expect("channel open ack is ok"); + + let msg = MsgPacketRecv { + packets: vec![Packet { + source_channel: 0, + destination_channel: 2, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 0, + }], + relayer_msgs: vec![vec![1].into()], + relayer: mock_addr(RELAYER).to_string(), + proof: vec![1, 2, 3].into(), + proof_height: 1, + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketRecv(msg), + ) + .expect("recv packet ok"); + let msg = MsgWriteAcknowledgement { + channel_id: 2, + packet: Packet { + source_channel: 0, + destination_channel: 2, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 0, + }, + acknowledgement: vec![1].into(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::WriteAcknowledgement(msg), + ) + .expect("write ack is ok"); + let msg = MsgPacketRecv { + packets: vec![Packet { + source_channel: 0, + destination_channel: 2, + data: vec![3, 4, 5].into(), + timeout_height: 100000, + timeout_timestamp: 0, + }], + relayer_msgs: vec![vec![1].into()], + relayer: mock_addr(RELAYER).to_string(), + proof: vec![1, 2, 3].into(), + proof_height: 1, + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketRecv(msg), + ) + .expect("recv packet ok"); + let msg = MsgWriteAcknowledgement { + channel_id: 2, + packet: Packet { + source_channel: 0, + destination_channel: 2, + data: vec![3, 4, 5].into(), + timeout_height: 100000, + timeout_timestamp: 0, + }, + acknowledgement: vec![1].into(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::WriteAcknowledgement(msg), + ) + .expect("write ack is ok"); + + let msg = MsgBatchAcks { + source_channel: 2, + packets: vec![ + Packet { + source_channel: 0, + destination_channel: 2, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 0, + }, + Packet { + source_channel: 0, + destination_channel: 2, + data: vec![3, 4, 5].into(), + timeout_height: 100000, + timeout_timestamp: 0, + }, + ], + acks: vec![vec![1].into(), vec![1].into()], + }; + assert!(dbg!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::BatchAcks(msg) + )) + .is_ok()) +} + +#[test] +fn batch_acks_packet_not_received() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::VerifyNonMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::GetTimestamp { .. } => to_json_binary(&100000), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + let msg = MsgChannelOpenInit { + port_id: mock_addr(SENDER).to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) + .expect("channel open init is okay"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + let msg = MsgChannelOpenAck { + channel_id: 2, + counterparty_version: VERSION.to_owned(), + counterparty_channel_id: 0, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenAck(msg), + ) + .expect("channel open ack is ok"); + + let msg = MsgBatchAcks { + source_channel: 2, + packets: vec![ + Packet { + source_channel: 0, + destination_channel: 2, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 0, + }, + Packet { + source_channel: 0, + destination_channel: 2, + data: vec![3, 4, 5].into(), + timeout_height: 100000, + timeout_timestamp: 0, + }, + ], + acks: vec![vec![1].into(), vec![1].into()], + }; + assert!(dbg!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::BatchAcks(msg) + )) + .is_err_and(|err| { matches!(err, ContractError::PacketCommitmentNotFound) })) +} + +#[test] +fn batch_acks_tampered_packet() { + let mut deps = mock_dependencies(); + instantiate( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + InitMsg {}, + ) + .expect("instantiate is ok"); + deps.querier + .update_wasm(wasm_query_handler(|msg| match msg { + LightClientQueryMsg::VerifyCreation { .. } => to_json_binary(&1), + LightClientQueryMsg::VerifyMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::VerifyNonMembership { .. } => to_json_binary(&()), + LightClientQueryMsg::GetTimestamp { .. } => to_json_binary(&100000), + msg => panic!("should not be called: {:?}", msg), + })); + + // Create client + register_client(deps.as_mut()).expect("register client ok"); + create_client(deps.as_mut()).expect("create client ok"); + // Create connection + connection_open_try(deps.as_mut()).expect("connection open try is ok"); + connection_open_confirm(deps.as_mut()).expect("connection open confirm is ok"); + // Create channel + channel_open_init(deps.as_mut()).expect("channel open init is ok"); + let msg = MsgChannelOpenInit { + port_id: mock_addr(SENDER).to_string(), + counterparty_port_id: vec![1].into(), + connection_id: 1, + version: VERSION.to_owned(), + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenInit(msg), + ) + .expect("channel open init is okay"); + channel_open_ack(deps.as_mut()).expect("channel open ack is ok"); + let msg = MsgChannelOpenAck { + channel_id: 2, + counterparty_version: VERSION.to_owned(), + counterparty_channel_id: 0, + proof_try: vec![1, 2, 3].into(), + proof_height: 1, + relayer: mock_addr(RELAYER).to_string(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::ChannelOpenAck(msg), + ) + .expect("channel open ack is ok"); + + let msg = MsgPacketRecv { + packets: vec![Packet { + source_channel: 0, + destination_channel: 2, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 0, + }], + relayer_msgs: vec![vec![1].into()], + relayer: mock_addr(RELAYER).to_string(), + proof: vec![1, 2, 3].into(), + proof_height: 1, + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketRecv(msg), + ) + .expect("recv packet ok"); + let msg = MsgWriteAcknowledgement { + channel_id: 2, + packet: Packet { + source_channel: 0, + destination_channel: 2, + data: vec![1, 2, 3].into(), + timeout_height: 100000, + timeout_timestamp: 0, + }, + acknowledgement: vec![1].into(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::WriteAcknowledgement(msg), + ) + .expect("write ack is ok"); + let msg = MsgPacketRecv { + packets: vec![Packet { + source_channel: 0, + destination_channel: 2, + data: vec![3, 4, 5].into(), + timeout_height: 100000, + timeout_timestamp: 0, + }], + relayer_msgs: vec![vec![1].into()], + relayer: mock_addr(RELAYER).to_string(), + proof: vec![1, 2, 3].into(), + proof_height: 1, + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::PacketRecv(msg), + ) + .expect("recv packet ok"); + let msg = MsgWriteAcknowledgement { + channel_id: 2, + packet: Packet { + source_channel: 0, + destination_channel: 2, + data: vec![3, 4, 5].into(), + timeout_height: 100000, + timeout_timestamp: 0, + }, + acknowledgement: vec![1].into(), + }; + execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::WriteAcknowledgement(msg), + ) + .expect("write ack is ok"); + + let msg = MsgBatchAcks { + source_channel: 2, + packets: vec![ + Packet { + source_channel: 0, + destination_channel: 2, + data: vec![10, 20, 30].into(), + timeout_height: 100000, + timeout_timestamp: 0, + }, + Packet { + source_channel: 0, + destination_channel: 2, + data: vec![30, 40, 50].into(), + timeout_height: 100000, + timeout_timestamp: 0, + }, + ], + acks: vec![vec![1].into(), vec![1].into()], + }; + assert!(execute( + deps.as_mut(), + mock_env(), + message_info(&mock_addr(SENDER), &[]), + ExecuteMsg::BatchAcks(msg) + ) + .is_err_and(|err| { matches!(err, ContractError::PacketCommitmentNotFound) })) +}