From fb118da96d3ee8b00700333b4d12e737a4332e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Kuras?= Date: Thu, 9 Sep 2021 20:23:43 +0200 Subject: [PATCH 1/5] Removing dyn from Router --- packages/multi-test/src/app.rs | 359 ++++++++++++++-------- packages/multi-test/src/custom_handler.rs | 45 ++- packages/multi-test/src/wasm.rs | 168 ++++++---- 3 files changed, 378 insertions(+), 194 deletions(-) diff --git a/packages/multi-test/src/app.rs b/packages/multi-test/src/app.rs index 8d915350a..5b6cabc51 100644 --- a/packages/multi-test/src/app.rs +++ b/packages/multi-test/src/app.rs @@ -19,7 +19,6 @@ use crate::wasm::{ContractData, Wasm, WasmKeeper}; use crate::BankKeeper; use anyhow::Result as AnyResult; -use derivative::Derivative; pub fn next_block(block: &mut BlockInfo) { block.time = block.time.plus_seconds(5); @@ -29,27 +28,35 @@ pub fn next_block(block: &mut BlockInfo) { /// Router is a persisted state. You can query this. /// Execution generally happens on the RouterCache, which then can be atomically committed or rolled back. /// We offer .execute() as a wrapper around cache, execute, commit/rollback process. -/// -/// ExecC is the custom message returned init, handle, sudo (Response). -/// All contracts must return Response or Response. -/// -/// Also `ExecC` is the custom message which is handled by custom message handler. -/// -/// `QueryC` is custom query message handled by custom message handler. -pub struct App -where - ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, -{ - router: Router, +pub struct App< + Wasm = WasmKeeper, + Bank = BankKeeper, + Custom = PanickingCustomHandler, +> { + router: Router, api: Box, storage: Box, block: BlockInfo, } -impl Querier for App +impl + App, BankKeeper, PanickingCustomHandler> where - ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, - QueryC: CustomQuery + DeserializeOwned, + ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + QueryC: std::fmt::Debug + CustomQuery + DeserializeOwned + 'static, +{ + pub fn new() -> Self { + AppBuilder::new().build() + } +} + +impl Querier for App +where + CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, + WasmT: Wasm, + BankT: Bank, + CustomT: CustomHandler, { fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { self.router @@ -58,12 +65,15 @@ where } } -impl Executor for App +impl Executor for App where - ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, - QueryC: CustomQuery + DeserializeOwned, + CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, + WasmT: Wasm, + BankT: Bank, + CustomT: CustomHandler, { - fn execute(&mut self, sender: Addr, msg: CosmosMsg) -> AnyResult { + fn execute(&mut self, sender: Addr, msg: CosmosMsg) -> AnyResult { let mut all = self.execute_multi(sender, vec![msg])?; let res = all.pop().unwrap(); Ok(res) @@ -71,36 +81,89 @@ where } /// Utility to build App in stages. If particular items wont be set, defaults would be used -#[derive(Derivative)] -#[derivative(Default(bound = "", new = "true"))] -pub struct AppBuilder { - wasm: Option>>, - bank: Option>, +pub struct AppBuilder { + wasm: Wasm, + bank: Bank, api: Option>, storage: Option>, - custom: Option>>, + custom: Custom, block: Option, } -impl AppBuilder +impl + AppBuilder, BankKeeper, PanickingCustomHandler> where - ExecC: Debug + PartialEq + Clone + JsonSchema + 'static, - QueryC: Debug + CustomQuery + DeserializeOwned + 'static, + ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, { - /// Overwrites default wasm executor. Panic if already set. - #[track_caller] - pub fn with_wasm(mut self, wasm: impl Wasm + 'static) -> Self { - assert!(self.wasm.is_none(), "Wasm executor already overwritten"); - self.wasm = Some(Box::new(wasm)); - self + /// Creates builder with default components + pub fn new() -> Self { + Self { + wasm: WasmKeeper::::new(), + bank: BankKeeper::new(), + api: None, + storage: None, + custom: PanickingCustomHandler::::new(), + block: None, + } + } +} + +impl AppBuilder { + /// Overwrites default wasm executor. + /// + /// At this point it is needed that new wasm implements some `Wasm` trait, but it doesn't need + /// to be bound to Bank or Custom yet - as those may change. The cross-components validation is + /// done on final building. + /// + /// Also it is possible to completely abandon trait bounding here which would not be bad idea, + /// however it might make the message on build creepy in many cases, so as for properly build + /// `App` we always want `Wasm` to be `Wasm`, some checks are done early. + pub fn with_wasm>( + self, + wasm: NewWasm, + ) -> AppBuilder { + let AppBuilder { + bank, + api, + storage, + custom, + block, + .. + } = self; + + AppBuilder { + wasm, + bank, + api, + storage, + custom, + block, + } } /// Overwrites default bank interface - #[track_caller] - pub fn with_bank(mut self, bank: impl Bank + 'static) -> Self { - assert!(self.bank.is_none(), "Bank interface already overwritten"); - self.bank = Some(Box::new(bank)); - self + pub fn with_bank( + mut self, + bank: NewBank, + ) -> AppBuilder { + let AppBuilder { + wasm, + api, + storage, + custom, + block, + .. + } = self; + + AppBuilder { + wasm, + bank, + api, + storage, + custom, + block, + } } /// Overwrites default api interface @@ -123,11 +186,35 @@ where } /// Overwrites default custom messages handler - #[track_caller] - pub fn with_custom(mut self, custom: impl CustomHandler + 'static) -> Self { - assert!(self.custom.is_none(), "Custom handler already overwritten"); - self.custom = Some(Box::new(custom)); - self + /// + /// At this point it is needed that new custom implements some `CustomHandler` trait, but it doesn't need + /// to be bound to ExecC or QueryC yet - as those may change. The cross-components validation is + /// done on final building. + /// + /// Also it is possible to completely abandon trait bounding here which would not be bad idea, + /// however it might make the message on build creepy in many cases, so as for properly build + /// `App` we always want `Wasm` to be `Wasm`, some checks are done early. + pub fn with_custom( + self, + custom: NewCustom, + ) -> AppBuilder { + let AppBuilder { + wasm, + bank, + api, + storage, + block, + .. + } = self; + + AppBuilder { + wasm, + bank, + api, + storage, + custom, + block, + } } /// Overwrites default initial block @@ -141,17 +228,24 @@ where self } - pub fn build(self) -> App { - let wasm = self.wasm.unwrap_or_else(|| Box::new(WasmKeeper::new())); - let bank = self.bank.unwrap_or_else(|| Box::new(BankKeeper::new())); + /// Builds final `App`. At this point all components type have to be properly related to each + /// other. If there are some generics related compilation error make sure, that all components + /// are properly relating to each other. + pub fn build(self) -> App + where + WasmT: Wasm, + BankT: Bank, + CustomT: CustomHandler, + { let api = self.api.unwrap_or_else(|| Box::new(MockApi::default())); let storage = self.storage.unwrap_or_else(|| Box::new(MockStorage::new())); let block = self.block.unwrap_or_else(|| mock_env().block); - let custom = self - .custom - .unwrap_or_else(|| Box::new(PanickingCustomHandler)); - let router = Router { wasm, bank, custom }; + let router = Router { + wasm: self.wasm, + bank: self.bank, + custom: self.custom, + }; App { router, @@ -162,10 +256,13 @@ where } } -impl App +impl App where - ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, - QueryC: CustomQuery + DeserializeOwned, + CustomT::ExecC: std::fmt::Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, + CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, + WasmT: Wasm, + BankT: Bank, + CustomT: CustomHandler, { pub fn set_block(&mut self, block: BlockInfo) { self.block = block; @@ -193,7 +290,7 @@ where pub fn execute_multi( &mut self, sender: Addr, - msgs: Vec>, + msgs: Vec>, ) -> AnyResult> { // we need to do some caching of storage here, once in the entry point: // meaning, wrap current state, all writes go to a cache, only when execute @@ -222,7 +319,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.router.wasm.store_code(code) as u64 } @@ -251,23 +348,19 @@ where } } -pub struct Router { - pub(crate) wasm: Box>, - pub(crate) bank: Box, - pub(crate) custom: Box>, +pub struct Router { + pub(crate) wasm: Wasm, + pub(crate) bank: Bank, + pub(crate) custom: Custom, } -impl Router -where - ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, - QueryC: CustomQuery + DeserializeOwned, -{ +impl Router { pub fn querier<'a>( &'a self, api: &'a dyn Api, storage: &'a dyn Storage, block_info: &'a BlockInfo, - ) -> RouterQuerier<'a, ExecC, QueryC> { + ) -> RouterQuerier<'a, WasmT, BankT, CustomT> { RouterQuerier { router: self, api, @@ -284,8 +377,16 @@ where api: &dyn Api, storage: &dyn Storage, block: &BlockInfo, - request: QueryRequest, - ) -> AnyResult { + request: QueryRequest, + ) -> AnyResult + where + CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, + CustomT::ExecC: + std::fmt::Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, + WasmT: Wasm, + BankT: Bank, + CustomT: CustomHandler, + { match request { QueryRequest::Wasm(req) => { self.wasm @@ -303,8 +404,14 @@ where storage: &mut dyn Storage, block: &BlockInfo, sender: Addr, - msg: CosmosMsg, - ) -> AnyResult { + msg: CosmosMsg, + ) -> AnyResult + where + CustomT::ExecC: std::fmt::Debug + Clone + PartialEq + JsonSchema, + WasmT: Wasm, + BankT: Bank, + CustomT: CustomHandler, + { match msg { CosmosMsg::Wasm(msg) => self.wasm.execute(api, storage, &self, block, sender, msg), CosmosMsg::Bank(msg) => self.bank.execute(storage, sender, msg), @@ -314,22 +421,16 @@ where } } -pub struct RouterQuerier<'a, ExecC, QueryC> -where - ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, -{ - router: &'a Router, +pub struct RouterQuerier<'a, Wasm, Bank, Custom> { + router: &'a Router, api: &'a dyn Api, storage: &'a dyn Storage, block_info: &'a BlockInfo, } -impl<'a, ExecC, QueryC> RouterQuerier<'a, ExecC, QueryC> -where - ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, -{ +impl<'a, Wasm, Bank, Custom> RouterQuerier<'a, Wasm, Bank, Custom> { pub fn new( - router: &'a Router, + router: &'a Router, api: &'a dyn Api, storage: &'a dyn Storage, block_info: &'a BlockInfo, @@ -343,13 +444,16 @@ where } } -impl<'a, ExecC, QueryC> Querier for RouterQuerier<'a, ExecC, QueryC> +impl<'a, WasmT, BankT, CustomT> Querier for RouterQuerier<'a, WasmT, BankT, CustomT> where - ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, - QueryC: CustomQuery + DeserializeOwned, + CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, + WasmT: Wasm, + BankT: Bank, + CustomT: CustomHandler, { fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { - let request: QueryRequest = match from_slice(bin_request) { + let request: QueryRequest = match from_slice(bin_request) { Ok(v) => v, Err(e) => { return SystemResult::Err(SystemError::InvalidRequest { @@ -381,24 +485,23 @@ mod test { use super::*; - fn mock_app() -> App { - AppBuilder::new().build() - } - - fn custom_app() -> App { - AppBuilder::new().build() - } - - fn get_balance(app: &App, addr: &Addr) -> Vec + fn get_balance( + app: &App, + addr: &Addr, + ) -> Vec where - C: Clone + fmt::Debug + PartialEq + JsonSchema, + CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, + WasmT: Wasm, + BankT: Bank, + CustomT: CustomHandler, { app.wrap().query_all_balances(addr).unwrap() } #[test] fn update_block() { - let mut app = mock_app(); + let mut app = App::new(); let BlockInfo { time, height, .. } = app.block; app.update_block(next_block); @@ -409,7 +512,7 @@ mod test { #[test] fn send_tokens() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); let rcpt = Addr::unchecked("receiver"); @@ -450,7 +553,7 @@ mod test { #[test] fn simple_contract() { - let mut app = mock_app(); + let mut app = App::new(); // set personal balance let owner = Addr::unchecked("owner"); @@ -529,7 +632,7 @@ mod test { #[test] fn reflect_success() { - let mut app = custom_app(); + let mut app = App::new(); // set personal balance let owner = Addr::unchecked("owner"); @@ -626,7 +729,7 @@ mod test { #[test] fn reflect_error() { - let mut app = custom_app(); + let mut app = App::new(); // set personal balance let owner = Addr::unchecked("owner"); @@ -717,7 +820,7 @@ mod test { #[test] fn sudo_works() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); let init_funds = vec![coin(100, "eth")]; @@ -751,7 +854,7 @@ mod test { #[test] fn reflect_submessage_reply_works() { - let mut app = custom_app(); + let mut app = App::new(); // set personal balance let owner = Addr::unchecked("owner"); @@ -835,14 +938,17 @@ mod test { // TODO: check error? } - fn query_router( - router: &Router, + fn query_router( + router: &Router, api: &dyn Api, storage: &dyn Storage, rcpt: &Addr, ) -> Vec where - ExecC: Clone + fmt::Debug + PartialEq + JsonSchema, + CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema, + WasmT: Wasm, + BankT: Bank, + CustomT: CustomHandler, { let query = BankQuery::AllBalances { address: rcpt.into(), @@ -852,9 +958,12 @@ mod test { val.amount } - fn query_app(app: &App, rcpt: &Addr) -> Vec + fn query_app(app: &App, rcpt: &Addr) -> Vec where - C: Clone + fmt::Debug + PartialEq + JsonSchema, + CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema, + WasmT: Wasm, + BankT: Bank, + CustomT: CustomHandler, { let query = BankQuery::AllBalances { address: rcpt.into(), @@ -866,7 +975,7 @@ mod test { #[test] fn multi_level_bank_cache() { - let mut app = mock_app(); + let mut app = App::new(); // set personal balance let owner = Addr::unchecked("owner"); @@ -923,7 +1032,7 @@ mod test { // additional 20btc. Then beneficiary balance is checked - expeced value is 30btc. 10btc // would mean that sending tokens with message is not visible for this very message, and // 20btc means, that only such just send funds are visible. - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); let beneficiary = Addr::unchecked("beneficiary"); @@ -967,7 +1076,7 @@ mod test { // migrate fails if not admin // migrate succeeds if admin // check beneficiary updated - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); let beneficiary = Addr::unchecked("beneficiary"); @@ -1072,7 +1181,7 @@ mod test { #[test] fn no_submsg() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); @@ -1098,7 +1207,7 @@ mod test { #[test] fn single_submsg() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); @@ -1125,7 +1234,7 @@ mod test { #[test] fn single_submsg_no_reply() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); @@ -1152,7 +1261,7 @@ mod test { #[test] fn single_no_submsg_data() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); @@ -1179,7 +1288,7 @@ mod test { #[test] fn single_no_top_level_data() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); @@ -1205,7 +1314,7 @@ mod test { #[test] fn single_submsg_reply_returns_none() { - let mut app = custom_app(); + let mut app = App::new(); // set personal balance let owner = Addr::unchecked("owner"); @@ -1261,7 +1370,7 @@ mod test { #[test] fn multiple_submsg() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); @@ -1293,7 +1402,7 @@ mod test { #[test] fn multiple_submsg_no_reply() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); @@ -1325,7 +1434,7 @@ mod test { #[test] fn multiple_submsg_mixed() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); @@ -1357,7 +1466,7 @@ mod test { #[test] fn nested_submsg() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); @@ -1403,7 +1512,7 @@ mod test { #[test] fn empty_attribute_key() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); @@ -1433,7 +1542,7 @@ mod test { #[test] fn empty_attribute_value() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); @@ -1463,7 +1572,7 @@ mod test { #[test] fn empty_event_attribute_key() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); @@ -1492,7 +1601,7 @@ mod test { #[test] fn empty_event_attribute_value() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); @@ -1521,7 +1630,7 @@ mod test { #[test] fn too_short_event_type() { - let mut app = mock_app(); + let mut app = App::new(); let owner = Addr::unchecked("owner"); diff --git a/packages/multi-test/src/custom_handler.rs b/packages/multi-test/src/custom_handler.rs index f0eb399e3..88019fe54 100644 --- a/packages/multi-test/src/custom_handler.rs +++ b/packages/multi-test/src/custom_handler.rs @@ -1,8 +1,9 @@ -use cosmwasm_std::{Addr, Api, Binary, BlockInfo, Empty, Storage}; +use cosmwasm_std::{Addr, Api, Binary, BlockInfo, Storage}; use anyhow::Result as AnyResult; use derivative::Derivative; use std::cell::{Ref, RefCell}; +use std::marker::PhantomData; use std::ops::Deref; use std::rc::Rc; @@ -10,14 +11,20 @@ use crate::AppResponse; /// Custom message handler trait. Implementor of this trait is mocking environment behavior on /// given custom message. -pub trait CustomHandler { +pub trait CustomHandler { + /// Custom exec message for this handler + type ExecC; + + /// Custom query message for this handler + type QueryC; + fn execute( &self, api: &dyn Api, storage: &mut dyn Storage, block: &BlockInfo, sender: Addr, - msg: ExecC, + msg: Self::ExecC, ) -> AnyResult; fn query( @@ -25,26 +32,35 @@ pub trait CustomHandler { api: &dyn Api, storage: &dyn Storage, block: &BlockInfo, - msg: QueryC, + msg: Self::QueryC, ) -> AnyResult; } /// Custom handler implementation panicking on each call. Assuming, that unless specific behavior /// is implemented, custom messages should not be send. -pub(crate) struct PanickingCustomHandler; +pub struct PanickingCustomHandler(PhantomData, PhantomData); -impl CustomHandler for PanickingCustomHandler +impl PanickingCustomHandler { + pub fn new() -> Self { + PanickingCustomHandler(PhantomData, PhantomData) + } +} + +impl CustomHandler for PanickingCustomHandler where - ExecC: std::fmt::Debug, - QueryC: std::fmt::Debug, + Exec: std::fmt::Debug, + Query: std::fmt::Debug, { + type ExecC = Exec; + type QueryC = Query; + fn execute( &self, _api: &dyn Api, _storage: &mut dyn Storage, _block: &BlockInfo, sender: Addr, - msg: ExecC, + msg: Self::ExecC, ) -> AnyResult { panic!("Unexpected custom exec msg {:?} from {:?}", msg, sender) } @@ -54,7 +70,7 @@ where _api: &dyn Api, _storage: &dyn Storage, _block: &BlockInfo, - msg: QueryC, + msg: Self::QueryC, ) -> AnyResult { panic!("Unexpected custom query {:?}", msg) } @@ -99,14 +115,17 @@ impl CachingCustomHandler { } } -impl CustomHandler for CachingCustomHandler { +impl CustomHandler for CachingCustomHandler { + type ExecC = Exec; + type QueryC = Query; + fn execute( &self, _api: &dyn Api, _storage: &mut dyn Storage, _block: &BlockInfo, _sender: Addr, - msg: ExecC, + msg: Exec, ) -> AnyResult { self.state.execs.borrow_mut().push(msg); Ok(AppResponse::default()) @@ -117,7 +136,7 @@ impl CustomHandler for CachingCustomHandler AnyResult { self.state.queries.borrow_mut().push(msg); Ok(Binary::default()) diff --git a/packages/multi-test/src/wasm.rs b/packages/multi-test/src/wasm.rs index 66f3893ae..f9939a685 100644 --- a/packages/multi-test/src/wasm.rs +++ b/packages/multi-test/src/wasm.rs @@ -20,6 +20,7 @@ use crate::contracts::Contract; use crate::error::Error; use crate::executor::AppResponse; use crate::transactions::transactional; +use crate::{Bank, CustomHandler}; use cosmwasm_std::testing::mock_wasmd_attr; use anyhow::{anyhow, bail, Result as AnyResult}; @@ -46,10 +47,7 @@ pub struct ContractData { pub created: u64, } -pub trait Wasm -where - ExecC: Clone + fmt::Debug + PartialEq + JsonSchema, -{ +pub trait Wasm { /// Handles all WasmQuery requests fn query( &self, @@ -65,14 +63,16 @@ where &self, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, sender: Addr, msg: WasmMsg, - ) -> AnyResult; + ) -> AnyResult + where + Self: Sized; // Add a new contract. Must be done on the base object, when no contracts running - fn store_code(&mut self, code: Box>) -> usize; + fn store_code(&mut self, code: Box>) -> usize; // Helper for querying for specific contract data fn contract_data(&self, storage: &dyn Storage, address: &Addr) -> AnyResult; @@ -83,13 +83,15 @@ where api: &dyn Api, contract_addr: Addr, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, msg: Vec, - ) -> AnyResult; + ) -> AnyResult + where + Self: Sized; } -pub struct WasmKeeper { +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>>, @@ -106,10 +108,12 @@ impl Default for WasmKeeper { } } -impl Wasm for WasmKeeper +impl Wasm for WasmKeeper where - ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, - QueryC: CustomQuery + DeserializeOwned, + CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, + BankT: Bank, + CustomT: CustomHandler, { fn query( &self, @@ -136,7 +140,7 @@ where &self, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, sender: Addr, msg: WasmMsg, @@ -148,7 +152,7 @@ where self.process_response(api, router, storage, block, resender, res, msgs) } - fn store_code(&mut self, code: Box>) -> usize { + fn store_code(&mut self, code: Box>) -> usize { let idx = self.codes.len() + 1; self.codes.insert(idx, code); idx @@ -163,7 +167,7 @@ where api: &dyn Api, contract: Addr, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, msg: Vec, ) -> AnyResult { @@ -177,8 +181,8 @@ where impl WasmKeeper where - ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, - QueryC: CustomQuery + DeserializeOwned, + ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, { pub fn new() -> Self { Self::default() @@ -209,16 +213,21 @@ where data.into() } - fn send>( + fn send( &self, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, sender: T, recipient: String, amount: &[Coin], - ) -> AnyResult { + ) -> AnyResult + where + T: Into, + BankT: Bank, + CustomT: CustomHandler, + { if !amount.is_empty() { let msg = BankMsg::Send { to_address: recipient, @@ -232,15 +241,21 @@ where } // this returns the contract address as well, so we can properly resend the data - fn execute_wasm( + fn execute_wasm( &self, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, sender: Addr, wasm_msg: WasmMsg, - ) -> AnyResult<(Addr, Response, Event)> { + ) -> AnyResult<(Addr, Response, Event)> + where + BankT: Bank, + CustomT: CustomHandler, + ExecC: DeserializeOwned, + QueryC: 'static, + { match wasm_msg { WasmMsg::Execute { contract_addr, @@ -371,15 +386,19 @@ where /// /// The `data` on `AppResponse` is data returned from `reply` call, not from execution of /// submessage itself. In case if `reply` is not called, no `data` is set. - fn execute_submsg( + fn execute_submsg( &self, api: &dyn Api, - router: &Router, + router: &Router, storage: &mut dyn Storage, block: &BlockInfo, contract: Addr, msg: SubMsg, - ) -> AnyResult { + ) -> AnyResult + where + BankT: Bank, + CustomT: CustomHandler, + { let SubMsg { msg, id, reply_on, .. } = msg; @@ -426,15 +445,19 @@ where } } - fn _reply( + fn _reply( &self, api: &dyn Api, - router: &Router, + router: &Router, storage: &mut dyn Storage, block: &BlockInfo, contract: Addr, reply: Reply, - ) -> AnyResult { + ) -> AnyResult + where + BankT: Bank, + CustomT: CustomHandler, + { let ok_attr = if reply.result.is_ok() { "handle_success" } else { @@ -495,16 +518,20 @@ where (app, messages) } - fn process_response( + fn process_response( &self, api: &dyn Api, - router: &Router, + router: &Router, storage: &mut dyn Storage, block: &BlockInfo, contract: Addr, response: AppResponse, messages: Vec>, - ) -> AnyResult { + ) -> AnyResult + where + BankT: Bank, + CustomT: CustomHandler, + { let AppResponse { mut events, data } = response; // recurse in all messages @@ -547,16 +574,22 @@ where Ok(addr) } - pub fn call_execute( + pub fn call_execute( &self, api: &dyn Api, storage: &mut dyn Storage, address: Addr, - router: &Router, + router: &Router, block: &BlockInfo, info: MessageInfo, msg: Vec, - ) -> AnyResult> { + ) -> AnyResult> + where + BankT: Bank, + CustomT: CustomHandler, + ExecC: DeserializeOwned, + QueryC: 'static, + { Self::verify_response(self.with_storage( api, storage, @@ -567,16 +600,22 @@ where )?) } - pub fn call_instantiate( + pub fn call_instantiate( &self, address: Addr, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, info: MessageInfo, msg: Vec, - ) -> AnyResult> { + ) -> AnyResult> + where + BankT: Bank, + CustomT: CustomHandler, + ExecC: DeserializeOwned, + QueryC: 'static, + { Self::verify_response(self.with_storage( api, storage, @@ -587,15 +626,19 @@ where )?) } - pub fn call_reply( + pub fn call_reply( &self, address: Addr, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, reply: Reply, - ) -> AnyResult> { + ) -> AnyResult> + where + BankT: Bank, + CustomT: CustomHandler, + { Self::verify_response(self.with_storage( api, storage, @@ -606,15 +649,19 @@ where )?) } - pub fn call_sudo( + pub fn call_sudo( &self, address: Addr, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, msg: Vec, - ) -> AnyResult> { + ) -> AnyResult> + where + BankT: Bank, + CustomT: CustomHandler, + { Self::verify_response(self.with_storage( api, storage, @@ -625,15 +672,19 @@ where )?) } - pub fn call_migrate( + pub fn call_migrate( &self, address: Addr, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, msg: Vec, - ) -> AnyResult> { + ) -> AnyResult> + where + BankT: Bank, + CustomT: CustomHandler, + { Self::verify_response(self.with_storage( api, storage, @@ -681,17 +732,21 @@ where action(handler, deps, env) } - fn with_storage( + fn with_storage( &self, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, address: Addr, action: F, ) -> AnyResult where F: FnOnce(&Box>, DepsMut, Env) -> AnyResult, + BankT: Bank, + CustomT: CustomHandler, + ExecC: DeserializeOwned, + QueryC: 'static, { let contract = self.load_contract(storage, &address)?; let handler = self @@ -864,15 +919,16 @@ mod test { use super::*; - fn mock_keeper() -> WasmKeeper { + fn mock_keeper() -> WasmKeeper { WasmKeeper::new() } - fn mock_router() -> Router { + fn mock_router( + ) -> Router, BankKeeper, PanickingCustomHandler> { Router { - wasm: Box::new(WasmKeeper::new()), - bank: Box::new(BankKeeper::new()), - custom: Box::new(PanickingCustomHandler), + wasm: WasmKeeper::new(), + bank: BankKeeper::new(), + custom: PanickingCustomHandler::new(), } } @@ -1045,7 +1101,7 @@ mod test { } fn assert_payout( - router: &WasmKeeper, + router: &WasmKeeper, storage: &mut dyn Storage, contract_addr: &Addr, payout: &Coin, From 39b2aa3cfe877f95001098aaa3c929d6b59323bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Kuras?= Date: Mon, 13 Sep 2021 14:13:50 +0200 Subject: [PATCH 2/5] Untangling Wasm trait in multitest --- packages/multi-test/src/app.rs | 140 +++++++++++++++++++------------- packages/multi-test/src/lib.rs | 2 +- packages/multi-test/src/wasm.rs | 100 +++++++++++------------ 3 files changed, 133 insertions(+), 109 deletions(-) diff --git a/packages/multi-test/src/app.rs b/packages/multi-test/src/app.rs index 5b6cabc51..d69884c75 100644 --- a/packages/multi-test/src/app.rs +++ b/packages/multi-test/src/app.rs @@ -25,36 +25,46 @@ pub fn next_block(block: &mut BlockInfo) { block.height += 1; } +/// Type alias for default build `App` to make its storing simpler in typical scenario +pub type BasicApp = + App, WasmKeeper>; + /// Router is a persisted state. You can query this. /// Execution generally happens on the RouterCache, which then can be atomically committed or rolled back. /// We offer .execute() as a wrapper around cache, execute, commit/rollback process. pub struct App< - Wasm = WasmKeeper, Bank = BankKeeper, Custom = PanickingCustomHandler, + Wasm = WasmKeeper, > { - router: Router, + router: Router, api: Box, storage: Box, block: BlockInfo, } -impl - App, BankKeeper, PanickingCustomHandler> -where - ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, - QueryC: std::fmt::Debug + CustomQuery + DeserializeOwned + 'static, -{ +impl BasicApp { + /// Creates new default `App` implementation working with Empty custom messages. pub fn new() -> Self { AppBuilder::new().build() } } -impl Querier for App +/// Creates new default `App` implementation working with customized exec and query messages. +/// Outside of `App` implementation to make type elision better. +pub fn custom_app() -> BasicApp +where + ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + QueryC: Debug + CustomQuery + DeserializeOwned + 'static, +{ + AppBuilder::new_custom().build() +} + +impl Querier for App where CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, - WasmT: Wasm, + WasmT: Wasm, BankT: Bank, CustomT: CustomHandler, { @@ -65,11 +75,11 @@ where } } -impl Executor for App +impl Executor for App where CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, - WasmT: Wasm, + WasmT: Wasm, BankT: Bank, CustomT: CustomHandler, { @@ -81,7 +91,7 @@ where } /// Utility to build App in stages. If particular items wont be set, defaults would be used -pub struct AppBuilder { +pub struct AppBuilder { wasm: Wasm, bank: Bank, api: Option>, @@ -90,26 +100,41 @@ pub struct AppBuilder { block: Option, } +impl AppBuilder, WasmKeeper> { + /// Creates builder with default components working with empty exec and query messages. + pub fn new() -> Self { + AppBuilder { + wasm: WasmKeeper::new(), + bank: BankKeeper::new(), + api: None, + storage: None, + custom: PanickingCustomHandler::new(), + block: None, + } + } +} + impl - AppBuilder, BankKeeper, PanickingCustomHandler> + AppBuilder, WasmKeeper> where - ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, - QueryC: CustomQuery + DeserializeOwned + 'static, + ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + QueryC: Debug + CustomQuery + DeserializeOwned + 'static, { - /// Creates builder with default components - pub fn new() -> Self { - Self { - wasm: WasmKeeper::::new(), + /// Creates builder with default components designed to work with custom exec and query + /// messages. + pub fn new_custom() -> Self { + AppBuilder { + wasm: WasmKeeper::new(), bank: BankKeeper::new(), api: None, storage: None, - custom: PanickingCustomHandler::::new(), + custom: PanickingCustomHandler::new(), block: None, } } } -impl AppBuilder { +impl AppBuilder { /// Overwrites default wasm executor. /// /// At this point it is needed that new wasm implements some `Wasm` trait, but it doesn't need @@ -119,10 +144,10 @@ impl AppBuilder { /// Also it is possible to completely abandon trait bounding here which would not be bad idea, /// however it might make the message on build creepy in many cases, so as for properly build /// `App` we always want `Wasm` to be `Wasm`, some checks are done early. - pub fn with_wasm>( + pub fn with_wasm>( self, wasm: NewWasm, - ) -> AppBuilder { + ) -> AppBuilder { let AppBuilder { bank, api, @@ -143,10 +168,7 @@ impl AppBuilder { } /// Overwrites default bank interface - pub fn with_bank( - mut self, - bank: NewBank, - ) -> AppBuilder { + pub fn with_bank(self, bank: NewBank) -> AppBuilder { let AppBuilder { wasm, api, @@ -197,7 +219,7 @@ impl AppBuilder { pub fn with_custom( self, custom: NewCustom, - ) -> AppBuilder { + ) -> AppBuilder { let AppBuilder { wasm, bank, @@ -231,11 +253,11 @@ impl AppBuilder { /// Builds final `App`. At this point all components type have to be properly related to each /// other. If there are some generics related compilation error make sure, that all components /// are properly relating to each other. - pub fn build(self) -> App + pub fn build(self) -> App where - WasmT: Wasm, BankT: Bank, CustomT: CustomHandler, + WasmT: Wasm, { let api = self.api.unwrap_or_else(|| Box::new(MockApi::default())); let storage = self.storage.unwrap_or_else(|| Box::new(MockStorage::new())); @@ -256,11 +278,11 @@ impl AppBuilder { } } -impl App +impl App where CustomT::ExecC: std::fmt::Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, - WasmT: Wasm, + WasmT: Wasm, BankT: Bank, CustomT: CustomHandler, { @@ -348,19 +370,19 @@ where } } -pub struct Router { +pub struct Router { pub(crate) wasm: Wasm, pub(crate) bank: Bank, pub(crate) custom: Custom, } -impl Router { +impl Router { pub fn querier<'a>( &'a self, api: &'a dyn Api, storage: &'a dyn Storage, block_info: &'a BlockInfo, - ) -> RouterQuerier<'a, WasmT, BankT, CustomT> { + ) -> RouterQuerier<'a, BankT, CustomT, WasmT> { RouterQuerier { router: self, api, @@ -383,7 +405,7 @@ impl Router { CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, CustomT::ExecC: std::fmt::Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, - WasmT: Wasm, + WasmT: Wasm, BankT: Bank, CustomT: CustomHandler, { @@ -408,7 +430,7 @@ impl Router { ) -> AnyResult where CustomT::ExecC: std::fmt::Debug + Clone + PartialEq + JsonSchema, - WasmT: Wasm, + WasmT: Wasm, BankT: Bank, CustomT: CustomHandler, { @@ -421,16 +443,16 @@ impl Router { } } -pub struct RouterQuerier<'a, Wasm, Bank, Custom> { - router: &'a Router, +pub struct RouterQuerier<'a, Bank, Custom, Wasm> { + router: &'a Router, api: &'a dyn Api, storage: &'a dyn Storage, block_info: &'a BlockInfo, } -impl<'a, Wasm, Bank, Custom> RouterQuerier<'a, Wasm, Bank, Custom> { +impl<'a, Bank, Custom, Wasm> RouterQuerier<'a, Bank, Custom, Wasm> { pub fn new( - router: &'a Router, + router: &'a Router, api: &'a dyn Api, storage: &'a dyn Storage, block_info: &'a BlockInfo, @@ -444,11 +466,11 @@ impl<'a, Wasm, Bank, Custom> RouterQuerier<'a, Wasm, Bank, Custom> { } } -impl<'a, WasmT, BankT, CustomT> Querier for RouterQuerier<'a, WasmT, BankT, CustomT> +impl<'a, BankT, CustomT, WasmT> Querier for RouterQuerier<'a, BankT, CustomT, WasmT> where CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, - WasmT: Wasm, + WasmT: Wasm, BankT: Bank, CustomT: CustomHandler, { @@ -485,14 +507,14 @@ mod test { use super::*; - fn get_balance( - app: &App, + fn get_balance( + app: &App, addr: &Addr, ) -> Vec where CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, - WasmT: Wasm, + WasmT: Wasm, BankT: Bank, CustomT: CustomHandler, { @@ -632,7 +654,7 @@ mod test { #[test] fn reflect_success() { - let mut app = App::new(); + let mut app = custom_app::(); // set personal balance let owner = Addr::unchecked("owner"); @@ -729,7 +751,7 @@ mod test { #[test] fn reflect_error() { - let mut app = App::new(); + let mut app = custom_app::(); // set personal balance let owner = Addr::unchecked("owner"); @@ -854,7 +876,7 @@ mod test { #[test] fn reflect_submessage_reply_works() { - let mut app = App::new(); + let mut app = custom_app::(); // set personal balance let owner = Addr::unchecked("owner"); @@ -938,15 +960,15 @@ mod test { // TODO: check error? } - fn query_router( - router: &Router, + fn query_router( + router: &Router, api: &dyn Api, storage: &dyn Storage, rcpt: &Addr, ) -> Vec where CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema, - WasmT: Wasm, + WasmT: Wasm, BankT: Bank, CustomT: CustomHandler, { @@ -958,10 +980,12 @@ mod test { val.amount } - fn query_app(app: &App, rcpt: &Addr) -> Vec + fn query_app(app: &App, rcpt: &Addr) -> Vec where - CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema, - WasmT: Wasm, + CustomT::ExecC: + std::fmt::Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, + CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, + WasmT: Wasm, BankT: Bank, CustomT: CustomHandler, { @@ -1314,7 +1338,7 @@ mod test { #[test] fn single_submsg_reply_returns_none() { - let mut app = App::new(); + let mut app = custom_app::(); // set personal balance let owner = Addr::unchecked("owner"); @@ -1669,7 +1693,7 @@ mod test { let custom_handler = CachingCustomHandler::::new(); let custom_handler_state = custom_handler.state(); - let mut app = AppBuilder::new() + let mut app = AppBuilder::new_custom() .with_api(api) .with_custom(custom_handler) .build(); diff --git a/packages/multi-test/src/lib.rs b/packages/multi-test/src/lib.rs index b3d83e37e..1c1e0fec4 100644 --- a/packages/multi-test/src/lib.rs +++ b/packages/multi-test/src/lib.rs @@ -16,7 +16,7 @@ mod test_helpers; mod transactions; mod wasm; -pub use crate::app::{next_block, App, AppBuilder, Router}; +pub use crate::app::{custom_app, next_block, App, AppBuilder, BasicApp, Router}; pub use crate::bank::{Bank, BankKeeper}; pub use crate::contracts::{Contract, ContractWrapper}; pub use crate::custom_handler::CustomHandler; diff --git a/packages/multi-test/src/wasm.rs b/packages/multi-test/src/wasm.rs index f9939a685..b37add054 100644 --- a/packages/multi-test/src/wasm.rs +++ b/packages/multi-test/src/wasm.rs @@ -4,8 +4,8 @@ use std::ops::Deref; use cosmwasm_std::{ Addr, Api, Attribute, BankMsg, Binary, BlockInfo, Coin, ContractInfo, ContractResult, - CustomQuery, Deps, DepsMut, Empty, Env, Event, MessageInfo, Order, Querier, QuerierWrapper, - Reply, ReplyOn, Response, Storage, SubMsg, SubMsgExecutionResponse, WasmMsg, WasmQuery, + CustomQuery, Deps, DepsMut, Env, Event, MessageInfo, Order, Querier, QuerierWrapper, Reply, + ReplyOn, Response, Storage, SubMsg, SubMsgExecutionResponse, WasmMsg, WasmQuery, }; use cosmwasm_storage::{prefixed, prefixed_read, PrefixedStorage, ReadonlyPrefixedStorage}; use prost::Message; @@ -47,7 +47,7 @@ pub struct ContractData { pub created: u64, } -pub trait Wasm { +pub trait Wasm { /// Handles all WasmQuery requests fn query( &self, @@ -59,61 +59,63 @@ pub trait Wasm { ) -> AnyResult; /// Handles all WasmMsg messages - fn execute( + fn execute( &self, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, sender: Addr, msg: WasmMsg, ) -> AnyResult where - Self: Sized; + Self: Sized, + BankT: Bank, + CustomT: CustomHandler; // Add a new contract. Must be done on the base object, when no contracts running - fn store_code(&mut self, code: Box>) -> usize; + fn store_code(&mut self, code: Box>) -> usize; // Helper for querying for specific contract data fn contract_data(&self, storage: &dyn Storage, address: &Addr) -> AnyResult; /// Admin interface, cannot be called via CosmosMsg - fn sudo( + fn sudo( &self, api: &dyn Api, contract_addr: Addr, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, msg: Vec, ) -> AnyResult where - Self: Sized; + Self: Sized, + BankT: Bank, + CustomT: CustomHandler; } 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>>, - /// Just marker to make type elision fork when using it as `Wasm` trait - _q: std::marker::PhantomData, + /// Just markers to make type elision fork when using it as `Wasm` trait + _p: std::marker::PhantomData<(ExecC, QueryC)>, } impl Default for WasmKeeper { fn default() -> Self { Self { codes: HashMap::default(), - _q: std::marker::PhantomData, + _p: std::marker::PhantomData, } } } -impl Wasm for WasmKeeper +impl Wasm for WasmKeeper where - CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, - CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, - BankT: Bank, - CustomT: CustomHandler, + ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, { fn query( &self, @@ -136,15 +138,19 @@ where } } - fn execute( + fn execute( &self, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, sender: Addr, msg: WasmMsg, - ) -> AnyResult { + ) -> AnyResult + where + BankT: Bank, + CustomT: CustomHandler, + { let (resender, res, custom_event) = self.execute_wasm(api, storage, router, block, sender, msg)?; @@ -152,7 +158,7 @@ where self.process_response(api, router, storage, block, resender, res, msgs) } - fn store_code(&mut self, code: Box>) -> usize { + fn store_code(&mut self, code: Box>) -> usize { let idx = self.codes.len() + 1; self.codes.insert(idx, code); idx @@ -162,15 +168,19 @@ where self.load_contract(storage, address) } - fn sudo( + fn sudo( &self, api: &dyn Api, contract: Addr, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, msg: Vec, - ) -> AnyResult { + ) -> AnyResult + where + BankT: Bank, + CustomT: CustomHandler, + { let custom_event = Event::new("sudo").add_attribute(CONTRACT_ATTR, &contract); let res = self.call_sudo(contract.clone(), api, storage, router, block, msg)?; @@ -217,7 +227,7 @@ where &self, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, sender: T, recipient: String, @@ -245,7 +255,7 @@ where &self, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, sender: Addr, wasm_msg: WasmMsg, @@ -253,8 +263,6 @@ where where BankT: Bank, CustomT: CustomHandler, - ExecC: DeserializeOwned, - QueryC: 'static, { match wasm_msg { WasmMsg::Execute { @@ -389,7 +397,7 @@ where fn execute_submsg( &self, api: &dyn Api, - router: &Router, + router: &Router, storage: &mut dyn Storage, block: &BlockInfo, contract: Addr, @@ -448,7 +456,7 @@ where fn _reply( &self, api: &dyn Api, - router: &Router, + router: &Router, storage: &mut dyn Storage, block: &BlockInfo, contract: Addr, @@ -521,7 +529,7 @@ where fn process_response( &self, api: &dyn Api, - router: &Router, + router: &Router, storage: &mut dyn Storage, block: &BlockInfo, contract: Addr, @@ -579,7 +587,7 @@ where api: &dyn Api, storage: &mut dyn Storage, address: Addr, - router: &Router, + router: &Router, block: &BlockInfo, info: MessageInfo, msg: Vec, @@ -587,8 +595,6 @@ where where BankT: Bank, CustomT: CustomHandler, - ExecC: DeserializeOwned, - QueryC: 'static, { Self::verify_response(self.with_storage( api, @@ -605,7 +611,7 @@ where address: Addr, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, info: MessageInfo, msg: Vec, @@ -613,8 +619,6 @@ where where BankT: Bank, CustomT: CustomHandler, - ExecC: DeserializeOwned, - QueryC: 'static, { Self::verify_response(self.with_storage( api, @@ -631,7 +635,7 @@ where address: Addr, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, reply: Reply, ) -> AnyResult> @@ -654,7 +658,7 @@ where address: Addr, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, msg: Vec, ) -> AnyResult> @@ -677,7 +681,7 @@ where address: Addr, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, msg: Vec, ) -> AnyResult> @@ -736,7 +740,7 @@ where &self, api: &dyn Api, storage: &mut dyn Storage, - router: &Router, + router: &Router, block: &BlockInfo, address: Addr, action: F, @@ -919,12 +923,8 @@ mod test { use super::*; - fn mock_keeper() -> WasmKeeper { - WasmKeeper::new() - } - fn mock_router( - ) -> Router, BankKeeper, PanickingCustomHandler> { + ) -> Router, WasmKeeper> { Router { wasm: WasmKeeper::new(), bank: BankKeeper::new(), @@ -936,7 +936,7 @@ mod test { fn register_contract() { let api = MockApi::default(); let mut wasm_storage = MockStorage::new(); - let mut keeper = mock_keeper(); + let mut keeper = WasmKeeper::new(); let block = mock_env().block; let code_id = keeper.store_code(error::contract()); @@ -1026,7 +1026,7 @@ mod test { #[test] fn contract_send_coins() { let api = MockApi::default(); - let mut keeper = mock_keeper(); + let mut keeper = WasmKeeper::new(); let block = mock_env().block; let code_id = keeper.store_code(payout::contract()); @@ -1137,7 +1137,7 @@ mod test { #[test] fn multi_level_wasm_cache() { let api = MockApi::default(); - let mut keeper = mock_keeper(); + let mut keeper = WasmKeeper::new(); let block = mock_env().block; let code_id = keeper.store_code(payout::contract()); From ecd8ab3c7b68ea7193638d766eb73339ff9e571f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Kuras?= Date: Mon, 13 Sep 2021 14:28:27 +0200 Subject: [PATCH 3/5] Abstracting out Api in multitest App --- packages/multi-test/src/app.rs | 99 ++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 33 deletions(-) diff --git a/packages/multi-test/src/app.rs b/packages/multi-test/src/app.rs index d69884c75..217329c78 100644 --- a/packages/multi-test/src/app.rs +++ b/packages/multi-test/src/app.rs @@ -27,18 +27,19 @@ pub fn next_block(block: &mut BlockInfo) { /// Type alias for default build `App` to make its storing simpler in typical scenario pub type BasicApp = - App, WasmKeeper>; + App, WasmKeeper>; /// Router is a persisted state. You can query this. /// Execution generally happens on the RouterCache, which then can be atomically committed or rolled back. /// We offer .execute() as a wrapper around cache, execute, commit/rollback process. pub struct App< Bank = BankKeeper, + Api = MockApi, Custom = PanickingCustomHandler, Wasm = WasmKeeper, > { router: Router, - api: Box, + api: Api, storage: Box, block: BlockInfo, } @@ -60,27 +61,29 @@ where AppBuilder::new_custom().build() } -impl Querier for App +impl Querier for App where CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, + ApiT: Api, CustomT: CustomHandler, { fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { self.router - .querier(&*self.api, &*self.storage, &self.block) + .querier(&self.api, &*self.storage, &self.block) .raw_query(bin_request) } } -impl Executor for App +impl Executor for App where CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, + ApiT: Api, CustomT: CustomHandler, { fn execute(&mut self, sender: Addr, msg: CosmosMsg) -> AnyResult { @@ -91,22 +94,24 @@ where } /// Utility to build App in stages. If particular items wont be set, defaults would be used -pub struct AppBuilder { +pub struct AppBuilder { wasm: Wasm, bank: Bank, - api: Option>, + api: Api, storage: Option>, custom: Custom, block: Option, } -impl AppBuilder, WasmKeeper> { +impl + AppBuilder, WasmKeeper> +{ /// Creates builder with default components working with empty exec and query messages. pub fn new() -> Self { AppBuilder { wasm: WasmKeeper::new(), bank: BankKeeper::new(), - api: None, + api: MockApi::default(), storage: None, custom: PanickingCustomHandler::new(), block: None, @@ -115,7 +120,12 @@ impl AppBuilder, WasmKeeper - AppBuilder, WasmKeeper> + AppBuilder< + BankKeeper, + MockApi, + PanickingCustomHandler, + WasmKeeper, + > where ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, QueryC: Debug + CustomQuery + DeserializeOwned + 'static, @@ -126,7 +136,7 @@ where AppBuilder { wasm: WasmKeeper::new(), bank: BankKeeper::new(), - api: None, + api: MockApi::default(), storage: None, custom: PanickingCustomHandler::new(), block: None, @@ -134,7 +144,7 @@ where } } -impl AppBuilder { +impl AppBuilder { /// Overwrites default wasm executor. /// /// At this point it is needed that new wasm implements some `Wasm` trait, but it doesn't need @@ -147,7 +157,7 @@ impl AppBuilder { pub fn with_wasm>( self, wasm: NewWasm, - ) -> AppBuilder { + ) -> AppBuilder { let AppBuilder { bank, api, @@ -168,7 +178,10 @@ impl AppBuilder { } /// Overwrites default bank interface - pub fn with_bank(self, bank: NewBank) -> AppBuilder { + pub fn with_bank( + self, + bank: NewBank, + ) -> AppBuilder { let AppBuilder { wasm, api, @@ -189,11 +202,24 @@ impl AppBuilder { } /// Overwrites default api interface - #[track_caller] - pub fn with_api(mut self, api: impl Api + 'static) -> Self { - assert!(self.api.is_none(), "API interface already overwritten"); - self.api = Some(Box::new(api)); - self + pub fn with_api(self, api: NewApi) -> AppBuilder { + let AppBuilder { + wasm, + bank, + storage, + custom, + block, + .. + } = self; + + AppBuilder { + wasm, + bank, + api, + storage, + custom, + block, + } } /// Overwrites default storage interface @@ -219,7 +245,7 @@ impl AppBuilder { pub fn with_custom( self, custom: NewCustom, - ) -> AppBuilder { + ) -> AppBuilder { let AppBuilder { wasm, bank, @@ -253,13 +279,14 @@ impl AppBuilder { /// Builds final `App`. At this point all components type have to be properly related to each /// other. If there are some generics related compilation error make sure, that all components /// are properly relating to each other. - pub fn build(self) -> App + pub fn build(self) -> App where BankT: Bank, + ApiT: Api, CustomT: CustomHandler, WasmT: Wasm, { - let api = self.api.unwrap_or_else(|| Box::new(MockApi::default())); + let api = self.api; let storage = self.storage.unwrap_or_else(|| Box::new(MockStorage::new())); let block = self.block.unwrap_or_else(|| mock_env().block); @@ -278,12 +305,13 @@ impl AppBuilder { } } -impl App +impl App where CustomT::ExecC: std::fmt::Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, + ApiT: Api, CustomT: CustomHandler, { pub fn set_block(&mut self, block: BlockInfo) { @@ -327,7 +355,7 @@ where transactional(&mut **storage, |write_cache, _| { msgs.into_iter() - .map(|msg| router.execute(&**api, write_cache, block, sender.clone(), msg)) + .map(|msg| router.execute(&*api, write_cache, block, sender.clone(), msg)) .collect() }) } @@ -360,7 +388,7 @@ where ) -> AnyResult { let msg = to_vec(msg)?; self.router.wasm.sudo( - &*self.api, + &self.api, contract_addr.into(), &mut *self.storage, &self.router, @@ -507,8 +535,8 @@ mod test { use super::*; - fn get_balance( - app: &App, + fn get_balance( + app: &App, addr: &Addr, ) -> Vec where @@ -516,6 +544,7 @@ mod test { CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, + ApiT: Api, CustomT: CustomHandler, { app.wrap().query_all_balances(addr).unwrap() @@ -980,13 +1009,17 @@ mod test { val.amount } - fn query_app(app: &App, rcpt: &Addr) -> Vec + fn query_app( + app: &App, + rcpt: &Addr, + ) -> Vec where CustomT::ExecC: std::fmt::Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, + ApiT: Api, CustomT: CustomHandler, { let query = BankQuery::AllBalances { @@ -1014,11 +1047,11 @@ mod test { amount: coins(25, "eth"), }; app.router - .execute(&*app.api, &mut cache, &app.block, owner.clone(), msg.into()) + .execute(&app.api, &mut cache, &app.block, owner.clone(), msg.into()) .unwrap(); // shows up in cache - let cached_rcpt = query_router(&app.router, &*app.api, &cache, &rcpt); + let cached_rcpt = query_router(&app.router, &app.api, &cache, &rcpt); assert_eq!(coins(25, "eth"), cached_rcpt); let router_rcpt = query_app(&app, &rcpt); assert_eq!(router_rcpt, vec![]); @@ -1030,13 +1063,13 @@ mod test { amount: coins(12, "eth"), }; app.router - .execute(&*app.api, cache2, &app.block, owner, msg.into()) + .execute(&app.api, cache2, &app.block, owner, msg.into()) .unwrap(); // shows up in 2nd cache - let cached_rcpt = query_router(&app.router, &*app.api, read, &rcpt); + let cached_rcpt = query_router(&app.router, &app.api, read, &rcpt); assert_eq!(coins(25, "eth"), cached_rcpt); - let cached2_rcpt = query_router(&app.router, &*app.api, cache2, &rcpt); + let cached2_rcpt = query_router(&app.router, &app.api, cache2, &rcpt); assert_eq!(coins(37, "eth"), cached2_rcpt); Ok(()) }) From 4084781aa40e3d3a7b7093717d1315a03219b018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Kuras?= Date: Mon, 13 Sep 2021 15:06:25 +0200 Subject: [PATCH 4/5] Abstracting out Storage in multitest App, clippization --- packages/multi-test/src/app.rs | 151 ++++++++++++++-------- packages/multi-test/src/custom_handler.rs | 6 + 2 files changed, 105 insertions(+), 52 deletions(-) diff --git a/packages/multi-test/src/app.rs b/packages/multi-test/src/app.rs index 217329c78..93fb30ba2 100644 --- a/packages/multi-test/src/app.rs +++ b/packages/multi-test/src/app.rs @@ -26,8 +26,13 @@ pub fn next_block(block: &mut BlockInfo) { } /// Type alias for default build `App` to make its storing simpler in typical scenario -pub type BasicApp = - App, WasmKeeper>; +pub type BasicApp = App< + BankKeeper, + MockApi, + MockStorage, + PanickingCustomHandler, + WasmKeeper, +>; /// Router is a persisted state. You can query this. /// Execution generally happens on the RouterCache, which then can be atomically committed or rolled back. @@ -35,15 +40,22 @@ pub type BasicApp = pub struct App< Bank = BankKeeper, Api = MockApi, + Storage = MockStorage, Custom = PanickingCustomHandler, Wasm = WasmKeeper, > { router: Router, api: Api, - storage: Box, + storage: Storage, block: BlockInfo, } +impl Default for BasicApp { + fn default() -> Self { + Self::new() + } +} + impl BasicApp { /// Creates new default `App` implementation working with Empty custom messages. pub fn new() -> Self { @@ -61,29 +73,32 @@ where AppBuilder::new_custom().build() } -impl Querier for App +impl Querier for App where CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, ApiT: Api, + StorageT: Storage, CustomT: CustomHandler, { fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { self.router - .querier(&self.api, &*self.storage, &self.block) + .querier(&self.api, &self.storage, &self.block) .raw_query(bin_request) } } -impl Executor for App +impl Executor + for App where CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, ApiT: Api, + StorageT: Storage, CustomT: CustomHandler, { fn execute(&mut self, sender: Addr, msg: CosmosMsg) -> AnyResult { @@ -94,17 +109,37 @@ where } /// Utility to build App in stages. If particular items wont be set, defaults would be used -pub struct AppBuilder { +pub struct AppBuilder { wasm: Wasm, bank: Bank, api: Api, - storage: Option>, + storage: Storage, custom: Custom, - block: Option, + block: BlockInfo, +} + +impl Default + for AppBuilder< + BankKeeper, + MockApi, + MockStorage, + PanickingCustomHandler, + WasmKeeper, + > +{ + fn default() -> Self { + Self::new() + } } impl - AppBuilder, WasmKeeper> + AppBuilder< + BankKeeper, + MockApi, + MockStorage, + PanickingCustomHandler, + WasmKeeper, + > { /// Creates builder with default components working with empty exec and query messages. pub fn new() -> Self { @@ -112,9 +147,9 @@ impl wasm: WasmKeeper::new(), bank: BankKeeper::new(), api: MockApi::default(), - storage: None, + storage: MockStorage::new(), custom: PanickingCustomHandler::new(), - block: None, + block: mock_env().block, } } } @@ -123,6 +158,7 @@ impl AppBuilder< BankKeeper, MockApi, + MockStorage, PanickingCustomHandler, WasmKeeper, > @@ -137,14 +173,14 @@ where wasm: WasmKeeper::new(), bank: BankKeeper::new(), api: MockApi::default(), - storage: None, + storage: MockStorage::new(), custom: PanickingCustomHandler::new(), - block: None, + block: mock_env().block, } } } -impl AppBuilder { +impl AppBuilder { /// Overwrites default wasm executor. /// /// At this point it is needed that new wasm implements some `Wasm` trait, but it doesn't need @@ -157,7 +193,7 @@ impl AppBuilder { pub fn with_wasm>( self, wasm: NewWasm, - ) -> AppBuilder { + ) -> AppBuilder { let AppBuilder { bank, api, @@ -181,7 +217,7 @@ impl AppBuilder { pub fn with_bank( self, bank: NewBank, - ) -> AppBuilder { + ) -> AppBuilder { let AppBuilder { wasm, api, @@ -202,7 +238,10 @@ impl AppBuilder { } /// Overwrites default api interface - pub fn with_api(self, api: NewApi) -> AppBuilder { + pub fn with_api( + self, + api: NewApi, + ) -> AppBuilder { let AppBuilder { wasm, bank, @@ -223,14 +262,27 @@ impl AppBuilder { } /// Overwrites default storage interface - #[track_caller] - pub fn with_storage(mut self, storage: impl Storage + 'static) -> Self { - assert!( - self.storage.is_none(), - "Storage interface already overwritten" - ); - self.storage = Some(Box::new(storage)); - self + pub fn with_storage( + self, + storage: NewStorage, + ) -> AppBuilder { + let AppBuilder { + wasm, + api, + bank, + custom, + block, + .. + } = self; + + AppBuilder { + wasm, + bank, + api, + storage, + custom, + block, + } } /// Overwrites default custom messages handler @@ -245,7 +297,7 @@ impl AppBuilder { pub fn with_custom( self, custom: NewCustom, - ) -> AppBuilder { + ) -> AppBuilder { let AppBuilder { wasm, bank, @@ -266,30 +318,22 @@ impl AppBuilder { } /// Overwrites default initial block - #[track_caller] pub fn with_block(mut self, block: BlockInfo) -> Self { - assert!( - self.block.is_none(), - "Initial block info already overwritten" - ); - self.block = Some(block); + self.block = block; self } /// Builds final `App`. At this point all components type have to be properly related to each /// other. If there are some generics related compilation error make sure, that all components /// are properly relating to each other. - pub fn build(self) -> App + pub fn build(self) -> App where BankT: Bank, ApiT: Api, + StorageT: Storage, CustomT: CustomHandler, WasmT: Wasm, { - let api = self.api; - let storage = self.storage.unwrap_or_else(|| Box::new(MockStorage::new())); - let block = self.block.unwrap_or_else(|| mock_env().block); - let router = Router { wasm: self.wasm, bank: self.bank, @@ -298,20 +342,21 @@ impl AppBuilder { App { router, - api, - storage, - block, + api: self.api, + storage: self.storage, + block: self.block, } } } -impl App +impl App where CustomT::ExecC: std::fmt::Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, CustomT::QueryC: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, ApiT: Api, + StorageT: Storage, CustomT: CustomHandler, { pub fn set_block(&mut self, block: BlockInfo) { @@ -353,7 +398,7 @@ where storage, } = self; - transactional(&mut **storage, |write_cache, _| { + transactional(&mut *storage, |write_cache, _| { msgs.into_iter() .map(|msg| router.execute(&*api, write_cache, block, sender.clone(), msg)) .collect() @@ -364,7 +409,7 @@ where pub fn init_bank_balance(&mut self, account: &Addr, amount: Vec) -> AnyResult<()> { self.router .bank - .init_balance(&mut *self.storage, account, amount) + .init_balance(&mut self.storage, account, amount) } /// This registers contract code (like uploading wasm bytecode on a chain), @@ -375,7 +420,7 @@ where /// This allows to get `ContractData` for specific contract pub fn contract_data(&self, address: &Addr) -> AnyResult { - self.router.wasm.contract_data(&*self.storage, address) + self.router.wasm.contract_data(&self.storage, address) } /// Runs arbitrary CosmosMsg in "sudo" mode. @@ -390,7 +435,7 @@ where self.router.wasm.sudo( &self.api, contract_addr.into(), - &mut *self.storage, + &mut self.storage, &self.router, &self.block, msg, @@ -535,8 +580,8 @@ mod test { use super::*; - fn get_balance( - app: &App, + fn get_balance( + app: &App, addr: &Addr, ) -> Vec where @@ -545,6 +590,7 @@ mod test { WasmT: Wasm, BankT: Bank, ApiT: Api, + StorageT: Storage, CustomT: CustomHandler, { app.wrap().query_all_balances(addr).unwrap() @@ -1009,8 +1055,8 @@ mod test { val.amount } - fn query_app( - app: &App, + fn query_app( + app: &App, rcpt: &Addr, ) -> Vec where @@ -1020,6 +1066,7 @@ mod test { WasmT: Wasm, BankT: Bank, ApiT: Api, + StorageT: Storage, CustomT: CustomHandler, { let query = BankQuery::AllBalances { @@ -1041,7 +1088,7 @@ mod test { app.init_bank_balance(&owner, init_funds).unwrap(); // cache 1 - send some tokens - let mut cache = StorageTransaction::new(&*app.storage); + let mut cache = StorageTransaction::new(&app.storage); let msg = BankMsg::Send { to_address: rcpt.clone().into(), amount: coins(25, "eth"), @@ -1076,7 +1123,7 @@ mod test { .unwrap(); // apply first to router - cache.prepare().commit(&mut *app.storage); + cache.prepare().commit(&mut app.storage); let committed = query_app(&app, &rcpt); assert_eq!(coins(37, "eth"), committed); diff --git a/packages/multi-test/src/custom_handler.rs b/packages/multi-test/src/custom_handler.rs index 88019fe54..f3420806f 100644 --- a/packages/multi-test/src/custom_handler.rs +++ b/packages/multi-test/src/custom_handler.rs @@ -46,6 +46,12 @@ impl PanickingCustomHandler { } } +impl Default for PanickingCustomHandler { + fn default() -> Self { + Self::new() + } +} + impl CustomHandler for PanickingCustomHandler where Exec: std::fmt::Debug, From c1c7a5da4411488f88938e84726dc7bbef1adc8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Kuras?= Date: Tue, 14 Sep 2021 10:53:27 +0200 Subject: [PATCH 5/5] Removed obsolete phantom type in multitest custom handler --- packages/multi-test/src/wasm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multi-test/src/wasm.rs b/packages/multi-test/src/wasm.rs index b37add054..a1c4f7cf3 100644 --- a/packages/multi-test/src/wasm.rs +++ b/packages/multi-test/src/wasm.rs @@ -100,7 +100,7 @@ pub struct WasmKeeper { /// this can only be edited on the WasmRouter, and just read in caches codes: HashMap>>, /// Just markers to make type elision fork when using it as `Wasm` trait - _p: std::marker::PhantomData<(ExecC, QueryC)>, + _p: std::marker::PhantomData, } impl Default for WasmKeeper {