From b4e8e671f96e0020ae92a262abf679db4bd8e27a Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Wed, 22 Dec 2021 21:47:34 +0100 Subject: [PATCH 1/9] add context to multitest execution errors --- packages/multi-test/src/contracts.rs | 26 +++++++++++++++++++------- packages/multi-test/src/executor.rs | 25 ++++++++++++++++++------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/packages/multi-test/src/contracts.rs b/packages/multi-test/src/contracts.rs index 8b0af4079..bf88b1158 100644 --- a/packages/multi-test/src/contracts.rs +++ b/packages/multi-test/src/contracts.rs @@ -6,7 +6,7 @@ use cosmwasm_std::{ from_slice, Binary, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Reply, Response, SubMsg, }; -use anyhow::{anyhow, bail, Result as AnyResult}; +use anyhow::{anyhow, bail, Context, Result as AnyResult}; /// Interface to call into a Contract pub trait Contract @@ -65,7 +65,7 @@ pub struct ContractWrapper< T6 = Empty, E6 = anyhow::Error, > where - T1: DeserializeOwned, + T1: DeserializeOwned + Debug, T2: DeserializeOwned, T3: DeserializeOwned, T4: DeserializeOwned, @@ -88,7 +88,7 @@ pub struct ContractWrapper< impl ContractWrapper where - T1: DeserializeOwned + 'static, + T1: DeserializeOwned + Debug + 'static, T2: DeserializeOwned + 'static, T3: DeserializeOwned + 'static, E1: Display + Debug + Send + Sync + 'static, @@ -132,7 +132,7 @@ where impl ContractWrapper where - T1: DeserializeOwned + 'static, + T1: DeserializeOwned + Debug + 'static, T2: DeserializeOwned + 'static, T3: DeserializeOwned + 'static, T4: DeserializeOwned + 'static, @@ -317,7 +317,7 @@ where impl Contract for ContractWrapper where - T1: DeserializeOwned, + T1: DeserializeOwned + Debug + Clone, T2: DeserializeOwned, T3: DeserializeOwned, T4: DeserializeOwned, @@ -337,8 +337,20 @@ where info: MessageInfo, msg: Vec, ) -> AnyResult> { - let msg = from_slice(&msg)?; - (self.execute_fn)(deps, env, info, msg).map_err(|err| anyhow!(err)) + let msg: T1 = from_slice(&msg)?; + let address = env.contract.address.clone(); + (self.execute_fn)(deps, env, info.clone(), msg.clone()) + .map_err(|err| anyhow!("{}", err)) + .context(format!( + r#"Contract returned an error on execute +Contract address: {} +Message sender: {} +Funds: {:?} +Message dump: +{:?} +"#, + address, info.sender, info.funds, msg, + )) } fn instantiate( diff --git a/packages/multi-test/src/executor.rs b/packages/multi-test/src/executor.rs index 6e1e8678d..31fe75ee5 100644 --- a/packages/multi-test/src/executor.rs +++ b/packages/multi-test/src/executor.rs @@ -8,7 +8,7 @@ use schemars::JsonSchema; use serde::Serialize; use utils::{parse_execute_response_data, parse_instantiate_response_data}; -use anyhow::Result as AnyResult; +use anyhow::{Context, Result as AnyResult}; #[derive(Default, Clone, Debug)] pub struct AppResponse { @@ -98,20 +98,31 @@ where /// Execute a contract and process all returned messages. /// This is just a helper around execute(), /// but we parse out the data field to that what is returned by the contract (not the protobuf wrapper) - fn execute_contract( + fn execute_contract( &mut self, sender: Addr, contract_addr: Addr, msg: &T, send_funds: &[Coin], ) -> AnyResult { - let msg = to_binary(msg)?; - let msg = WasmMsg::Execute { - contract_addr: contract_addr.into(), - msg, + let binary_msg = to_binary(msg)?; + let wrapped_msg = WasmMsg::Execute { + contract_addr: contract_addr.to_string(), + msg: binary_msg, funds: send_funds.to_vec(), }; - let mut res = self.execute(sender, msg.into())?; + let mut res = self + .execute(sender.clone(), wrapped_msg.into()) + .context(format!( + r#"Contract returned an error on execute +Contract address: {} +Message sender: {} +Funds: {:?} +Message dump: +{:?} +"#, + contract_addr, sender, send_funds, msg, + ))?; res.data = res .data .and_then(|d| parse_execute_response_data(d.as_slice()).unwrap().data); From 582e47e4a251b050e3de5977e90feafaa05ef5ca Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 3 Jan 2022 19:09:56 +0100 Subject: [PATCH 2/9] multitest: add a contract that tests WasmMsg calls --- packages/multi-test/src/contracts.rs | 2 +- .../multi-test/src/test_helpers/contracts.rs | 1 + .../src/test_helpers/contracts/caller.rs | 40 +++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 packages/multi-test/src/test_helpers/contracts/caller.rs diff --git a/packages/multi-test/src/contracts.rs b/packages/multi-test/src/contracts.rs index bf88b1158..8aca6173b 100644 --- a/packages/multi-test/src/contracts.rs +++ b/packages/multi-test/src/contracts.rs @@ -342,7 +342,7 @@ where (self.execute_fn)(deps, env, info.clone(), msg.clone()) .map_err(|err| anyhow!("{}", err)) .context(format!( - r#"Contract returned an error on execute + r#"aContract returned an error on execute Contract address: {} Message sender: {} Funds: {:?} diff --git a/packages/multi-test/src/test_helpers/contracts.rs b/packages/multi-test/src/test_helpers/contracts.rs index 8be3e8674..68babbf84 100644 --- a/packages/multi-test/src/test_helpers/contracts.rs +++ b/packages/multi-test/src/test_helpers/contracts.rs @@ -1,5 +1,6 @@ //! Module for simple contracts to be used in tests +pub mod caller; pub mod echo; pub mod error; pub mod hackatom; diff --git a/packages/multi-test/src/test_helpers/contracts/caller.rs b/packages/multi-test/src/test_helpers/contracts/caller.rs new file mode 100644 index 000000000..92367a3de --- /dev/null +++ b/packages/multi-test/src/test_helpers/contracts/caller.rs @@ -0,0 +1,40 @@ +use std::fmt; + +use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, StdError, SubMsg, WasmMsg}; +use schemars::JsonSchema; + +use crate::{test_helpers::EmptyMsg, Contract, ContractWrapper}; + +fn instantiate( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + _msg: EmptyMsg, +) -> Result { + Ok(Response::default()) +} + +fn execute( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + msg: WasmMsg, +) -> Result { + let message = SubMsg::new(msg); + + Ok(Response::new().add_submessage(message)) +} + +fn query(_deps: Deps, _env: Env, _msg: EmptyMsg) -> Result { + Err(StdError::generic_err( + "query not implemented for the `caller` contract", + )) +} + +pub fn contract() -> Box> +where + C: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, +{ + let contract = ContractWrapper::new_with_empty(execute, instantiate, query); + Box::new(contract) +} From 0291e82f1ffde063cdbd1917fe8a392eab690755 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 4 Jan 2022 11:22:36 +0100 Subject: [PATCH 3/9] multitest: add tests for contract errors --- packages/multi-test/src/app.rs | 132 +++++++++++++++++- packages/multi-test/src/contracts.rs | 7 +- .../src/test_helpers/contracts/error.rs | 19 ++- packages/multi-test/src/wasm.rs | 2 +- 4 files changed, 152 insertions(+), 8 deletions(-) diff --git a/packages/multi-test/src/app.rs b/packages/multi-test/src/app.rs index 7af9792e2..01a1ddfa4 100644 --- a/packages/multi-test/src/app.rs +++ b/packages/multi-test/src/app.rs @@ -947,7 +947,7 @@ mod test { }; use crate::error::Error; - use crate::test_helpers::contracts::{echo, hackatom, payout, reflect}; + use crate::test_helpers::contracts::{caller, echo, error, hackatom, payout, reflect}; use crate::test_helpers::{CustomMsg, EmptyMsg}; use crate::transactions::StorageTransaction; @@ -2580,4 +2580,134 @@ mod test { assert_eq!(exec_res.data, Some(Binary::from(b"hello"))); } } + + mod errors { + use super::*; + + #[test] + fn simple_call() { + let owner = Addr::unchecked("owner"); + let mut app = App::default(); + + // set up contract + let code_id = app.store_code(error::contract(true)); + let msg = EmptyMsg {}; + let contract_addr = app + .instantiate_contract(code_id, owner, &msg, &[], "error", None) + .unwrap(); + + // execute should error + let err = app + .execute_contract(Addr::unchecked("random"), contract_addr.clone(), &msg, &[]) + .unwrap_err(); + let source: &StdError = err.downcast_ref().unwrap(); + if let StdError::GenericErr { msg } = source { + assert_eq!(msg, "Handle failed"); + } else { + panic!("wrong StdError variant"); + } + } + + // #[test] + // fn simple_call_gives_one_context_layer() { + // let owner = Addr::unchecked("owner"); + // let mut app = App::default(); + + // let error_code_id = app.store_code(error::contract(true)); + + // // set up contract + // let msg = EmptyMsg {}; + // let error_addr = app + // .instantiate_contract(error_code_id, owner, &msg, &[], "error", None) + // .unwrap(); + + // // execute should error + // let err = app + // .execute_contract(Addr::unchecked("random"), error_addr.clone(), &msg, &[]) + // .unwrap(); + // //let source = err.source().unwrap(); + // //let foo: &StdError = source.downcast_ref().unwrap(); + // //assert_eq!(source.to_string(), "aContract returned an error on execute\nContract address: Contract #0\nMessage sender: random\nFunds: []\nMessage dump:\nEmptyMsg\n"); + // } + + #[test] + fn nested_call() { + let owner = Addr::unchecked("owner"); + let mut app = App::default(); + + let error_code_id = app.store_code(error::contract(true)); + let caller_code_id = app.store_code(caller::contract()); + + // set up contracts + let msg = EmptyMsg {}; + let caller_addr = app + .instantiate_contract(caller_code_id, owner.clone(), &msg, &[], "caller", None) + .unwrap(); + let error_addr = app + .instantiate_contract(error_code_id, owner, &msg, &[], "error", None) + .unwrap(); + + // execute should error + let msg = WasmMsg::Execute { + contract_addr: error_addr.into(), + msg: to_binary(&EmptyMsg {}).unwrap(), + funds: vec![], + }; + let err = app + .execute_contract(Addr::unchecked("random"), caller_addr.clone(), &msg, &[]) + .unwrap_err(); + + // we can downcast to get the original error + let source: &StdError = err.downcast_ref().unwrap(); + if let StdError::GenericErr { msg } = source { + assert_eq!(msg, "Handle failed"); + } else { + panic!("wrong StdError variant"); + } + } + + #[test] + fn double_nested_call() { + let owner = Addr::unchecked("owner"); + let mut app = App::default(); + + let error_code_id = app.store_code(error::contract(true)); + let caller_code_id = app.store_code(caller::contract()); + + // set up contracts + let msg = EmptyMsg {}; + let caller_addr1 = app + .instantiate_contract(caller_code_id, owner.clone(), &msg, &[], "caller", None) + .unwrap(); + let caller_addr2 = app + .instantiate_contract(caller_code_id, owner.clone(), &msg, &[], "caller", None) + .unwrap(); + let error_addr = app + .instantiate_contract(error_code_id, owner, &msg, &[], "error", None) + .unwrap(); + + // caller1 calls caller2, caller2 calls error + let msg = WasmMsg::Execute { + contract_addr: caller_addr2.into(), + msg: to_binary(&WasmMsg::Execute { + contract_addr: error_addr.into(), + msg: to_binary(&EmptyMsg {}).unwrap(), + funds: vec![], + }) + .unwrap(), + funds: vec![], + }; + let err = app + .execute_contract(Addr::unchecked("random"), caller_addr1.clone(), &msg, &[]) + .unwrap_err(); + + // we can downcast to get the original error + let source: &StdError = err.downcast_ref().unwrap(); + if let StdError::GenericErr { msg } = source { + assert_eq!(msg, "Handle failed"); + } else { + panic!("wrong StdError variant"); + } + } + } } diff --git a/packages/multi-test/src/contracts.rs b/packages/multi-test/src/contracts.rs index 8aca6173b..39101245b 100644 --- a/packages/multi-test/src/contracts.rs +++ b/packages/multi-test/src/contracts.rs @@ -1,5 +1,6 @@ use schemars::JsonSchema; use serde::de::DeserializeOwned; +use std::error::Error; use std::fmt::{self, Debug, Display}; use cosmwasm_std::{ @@ -322,7 +323,7 @@ where T3: DeserializeOwned, T4: DeserializeOwned, T6: DeserializeOwned, - E1: Display + Debug + Send + Sync + 'static, + E1: Display + Debug + Send + Sync + Error + 'static, E2: Display + Debug + Send + Sync + 'static, E3: Display + Debug + Send + Sync + 'static, E4: Display + Debug + Send + Sync + 'static, @@ -340,9 +341,9 @@ where let msg: T1 = from_slice(&msg)?; let address = env.contract.address.clone(); (self.execute_fn)(deps, env, info.clone(), msg.clone()) - .map_err(|err| anyhow!("{}", err)) + .map_err(|err| anyhow::Error::from(err)) .context(format!( - r#"aContract returned an error on execute + r#"Contract returned an error on execute Contract address: {} Message sender: {} Funds: {:?} diff --git a/packages/multi-test/src/test_helpers/contracts/error.rs b/packages/multi-test/src/test_helpers/contracts/error.rs index 710484aca..e707e80d6 100644 --- a/packages/multi-test/src/test_helpers/contracts/error.rs +++ b/packages/multi-test/src/test_helpers/contracts/error.rs @@ -5,7 +5,7 @@ use schemars::JsonSchema; use crate::{test_helpers::EmptyMsg, Contract, ContractWrapper}; -fn instantiate( +fn instantiate_err( _deps: DepsMut, _env: Env, _info: MessageInfo, @@ -14,6 +14,15 @@ fn instantiate( Err(StdError::generic_err("Init failed")) } +fn instantiate_ok( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + _msg: EmptyMsg, +) -> Result { + Ok(Response::default()) +} + fn execute( _deps: DepsMut, _env: Env, @@ -27,10 +36,14 @@ fn query(_deps: Deps, _env: Env, _msg: EmptyMsg) -> Result { Err(StdError::generic_err("Query failed")) } -pub fn contract() -> Box> +pub fn contract(instantiable: bool) -> Box> where C: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, { - let contract = ContractWrapper::new_with_empty(execute, instantiate, query); + let contract = if instantiable { + ContractWrapper::new_with_empty(execute, instantiate_ok, query) + } else { + ContractWrapper::new_with_empty(execute, instantiate_err, query) + }; Box::new(contract) } diff --git a/packages/multi-test/src/wasm.rs b/packages/multi-test/src/wasm.rs index 1e1ef5872..a0b7c66c6 100644 --- a/packages/multi-test/src/wasm.rs +++ b/packages/multi-test/src/wasm.rs @@ -946,7 +946,7 @@ mod test { let mut wasm_storage = MockStorage::new(); let mut keeper = WasmKeeper::new(); let block = mock_env().block; - let code_id = keeper.store_code(error::contract()); + let code_id = keeper.store_code(error::contract(false)); transactional(&mut wasm_storage, |cache, _| { // cannot register contract with unregistered codeId From 2c90217e59945eef0c6a6f8fa6f53e6904e529f4 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 4 Jan 2022 15:05:53 +0100 Subject: [PATCH 4/9] multitest: handle nested error contexts properly --- packages/multi-test/src/app.rs | 36 +++++++++++----------------- packages/multi-test/src/contracts.rs | 11 ++------- packages/multi-test/src/executor.rs | 15 ++---------- packages/multi-test/src/wasm.rs | 13 +++++++--- 4 files changed, 28 insertions(+), 47 deletions(-) diff --git a/packages/multi-test/src/app.rs b/packages/multi-test/src/app.rs index 01a1ddfa4..25c50d312 100644 --- a/packages/multi-test/src/app.rs +++ b/packages/multi-test/src/app.rs @@ -2600,35 +2600,19 @@ mod test { let err = app .execute_contract(Addr::unchecked("random"), contract_addr.clone(), &msg, &[]) .unwrap_err(); + + // we should be able to retrieve the original error by downcasting let source: &StdError = err.downcast_ref().unwrap(); if let StdError::GenericErr { msg } = source { assert_eq!(msg, "Handle failed"); } else { panic!("wrong StdError variant"); } - } - - // #[test] - // fn simple_call_gives_one_context_layer() { - // let owner = Addr::unchecked("owner"); - // let mut app = App::default(); - - // let error_code_id = app.store_code(error::contract(true)); - // // set up contract - // let msg = EmptyMsg {}; - // let error_addr = app - // .instantiate_contract(error_code_id, owner, &msg, &[], "error", None) - // .unwrap(); - - // // execute should error - // let err = app - // .execute_contract(Addr::unchecked("random"), error_addr.clone(), &msg, &[]) - // .unwrap(); - // //let source = err.source().unwrap(); - // //let foo: &StdError = source.downcast_ref().unwrap(); - // //assert_eq!(source.to_string(), "aContract returned an error on execute\nContract address: Contract #0\nMessage sender: random\nFunds: []\nMessage dump:\nEmptyMsg\n"); - // } + // we're expecting exactly 3 wrapped errors + // (the original error, execute msg context, WasmMsg context) + assert_eq!(err.chain().count(), 3); + } #[test] fn nested_call() { @@ -2664,6 +2648,10 @@ mod test { } else { panic!("wrong StdError variant"); } + + // we're expecting exactly 4 wrapped errors + // (the original error, execute msg context, 2 WasmMsg contexts) + assert_eq!(err.chain().count(), 4); } #[test] @@ -2708,6 +2696,10 @@ mod test { } else { panic!("wrong StdError variant"); } + + // we're expecting exactly 5 wrapped errors + // (the original error, execute msg context, 3 WasmMsg contexts) + assert_eq!(err.chain().count(), 5); } } } diff --git a/packages/multi-test/src/contracts.rs b/packages/multi-test/src/contracts.rs index 39101245b..1cb04509c 100644 --- a/packages/multi-test/src/contracts.rs +++ b/packages/multi-test/src/contracts.rs @@ -339,18 +339,11 @@ where msg: Vec, ) -> AnyResult> { let msg: T1 = from_slice(&msg)?; - let address = env.contract.address.clone(); (self.execute_fn)(deps, env, info.clone(), msg.clone()) .map_err(|err| anyhow::Error::from(err)) .context(format!( - r#"Contract returned an error on execute -Contract address: {} -Message sender: {} -Funds: {:?} -Message dump: -{:?} -"#, - address, info.sender, info.funds, msg, + "Contract returned an error on execute msg:\n{:?}", + msg, )) } diff --git a/packages/multi-test/src/executor.rs b/packages/multi-test/src/executor.rs index 31fe75ee5..0ab199413 100644 --- a/packages/multi-test/src/executor.rs +++ b/packages/multi-test/src/executor.rs @@ -8,7 +8,7 @@ use schemars::JsonSchema; use serde::Serialize; use utils::{parse_execute_response_data, parse_instantiate_response_data}; -use anyhow::{Context, Result as AnyResult}; +use anyhow::Result as AnyResult; #[derive(Default, Clone, Debug)] pub struct AppResponse { @@ -111,18 +111,7 @@ where msg: binary_msg, funds: send_funds.to_vec(), }; - let mut res = self - .execute(sender.clone(), wrapped_msg.into()) - .context(format!( - r#"Contract returned an error on execute -Contract address: {} -Message sender: {} -Funds: {:?} -Message dump: -{:?} -"#, - contract_addr, sender, send_funds, msg, - ))?; + let mut res = self.execute(sender.clone(), wrapped_msg.into())?; res.data = res .data .and_then(|d| parse_execute_response_data(d.as_slice()).unwrap().data); diff --git a/packages/multi-test/src/wasm.rs b/packages/multi-test/src/wasm.rs index a0b7c66c6..542c485d0 100644 --- a/packages/multi-test/src/wasm.rs +++ b/packages/multi-test/src/wasm.rs @@ -23,7 +23,7 @@ use crate::executor::AppResponse; use crate::transactions::transactional; use cosmwasm_std::testing::mock_wasmd_attr; -use anyhow::{bail, Result as AnyResult}; +use anyhow::{bail, Context, Result as AnyResult}; // TODO: we should import this from cosmwasm-std, but cannot due to non_exhaustive so copy here #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -174,7 +174,11 @@ where sender: Addr, msg: WasmMsg, ) -> AnyResult { - self.execute_wasm(api, storage, router, block, sender, msg) + self.execute_wasm(api, storage, router, block, sender.clone(), msg.clone()) + .context(format!( + "error executing WasmMsg:\nsender: {}\n{:?}", + sender, msg + )) } fn sudo( @@ -297,7 +301,10 @@ where )?; // then call the contract - let info = MessageInfo { sender, funds }; + let info = MessageInfo { + sender: sender.clone(), + funds: funds.clone(), + }; let res = self.call_execute( api, storage, From 05cf44454d4f7f9220fa1913a6488c8c751db8b8 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 4 Jan 2022 15:43:41 +0100 Subject: [PATCH 5/9] clippy --- packages/multi-test/src/app.rs | 6 +++--- packages/multi-test/src/contracts.rs | 4 ++-- packages/multi-test/src/executor.rs | 2 +- packages/multi-test/src/wasm.rs | 5 +---- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/multi-test/src/app.rs b/packages/multi-test/src/app.rs index 25c50d312..0f72cd698 100644 --- a/packages/multi-test/src/app.rs +++ b/packages/multi-test/src/app.rs @@ -2598,7 +2598,7 @@ mod test { // execute should error let err = app - .execute_contract(Addr::unchecked("random"), contract_addr.clone(), &msg, &[]) + .execute_contract(Addr::unchecked("random"), contract_addr, &msg, &[]) .unwrap_err(); // we should be able to retrieve the original error by downcasting @@ -2638,7 +2638,7 @@ mod test { funds: vec![], }; let err = app - .execute_contract(Addr::unchecked("random"), caller_addr.clone(), &msg, &[]) + .execute_contract(Addr::unchecked("random"), caller_addr, &msg, &[]) .unwrap_err(); // we can downcast to get the original error @@ -2686,7 +2686,7 @@ mod test { funds: vec![], }; let err = app - .execute_contract(Addr::unchecked("random"), caller_addr1.clone(), &msg, &[]) + .execute_contract(Addr::unchecked("random"), caller_addr1, &msg, &[]) .unwrap_err(); // we can downcast to get the original error diff --git a/packages/multi-test/src/contracts.rs b/packages/multi-test/src/contracts.rs index 1cb04509c..6c190a81c 100644 --- a/packages/multi-test/src/contracts.rs +++ b/packages/multi-test/src/contracts.rs @@ -339,8 +339,8 @@ where msg: Vec, ) -> AnyResult> { let msg: T1 = from_slice(&msg)?; - (self.execute_fn)(deps, env, info.clone(), msg.clone()) - .map_err(|err| anyhow::Error::from(err)) + (self.execute_fn)(deps, env, info, msg.clone()) + .map_err(anyhow::Error::from) .context(format!( "Contract returned an error on execute msg:\n{:?}", msg, diff --git a/packages/multi-test/src/executor.rs b/packages/multi-test/src/executor.rs index 0ab199413..53653ba02 100644 --- a/packages/multi-test/src/executor.rs +++ b/packages/multi-test/src/executor.rs @@ -111,7 +111,7 @@ where msg: binary_msg, funds: send_funds.to_vec(), }; - let mut res = self.execute(sender.clone(), wrapped_msg.into())?; + let mut res = self.execute(sender, wrapped_msg.into())?; res.data = res .data .and_then(|d| parse_execute_response_data(d.as_slice()).unwrap().data); diff --git a/packages/multi-test/src/wasm.rs b/packages/multi-test/src/wasm.rs index 542c485d0..56279925b 100644 --- a/packages/multi-test/src/wasm.rs +++ b/packages/multi-test/src/wasm.rs @@ -301,10 +301,7 @@ where )?; // then call the contract - let info = MessageInfo { - sender: sender.clone(), - funds: funds.clone(), - }; + let info = MessageInfo { sender, funds }; let res = self.call_execute( api, storage, From 3eb5e2d013c6f8a2aee0cf4a18f36e10755236fb Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 4 Jan 2022 15:50:06 +0100 Subject: [PATCH 6/9] multitest: test comments --- packages/multi-test/src/app.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/multi-test/src/app.rs b/packages/multi-test/src/app.rs index 0f72cd698..8827c7c55 100644 --- a/packages/multi-test/src/app.rs +++ b/packages/multi-test/src/app.rs @@ -2609,7 +2609,7 @@ mod test { panic!("wrong StdError variant"); } - // we're expecting exactly 3 wrapped errors + // we're expecting exactly 3 nested error types // (the original error, execute msg context, WasmMsg context) assert_eq!(err.chain().count(), 3); } @@ -2649,7 +2649,7 @@ mod test { panic!("wrong StdError variant"); } - // we're expecting exactly 4 wrapped errors + // we're expecting exactly 4 nested error types // (the original error, execute msg context, 2 WasmMsg contexts) assert_eq!(err.chain().count(), 4); } @@ -2689,6 +2689,9 @@ mod test { .execute_contract(Addr::unchecked("random"), caller_addr1, &msg, &[]) .unwrap_err(); + // uncomment to have the test fail and see how the error stringifies + // panic!("{:?}", err); + // we can downcast to get the original error let source: &StdError = err.downcast_ref().unwrap(); if let StdError::GenericErr { msg } = source { @@ -2697,7 +2700,7 @@ mod test { panic!("wrong StdError variant"); } - // we're expecting exactly 5 wrapped errors + // we're expecting exactly 5 nested error types // (the original error, execute msg context, 3 WasmMsg contexts) assert_eq!(err.chain().count(), 5); } From 708e572e1e200bd6b60312747de7cf0c6790f49b Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 4 Jan 2022 21:02:58 +0100 Subject: [PATCH 7/9] multitest: style --- packages/multi-test/src/executor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multi-test/src/executor.rs b/packages/multi-test/src/executor.rs index c756653d4..b6eb341e1 100644 --- a/packages/multi-test/src/executor.rs +++ b/packages/multi-test/src/executor.rs @@ -107,7 +107,7 @@ where ) -> AnyResult { let binary_msg = to_binary(msg)?; let wrapped_msg = WasmMsg::Execute { - contract_addr: contract_addr.to_string(), + contract_addr: contract_addr.into_string(), msg: binary_msg, funds: send_funds.to_vec(), }; From ef50e4b96e505e3ee0ea9352352325b3707edadf Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 4 Jan 2022 21:17:56 +0100 Subject: [PATCH 8/9] multitest: context for queries and instantiations --- packages/multi-test/src/app.rs | 25 +++++++++++++++++++++++++ packages/multi-test/src/contracts.rs | 26 ++++++++++++++++++-------- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/packages/multi-test/src/app.rs b/packages/multi-test/src/app.rs index 34dec22e8..326d54587 100644 --- a/packages/multi-test/src/app.rs +++ b/packages/multi-test/src/app.rs @@ -2584,6 +2584,31 @@ mod test { mod errors { use super::*; + #[test] + fn simple_instantiation() { + let owner = Addr::unchecked("owner"); + let mut app = App::default(); + + // set up contract + let code_id = app.store_code(error::contract(false)); + let msg = EmptyMsg {}; + let err = app + .instantiate_contract(code_id, owner, &msg, &[], "error", None) + .unwrap_err(); + + // we should be able to retrieve the original error by downcasting + let source: &StdError = err.downcast_ref().unwrap(); + if let StdError::GenericErr { msg } = source { + assert_eq!(msg, "Init failed"); + } else { + panic!("wrong StdError variant"); + } + + // we're expecting exactly 3 nested error types + // (the original error, initiate msg context, WasmMsg context) + assert_eq!(err.chain().count(), 3); + } + #[test] fn simple_call() { let owner = Addr::unchecked("owner"); diff --git a/packages/multi-test/src/contracts.rs b/packages/multi-test/src/contracts.rs index 6c190a81c..e703b75a8 100644 --- a/packages/multi-test/src/contracts.rs +++ b/packages/multi-test/src/contracts.rs @@ -319,13 +319,13 @@ impl Contract for ContractWrapper where T1: DeserializeOwned + Debug + Clone, - T2: DeserializeOwned, - T3: DeserializeOwned, + T2: DeserializeOwned + Debug + Clone, + T3: DeserializeOwned + Debug + Clone, T4: DeserializeOwned, T6: DeserializeOwned, E1: Display + Debug + Send + Sync + Error + 'static, - E2: Display + Debug + Send + Sync + 'static, - E3: Display + Debug + Send + Sync + 'static, + E2: Display + Debug + Send + Sync + Error + 'static, + E3: Display + Debug + Send + Sync + Error + 'static, E4: Display + Debug + Send + Sync + 'static, E5: Display + Debug + Send + Sync + 'static, E6: Display + Debug + Send + Sync + 'static, @@ -354,13 +354,23 @@ where info: MessageInfo, msg: Vec, ) -> AnyResult> { - let msg = from_slice(&msg)?; - (self.instantiate_fn)(deps, env, info, msg).map_err(|err| anyhow!(err)) + let msg: T2 = from_slice(&msg)?; + (self.instantiate_fn)(deps, env, info, msg.clone()) + .map_err(anyhow::Error::from) + .context(format!( + "Contract returned an error on instantiate msg:\n{:?}", + msg, + )) } fn query(&self, deps: Deps, env: Env, msg: Vec) -> AnyResult { - let msg = from_slice(&msg)?; - (self.query_fn)(deps, env, msg).map_err(|err| anyhow!(err)) + let msg: T3 = from_slice(&msg)?; + (self.query_fn)(deps, env, msg.clone()) + .map_err(anyhow::Error::from) + .context(format!( + "Contract returned an error on query msg:\n{:?}", + msg, + )) } // this returns an error if the contract doesn't implement sudo From ede69a5714a0c0be6faf22867179fd577415d770 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 4 Jan 2022 21:33:44 +0100 Subject: [PATCH 9/9] cw1-whitelist: missing InstantiateMsg derives --- contracts/cw1-whitelist/src/msg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/cw1-whitelist/src/msg.rs b/contracts/cw1-whitelist/src/msg.rs index f0c4f04c1..bdfb6d2f5 100644 --- a/contracts/cw1-whitelist/src/msg.rs +++ b/contracts/cw1-whitelist/src/msg.rs @@ -4,7 +4,7 @@ use std::fmt; use cosmwasm_std::{CosmosMsg, Empty}; -#[derive(Serialize, Deserialize, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct InstantiateMsg { pub admins: Vec, pub mutable: bool,