From 3edbdc75dfa3c3f72c2273a7488881d1362ac626 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 8 Feb 2022 22:25:35 +0100 Subject: [PATCH] multi-test: support custom queries --- packages/multi-test/src/app.rs | 2 +- packages/multi-test/src/contracts.rs | 130 ++++++++++++++------------- packages/multi-test/src/wasm.rs | 8 +- 3 files changed, 75 insertions(+), 65 deletions(-) diff --git a/packages/multi-test/src/app.rs b/packages/multi-test/src/app.rs index c23e6873a..f06ba6ac4 100644 --- a/packages/multi-test/src/app.rs +++ b/packages/multi-test/src/app.rs @@ -557,7 +557,7 @@ where { /// This registers contract code (like uploading wasm bytecode on a chain), /// so it can later be used to instantiate a contract. - pub fn store_code(&mut self, code: Box>) -> u64 { + pub fn store_code(&mut self, code: Box>) -> u64 { self.init_modules(|router, _, _| router.wasm.store_code(code) as u64) } diff --git a/packages/multi-test/src/contracts.rs b/packages/multi-test/src/contracts.rs index e703b75a8..72bf76950 100644 --- a/packages/multi-test/src/contracts.rs +++ b/packages/multi-test/src/contracts.rs @@ -4,19 +4,21 @@ use std::error::Error; use std::fmt::{self, Debug, Display}; use cosmwasm_std::{ - from_slice, Binary, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Reply, Response, SubMsg, + from_slice, Binary, CosmosMsg, CustomQuery, Deps, DepsMut, Empty, Env, MessageInfo, Reply, + Response, SubMsg, }; use anyhow::{anyhow, bail, Context, Result as AnyResult}; /// Interface to call into a Contract -pub trait Contract +pub trait Contract where T: Clone + fmt::Debug + PartialEq + JsonSchema, + Q: CustomQuery, { fn execute( &self, - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, msg: Vec, @@ -24,31 +26,32 @@ where fn instantiate( &self, - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, msg: Vec, ) -> AnyResult>; - fn query(&self, deps: Deps, env: Env, msg: Vec) -> AnyResult; + fn query(&self, deps: Deps, env: Env, msg: Vec) -> AnyResult; - fn sudo(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult>; + fn sudo(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult>; - fn reply(&self, deps: DepsMut, env: Env, msg: Reply) -> AnyResult>; + fn reply(&self, deps: DepsMut, env: Env, msg: Reply) -> AnyResult>; - fn migrate(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult>; + fn migrate(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult>; } -type ContractFn = - fn(deps: DepsMut, env: Env, info: MessageInfo, msg: T) -> Result, E>; -type PermissionedFn = fn(deps: DepsMut, env: Env, msg: T) -> Result, E>; -type ReplyFn = fn(deps: DepsMut, env: Env, msg: Reply) -> Result, E>; -type QueryFn = fn(deps: Deps, env: Env, msg: T) -> Result; +type ContractFn = + fn(deps: DepsMut, env: Env, info: MessageInfo, msg: T) -> Result, E>; +type PermissionedFn = fn(deps: DepsMut, env: Env, msg: T) -> Result, E>; +type ReplyFn = fn(deps: DepsMut, env: Env, msg: Reply) -> Result, E>; +type QueryFn = fn(deps: Deps, env: Env, msg: T) -> Result; -type ContractClosure = Box Result, E>>; -type PermissionedClosure = Box Result, E>>; -type ReplyClosure = Box Result, E>>; -type QueryClosure = Box Result>; +type ContractClosure = + Box, Env, MessageInfo, T) -> Result, E>>; +type PermissionedClosure = Box, Env, T) -> Result, E>>; +type ReplyClosure = Box, Env, Reply) -> Result, E>>; +type QueryClosure = Box, Env, T) -> Result>; /// Wraps the exported functions from a contract and provides the normalized format /// Place T4 and E4 at the end, as we just want default placeholders for most contracts that don't have sudo @@ -60,6 +63,7 @@ pub struct ContractWrapper< E2, E3, C = Empty, + Q = Empty, T4 = Empty, E4 = anyhow::Error, E5 = anyhow::Error, @@ -78,16 +82,17 @@ pub struct ContractWrapper< E5: Display + Debug + Send + Sync + 'static, E6: Display + Debug + Send + Sync + 'static, C: Clone + fmt::Debug + PartialEq + JsonSchema, + Q: CustomQuery + DeserializeOwned + 'static, { - execute_fn: ContractClosure, - instantiate_fn: ContractClosure, - query_fn: QueryClosure, - sudo_fn: Option>, - reply_fn: Option>, - migrate_fn: Option>, + execute_fn: ContractClosure, + instantiate_fn: ContractClosure, + query_fn: QueryClosure, + sudo_fn: Option>, + reply_fn: Option>, + migrate_fn: Option>, } -impl ContractWrapper +impl ContractWrapper where T1: DeserializeOwned + Debug + 'static, T2: DeserializeOwned + 'static, @@ -96,13 +101,14 @@ where E2: Display + Debug + Send + Sync + 'static, E3: Display + Debug + Send + Sync + 'static, C: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, + Q: CustomQuery + DeserializeOwned + 'static, { pub fn new( - execute_fn: ContractFn, - instantiate_fn: ContractFn, - query_fn: QueryFn, + execute_fn: ContractFn, + instantiate_fn: ContractFn, + query_fn: QueryFn, ) -> Self { - ContractWrapper { + Self { execute_fn: Box::new(execute_fn), instantiate_fn: Box::new(instantiate_fn), query_fn: Box::new(query_fn), @@ -115,11 +121,11 @@ where /// this will take a contract that returns Response and will "upgrade" it /// to Response if needed to be compatible with a chain-specific extension pub fn new_with_empty( - execute_fn: ContractFn, - instantiate_fn: ContractFn, - query_fn: QueryFn, + execute_fn: ContractFn, + instantiate_fn: ContractFn, + query_fn: QueryFn, ) -> Self { - ContractWrapper { + Self { execute_fn: customize_fn(execute_fn), instantiate_fn: customize_fn(instantiate_fn), query_fn: Box::new(query_fn), @@ -130,8 +136,8 @@ where } } -impl - ContractWrapper +impl + ContractWrapper where T1: DeserializeOwned + Debug + 'static, T2: DeserializeOwned + 'static, @@ -145,11 +151,12 @@ where E5: Display + Debug + Send + Sync + 'static, E6: Display + Debug + Send + Sync + 'static, C: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, + Q: CustomQuery + DeserializeOwned + 'static, { pub fn with_sudo( self, - sudo_fn: PermissionedFn, - ) -> ContractWrapper + sudo_fn: PermissionedFn, + ) -> ContractWrapper where T4A: DeserializeOwned + 'static, E4A: Display + Debug + Send + Sync + 'static, @@ -166,8 +173,8 @@ where pub fn with_sudo_empty( self, - sudo_fn: PermissionedFn, - ) -> ContractWrapper + sudo_fn: PermissionedFn, + ) -> ContractWrapper where T4A: DeserializeOwned + 'static, E4A: Display + Debug + Send + Sync + 'static, @@ -184,8 +191,8 @@ where pub fn with_reply( self, - reply_fn: ReplyFn, - ) -> ContractWrapper + reply_fn: ReplyFn, + ) -> ContractWrapper where E5A: Display + Debug + Send + Sync + 'static, { @@ -202,8 +209,8 @@ where /// A correlate of new_with_empty pub fn with_reply_empty( self, - reply_fn: ReplyFn, - ) -> ContractWrapper + reply_fn: ReplyFn, + ) -> ContractWrapper where E5A: Display + Debug + Send + Sync + 'static, { @@ -219,8 +226,8 @@ where pub fn with_migrate( self, - migrate_fn: PermissionedFn, - ) -> ContractWrapper + migrate_fn: PermissionedFn, + ) -> ContractWrapper where T6A: DeserializeOwned + 'static, E6A: Display + Debug + Send + Sync + 'static, @@ -237,8 +244,8 @@ where pub fn with_migrate_empty( self, - migrate_fn: PermissionedFn, - ) -> ContractWrapper + migrate_fn: PermissionedFn, + ) -> ContractWrapper where T6A: DeserializeOwned + 'static, E6A: Display + Debug + Send + Sync + 'static, @@ -254,28 +261,30 @@ where } } -fn customize_fn(raw_fn: ContractFn) -> ContractClosure +fn customize_fn(raw_fn: ContractFn) -> ContractClosure where T: DeserializeOwned + 'static, E: Display + Debug + Send + Sync + 'static, C: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, + Q: CustomQuery + DeserializeOwned + 'static, { let customized = - move |deps: DepsMut, env: Env, info: MessageInfo, msg: T| -> Result, E> { + move |deps: DepsMut, env: Env, info: MessageInfo, msg: T| -> Result, E> { raw_fn(deps, env, info, msg).map(customize_response::) }; Box::new(customized) } -fn customize_permissioned_fn( - raw_fn: PermissionedFn, -) -> PermissionedClosure +fn customize_permissioned_fn( + raw_fn: PermissionedFn, +) -> PermissionedClosure where T: DeserializeOwned + 'static, E: Display + Debug + Send + Sync + 'static, C: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, + Q: CustomQuery + DeserializeOwned + 'static, { - let customized = move |deps: DepsMut, env: Env, msg: T| -> Result, E> { + let customized = move |deps: DepsMut, env: Env, msg: T| -> Result, E> { raw_fn(deps, env, msg).map(customize_response::) }; Box::new(customized) @@ -315,8 +324,8 @@ where } } -impl Contract - for ContractWrapper +impl Contract + for ContractWrapper where T1: DeserializeOwned + Debug + Clone, T2: DeserializeOwned + Debug + Clone, @@ -330,10 +339,11 @@ where E5: Display + Debug + Send + Sync + 'static, E6: Display + Debug + Send + Sync + 'static, C: Clone + fmt::Debug + PartialEq + JsonSchema, + Q: CustomQuery + DeserializeOwned, { fn execute( &self, - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, msg: Vec, @@ -349,7 +359,7 @@ where fn instantiate( &self, - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, msg: Vec, @@ -363,7 +373,7 @@ where )) } - fn query(&self, deps: Deps, env: Env, msg: Vec) -> AnyResult { + fn query(&self, deps: Deps, env: Env, msg: Vec) -> AnyResult { let msg: T3 = from_slice(&msg)?; (self.query_fn)(deps, env, msg.clone()) .map_err(anyhow::Error::from) @@ -374,7 +384,7 @@ where } // this returns an error if the contract doesn't implement sudo - fn sudo(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult> { + fn sudo(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult> { let msg = from_slice(&msg)?; match &self.sudo_fn { Some(sudo) => sudo(deps, env, msg).map_err(|err| anyhow!(err)), @@ -383,7 +393,7 @@ where } // this returns an error if the contract doesn't implement reply - fn reply(&self, deps: DepsMut, env: Env, reply_data: Reply) -> AnyResult> { + fn reply(&self, deps: DepsMut, env: Env, reply_data: Reply) -> AnyResult> { match &self.reply_fn { Some(reply) => reply(deps, env, reply_data).map_err(|err| anyhow!(err)), None => bail!("reply not implemented for contract"), @@ -391,7 +401,7 @@ where } // this returns an error if the contract doesn't implement migrate - fn migrate(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult> { + fn migrate(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult> { let msg = from_slice(&msg)?; match &self.migrate_fn { Some(migrate) => migrate(deps, env, msg).map_err(|err| anyhow!(err)), diff --git a/packages/multi-test/src/wasm.rs b/packages/multi-test/src/wasm.rs index 9a30d47e7..ce793c3af 100644 --- a/packages/multi-test/src/wasm.rs +++ b/packages/multi-test/src/wasm.rs @@ -99,7 +99,7 @@ pub trait Wasm { pub struct WasmKeeper { /// code is in-memory lookup that stands in for wasm code /// this can only be edited on the WasmRouter, and just read in caches - codes: HashMap>>, + codes: HashMap>>, /// Just markers to make type elision fork when using it as `Wasm` trait _p: std::marker::PhantomData, } @@ -180,7 +180,7 @@ where } impl WasmKeeper { - pub fn store_code(&mut self, code: Box>) -> usize { + pub fn store_code(&mut self, code: Box>) -> usize { let idx = self.codes.len() + 1; self.codes.insert(idx, code); idx @@ -706,7 +706,7 @@ where action: F, ) -> AnyResult where - F: FnOnce(&Box>, Deps, Env) -> AnyResult, + F: FnOnce(&Box>, Deps, Env) -> AnyResult, { let contract = self.load_contract(storage, &address)?; let handler = self @@ -734,7 +734,7 @@ where action: F, ) -> AnyResult where - F: FnOnce(&Box>, DepsMut, Env) -> AnyResult, + F: FnOnce(&Box>, DepsMut, Env) -> AnyResult, ExecC: DeserializeOwned, { let contract = self.load_contract(storage, &address)?;