diff --git a/src/app.rs b/src/app.rs index 7f6d1804..d1e12e5a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -6,6 +6,7 @@ use crate::gov::Gov; use crate::ibc::Ibc; use crate::module::{FailingModule, Module}; use crate::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking, StakingSudo}; +use crate::stargate::{FailingStargate, Stargate, StargateMsg, StargateQuery}; use crate::transactions::transactional; use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; use crate::AppBuilder; @@ -35,6 +36,8 @@ pub type BasicApp = App< StakeKeeper, DistributionKeeper, FailingModule, + FailingModule, + FailingStargate, >; /// Router is a persisted state. You can query this. @@ -51,15 +54,16 @@ pub struct App< Distr = DistributionKeeper, Ibc = FailingModule, Gov = FailingModule, + Stargate = FailingStargate, > { - pub(crate) router: Router, + pub(crate) router: Router, pub(crate) api: Api, pub(crate) storage: Storage, pub(crate) block: BlockInfo, } -pub fn no_init( - _: &mut Router, +pub fn no_init( + _: &mut Router, _: &dyn Api, _: &mut dyn Storage, ) { @@ -84,12 +88,14 @@ impl BasicApp { DistributionKeeper, FailingModule, FailingModule, + FailingStargate, >, &dyn Api, &mut dyn Storage, ), { - AppBuilder::new().build(init_fn) + let a: BasicApp = AppBuilder::new().build(init_fn); + a } } @@ -108,6 +114,7 @@ where DistributionKeeper, FailingModule, FailingModule, + FailingStargate, >, &dyn Api, &mut dyn Storage, @@ -116,8 +123,8 @@ where AppBuilder::new_custom().build(init_fn) } -impl Querier - for App +impl Querier + for App where CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -130,6 +137,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { self.router @@ -138,8 +146,9 @@ where } } -impl Executor - for App +impl + Executor + for App where CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -152,6 +161,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { fn execute(&mut self, sender: Addr, msg: CosmosMsg) -> AnyResult { let mut all = self.execute_multi(sender, vec![msg])?; @@ -160,8 +170,8 @@ where } } -impl - App +impl + App where WasmT: Wasm, BankT: Bank, @@ -172,9 +182,12 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { /// Returns a shared reference to application's router. - pub fn router(&self) -> &Router { + pub fn router( + &self, + ) -> &Router { &self.router } @@ -196,7 +209,7 @@ where pub fn init_modules(&mut self, init_fn: F) -> T where F: FnOnce( - &mut Router, + &mut Router, &dyn Api, &mut dyn Storage, ) -> T, @@ -207,7 +220,7 @@ where pub fn read_module(&self, query_fn: F) -> T where F: FnOnce( - &Router, + &Router, &dyn Api, &dyn Storage, ) -> T, @@ -218,8 +231,8 @@ where // Helper functions to call some custom WasmKeeper logic. // They show how we can easily add such calls to other custom keepers (CustomT, StakingT, etc) -impl - App +impl + App where BankT: Bank, ApiT: Api, @@ -230,6 +243,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, { @@ -317,8 +331,8 @@ where } } -impl - App +impl + App where CustomT::ExecT: Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -331,6 +345,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { pub fn set_block(&mut self, block: BlockInfo) { self.block = block; @@ -423,7 +438,7 @@ where } #[derive(Clone)] -pub struct Router { +pub struct Router { // this can remain crate-only as all special functions are wired up to app currently // we need to figure out another format for wasm, as some like sudo need to be called after init pub(crate) wasm: Wasm, @@ -434,10 +449,11 @@ pub struct Router { pub distribution: Distr, pub ibc: Ibc, pub gov: Gov, + pub stargate: Stargate, } -impl - Router +impl + Router where CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -448,6 +464,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { pub fn querier<'a>( &'a self, @@ -521,8 +538,8 @@ pub trait CosmosRouter { ) -> AnyResult; } -impl CosmosRouter - for Router +impl CosmosRouter + for Router where CustomT::ExecT: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -533,6 +550,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { type ExecC = CustomT::ExecT; type QueryC = CustomT::QueryT; @@ -555,6 +573,14 @@ where .execute(api, storage, self, block, sender, msg), CosmosMsg::Ibc(msg) => self.ibc.execute(api, storage, self, block, sender, msg), CosmosMsg::Gov(msg) => self.gov.execute(api, storage, self, block, sender, msg), + CosmosMsg::Stargate { type_url, value } => self.stargate.execute( + api, + storage, + self, + block, + sender, + StargateMsg { type_url, value }, + ), _ => bail!("Cannot execute {:?}", msg), } } @@ -576,6 +602,10 @@ where QueryRequest::Custom(req) => self.custom.query(api, storage, &querier, block, req), QueryRequest::Staking(req) => self.staking.query(api, storage, &querier, block, req), QueryRequest::Ibc(req) => self.ibc.query(api, storage, &querier, block, req), + QueryRequest::Stargate { path, data } => { + self.stargate + .query(api, storage, &querier, block, StargateQuery { path, data }) + } _ => unimplemented!(), } } diff --git a/src/app_builder.rs b/src/app_builder.rs index 607ab0ce..fbee5656 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -1,5 +1,6 @@ //! Implementation of the builder for [App]. +use crate::stargate::{FailingStargate, Stargate}; use crate::{ App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingModule, Gov, Ibc, Module, Router, StakeKeeper, Staking, Wasm, WasmKeeper, @@ -35,11 +36,12 @@ pub type BasicAppBuilder = AppBuilder< DistributionKeeper, FailingModule, FailingModule, + FailingStargate, >; /// Utility to build [App] in stages. /// When particular properties are not explicitly set, then default values are used. -pub struct AppBuilder { +pub struct AppBuilder { api: Api, block: BlockInfo, storage: Storage, @@ -50,6 +52,7 @@ pub struct AppBuilder, FailingModule, + FailingStargate, > { fn default() -> Self { @@ -81,6 +85,7 @@ impl DistributionKeeper, FailingModule, FailingModule, + FailingStargate, > { /// Creates builder with default components working with empty exec and query messages. @@ -96,6 +101,7 @@ impl distribution: DistributionKeeper::new(), ibc: FailingModule::new(), gov: FailingModule::new(), + stargate: FailingModule::new(), } } } @@ -111,6 +117,7 @@ impl DistributionKeeper, FailingModule, FailingModule, + FailingStargate, > where ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, @@ -130,12 +137,13 @@ where distribution: DistributionKeeper::new(), ibc: FailingModule::new(), gov: FailingModule::new(), + stargate: FailingModule::new(), } } } -impl - AppBuilder +impl + AppBuilder where CustomT: Module, WasmT: Wasm, @@ -148,7 +156,8 @@ where pub fn with_wasm>( self, wasm: NewWasm, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { bank, api, @@ -159,6 +168,7 @@ where distribution, ibc, gov, + stargate, .. } = self; @@ -173,6 +183,7 @@ where distribution, ibc, gov, + stargate, } } @@ -180,7 +191,8 @@ where pub fn with_bank( self, bank: NewBank, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -191,6 +203,7 @@ where distribution, ibc, gov, + stargate, .. } = self; @@ -205,6 +218,7 @@ where distribution, ibc, gov, + stargate, } } @@ -212,7 +226,8 @@ where pub fn with_api( self, api: NewApi, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, bank, @@ -223,6 +238,7 @@ where distribution, ibc, gov, + stargate, .. } = self; @@ -237,6 +253,7 @@ where distribution, ibc, gov, + stargate, } } @@ -244,7 +261,8 @@ where pub fn with_storage( self, storage: NewStorage, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -255,6 +273,7 @@ where distribution, ibc, gov, + stargate, .. } = self; @@ -269,6 +288,7 @@ where distribution, ibc, gov, + stargate, } } @@ -280,7 +300,8 @@ where pub fn with_custom( self, custom: NewCustom, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, bank, @@ -291,6 +312,7 @@ where distribution, ibc, gov, + stargate, .. } = self; @@ -305,6 +327,7 @@ where distribution, ibc, gov, + stargate, } } @@ -312,7 +335,8 @@ where pub fn with_staking( self, staking: NewStaking, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -323,6 +347,7 @@ where distribution, ibc, gov, + stargate, .. } = self; @@ -337,6 +362,7 @@ where distribution, ibc, gov, + stargate, } } @@ -344,8 +370,18 @@ where pub fn with_distribution( self, distribution: NewDistribution, - ) -> AppBuilder - { + ) -> AppBuilder< + BankT, + ApiT, + StorageT, + CustomT, + WasmT, + StakingT, + NewDistribution, + IbcT, + GovT, + StargateT, + > { let AppBuilder { wasm, api, @@ -356,6 +392,7 @@ where bank, ibc, gov, + stargate, .. } = self; @@ -370,6 +407,7 @@ where distribution, ibc, gov, + stargate, } } @@ -383,7 +421,8 @@ where pub fn with_ibc( self, ibc: NewIbc, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -394,6 +433,7 @@ where bank, distribution, gov, + stargate, .. } = self; @@ -408,6 +448,7 @@ where distribution, ibc, gov, + stargate, } } @@ -415,7 +456,8 @@ where pub fn with_gov( self, gov: NewGov, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -426,6 +468,42 @@ where bank, distribution, ibc, + stargate, + .. + } = self; + + AppBuilder { + api, + block, + storage, + bank, + wasm, + custom, + staking, + distribution, + ibc, + gov, + stargate, + } + } + + /// Overwrites the default stargate interface. + pub fn with_stargate( + self, + stargate: NewStargate, + ) -> AppBuilder + { + let AppBuilder { + wasm, + api, + storage, + custom, + block, + staking, + bank, + distribution, + ibc, + gov, .. } = self; @@ -440,6 +518,7 @@ where distribution, ibc, gov, + stargate, } } @@ -455,7 +534,7 @@ where pub fn build( self, init_fn: F, - ) -> App + ) -> App where BankT: Bank, ApiT: Api, @@ -466,8 +545,9 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, F: FnOnce( - &mut Router, + &mut Router, &dyn Api, &mut dyn Storage, ), @@ -480,6 +560,7 @@ where distribution: self.distribution, ibc: self.ibc, gov: self.gov, + stargate: self.stargate, }; let mut app = App { diff --git a/src/lib.rs b/src/lib.rs index 2ebde753..2196d5e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ mod ibc; mod module; mod prefixed_storage; mod staking; +mod stargate; mod test_helpers; mod tests; mod transactions; @@ -39,4 +40,5 @@ pub use crate::module::{FailingModule, Module}; pub use crate::staking::{ Distribution, DistributionKeeper, StakeKeeper, Staking, StakingInfo, StakingSudo, }; +pub use crate::stargate::{FailingStargate, Stargate, StargateMsg, StargateQuery}; pub use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; diff --git a/src/staking.rs b/src/staking.rs index 88811ce6..f068f37a 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -991,6 +991,7 @@ mod test { use super::*; + use crate::stargate::FailingStargate; use cosmwasm_std::{ from_slice, testing::{mock_env, MockApi, MockStorage}, @@ -1006,6 +1007,7 @@ mod test { DistributionKeeper, FailingModule, FailingModule, + FailingStargate, >; fn mock_router() -> BasicRouter { @@ -1017,6 +1019,7 @@ mod test { distribution: DistributionKeeper::new(), ibc: FailingModule::new(), gov: FailingModule::new(), + stargate: FailingModule::new(), } } diff --git a/src/stargate.rs b/src/stargate.rs new file mode 100644 index 00000000..2c8d1cf4 --- /dev/null +++ b/src/stargate.rs @@ -0,0 +1,42 @@ +use crate::{FailingModule, Module}; +use cosmwasm_std::{Binary, CosmosMsg, Empty, QueryRequest}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct StargateMsg { + pub type_url: String, + pub value: Binary, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct StargateQuery { + pub path: String, + pub data: Binary, +} + +pub trait Stargate: Module {} + +pub type FailingStargate = FailingModule; + +impl Stargate for FailingStargate {} + +impl From for CosmosMsg { + fn from(msg: StargateMsg) -> Self { + CosmosMsg::Stargate { + type_url: msg.type_url, + value: msg.value, + } + } +} + +impl From for QueryRequest { + fn from(msg: StargateQuery) -> Self { + QueryRequest::Stargate { + path: msg.path, + data: msg.data, + } + } +} diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 51f7e7d1..1a7d3b21 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -40,8 +40,8 @@ where app.wrap().query_all_balances(addr).unwrap() } -fn query_router( - router: &Router, +fn query_router( + router: &Router, api: &dyn Api, storage: &dyn Storage, rcpt: &Addr, diff --git a/src/wasm.rs b/src/wasm.rs index 01c4885c..9fa3f98e 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1117,6 +1117,7 @@ mod test { use crate::bank::BankKeeper; use crate::module::FailingModule; use crate::staking::{DistributionKeeper, StakeKeeper}; + use crate::stargate::FailingStargate; use crate::test_helpers::{caller, error, payout}; use crate::transactions::StorageTransaction; use cosmwasm_std::testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage}; @@ -1134,6 +1135,7 @@ mod test { DistributionKeeper, FailingModule, FailingModule, + FailingStargate, >; fn wasm_keeper() -> WasmKeeper { @@ -1149,6 +1151,7 @@ mod test { distribution: DistributionKeeper::new(), ibc: FailingModule::new(), gov: FailingModule::new(), + stargate: FailingModule::new(), } } diff --git a/tests/mod.rs b/tests/mod.rs index cd393531..35ecef32 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -14,6 +14,7 @@ use sha2::{Digest, Sha256}; mod test_app_builder; mod test_module; +mod test_stargate; mod test_wasm; const COUNTER: Item = Item::new("count"); diff --git a/tests/test_app_builder/mod.rs b/tests/test_app_builder/mod.rs index a22c68ca..95f2547d 100644 --- a/tests/test_app_builder/mod.rs +++ b/tests/test_app_builder/mod.rs @@ -11,6 +11,7 @@ mod test_with_bank; mod test_with_block; mod test_with_distribution; mod test_with_staking; +mod test_with_stargate; mod test_with_storage; mod test_with_wasm; diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs new file mode 100644 index 00000000..e1b4c34c --- /dev/null +++ b/tests/test_app_builder/test_with_stargate.rs @@ -0,0 +1,52 @@ +use crate::test_app_builder::MyKeeper; +use cosmwasm_std::{to_vec, Addr, Empty, QueryRequest}; +use cw_multi_test::{AppBuilder, Executor, Stargate, StargateMsg, StargateQuery}; + +type MyStargateKeeper = MyKeeper; + +impl Stargate for MyStargateKeeper {} + +const EXECUTE_MSG: &str = "stargate execute called"; +const QUERY_MSG: &str = "stargate query called"; + +#[test] +fn building_app_with_custom_stargate_should_work() { + // build custom stargate keeper, stargate keeper has no sudo messages + let stargate_keeper = MyStargateKeeper::new(EXECUTE_MSG, QUERY_MSG, ""); + + // build the application with custom stargate keeper + let app_builder = AppBuilder::default(); + let mut app = app_builder + .with_stargate(stargate_keeper) + .build(|_, _, _| {}); + + // executing stargate message should return an error defined in custom keeper + assert_eq!( + app.execute( + Addr::unchecked("sender"), + StargateMsg { + type_url: "test".to_string(), + value: Default::default() + } + .into(), + ) + .unwrap_err() + .to_string(), + EXECUTE_MSG, + ); + + let query: QueryRequest = StargateQuery { + path: "test".to_string(), + data: Default::default(), + } + .into(); + + // executing stargate query should return an error defined in custom keeper + assert_eq!( + app.wrap() + .raw_query(to_vec(&query).unwrap().as_slice()) + .unwrap() + .unwrap_err(), + QUERY_MSG + ); +} diff --git a/tests/test_stargate/mod.rs b/tests/test_stargate/mod.rs new file mode 100644 index 00000000..0c8ce8ea --- /dev/null +++ b/tests/test_stargate/mod.rs @@ -0,0 +1 @@ +mod test_stargate_msg; diff --git a/tests/test_stargate/test_stargate_msg.rs b/tests/test_stargate/test_stargate_msg.rs new file mode 100644 index 00000000..df5f38ce --- /dev/null +++ b/tests/test_stargate/test_stargate_msg.rs @@ -0,0 +1,5 @@ +#[test] +#[cfg(feature = "stargate")] +fn a() { + // add a tests with contract that produces stargate message +}