From 6c3cbed87697d3c0879959149b759f33ae772d18 Mon Sep 17 00:00:00 2001 From: kent-3 <100624004+kent-3@users.noreply.github.com> Date: Sun, 24 Nov 2024 20:02:11 -0500 Subject: [PATCH 1/6] Revert "Parse protobuf data before executing submsg, update test contract to match (#12)" This reverts commit ca5c1704375c622398811b6339711b52b8dd3ad1. --- .../src/multi/test_helpers/contracts/echo.rs | 20 +++++++++++++++++-- packages/multi-test/src/multi/wasm.rs | 10 +--------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/packages/multi-test/src/multi/test_helpers/contracts/echo.rs b/packages/multi-test/src/multi/test_helpers/contracts/echo.rs index 18fba3a..5e9e5bb 100644 --- a/packages/multi-test/src/multi/test_helpers/contracts/echo.rs +++ b/packages/multi-test/src/multi/test_helpers/contracts/echo.rs @@ -96,13 +96,29 @@ where { let res = Response::new(); if let Reply { - id: _, + id, result: SubMsgResult::Ok(SubMsgResponse { data: Some(data), .. }), } = msg { - Ok(res.set_data(data)) + // We parse out the WasmMsg::Execute wrapper... + // TODO: Handle all of Execute, Instantiate, and BankMsg replies differently. + let parsed_data = if id < EXECUTE_REPLY_BASE_ID { + parse_instantiate_response_data(data.as_slice()) + .map_err(|e| StdError::generic_err(e.to_string()))? + .data + } else { + parse_execute_response_data(data.as_slice()) + .map_err(|e| StdError::generic_err(e.to_string()))? + .data + }; + + if let Some(data) = parsed_data { + Ok(res.set_data(data)) + } else { + Ok(res) + } } else { Ok(res) } diff --git a/packages/multi-test/src/multi/wasm.rs b/packages/multi-test/src/multi/wasm.rs index d87ef83..7149b74 100644 --- a/packages/multi-test/src/multi/wasm.rs +++ b/packages/multi-test/src/multi/wasm.rs @@ -37,7 +37,6 @@ use cosmwasm_std::{ use nanoid::nanoid; use prost::Message; use schemars::JsonSchema; -use secret_utils::parse_execute_response_data; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; @@ -572,18 +571,11 @@ where // call reply if meaningful if let Ok(mut r) = res { if matches!(reply_on, ReplyOn::Always | ReplyOn::Success) { - let data: Option = if let Some(b) = r.data { - let parsed = parse_execute_response_data(b.as_slice())?; - parsed.data - } else { - None - }; - let reply = Reply { id, result: SubMsgResult::Ok(SubMsgResponse { events: r.events.clone(), - data, + data: r.data, }), }; // do reply and combine it with the original response From 2b6e070660fa56c09e16abc8b4ffd8881985a8a1 Mon Sep 17 00:00:00 2001 From: kent-3 <100624004+kent-3@users.noreply.github.com> Date: Sun, 24 Nov 2024 20:04:43 -0500 Subject: [PATCH 2/6] rename _reply to reply --- packages/multi-test/src/multi/wasm.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/multi-test/src/multi/wasm.rs b/packages/multi-test/src/multi/wasm.rs index 7149b74..d9d091d 100644 --- a/packages/multi-test/src/multi/wasm.rs +++ b/packages/multi-test/src/multi/wasm.rs @@ -579,8 +579,7 @@ where }), }; // do reply and combine it with the original response - let reply_res = - self._reply(api, router, storage, block, contract.clone(), reply)?; + let reply_res = self.reply(api, router, storage, block, contract, reply)?; // override data r.data = reply_res.data; // append the events @@ -589,7 +588,6 @@ where // reply is not called, no data should be rerturned r.data = None; } - Ok(r) } else if let Err(e) = res { if matches!(reply_on, ReplyOn::Always | ReplyOn::Error) { @@ -597,7 +595,7 @@ where id, result: SubMsgResult::Err(e.to_string()), }; - self._reply(api, router, storage, block, contract, reply) + self.reply(api, router, storage, block, contract, reply) } else { Err(e) } @@ -606,7 +604,7 @@ where } } - fn _reply( + fn reply( &self, api: &dyn Api, router: &dyn CosmosRouter, From 500e417b97484366f1482a692f7a1b275881cb7b Mon Sep 17 00:00:00 2001 From: kent-3 <100624004+kent-3@users.noreply.github.com> Date: Mon, 25 Nov 2024 23:15:52 -0500 Subject: [PATCH 3/6] remove unused --- packages/multi-test/src/multi/executor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multi-test/src/multi/executor.rs b/packages/multi-test/src/multi/executor.rs index 3da0da9..6dc62ed 100644 --- a/packages/multi-test/src/multi/executor.rs +++ b/packages/multi-test/src/multi/executor.rs @@ -5,7 +5,7 @@ use cosmwasm_std::{ SubMsgResponse, WasmMsg, }; use schemars::JsonSchema; -use secret_utils::{parse_execute_response_data, parse_instantiate_response_data}; +use secret_utils::parse_execute_response_data; use serde::Serialize; use anyhow::Result as AnyResult; From dff2ed829d61fcbc04b0eb2afa630352b89fd3fc Mon Sep 17 00:00:00 2001 From: kent-3 <100624004+kent-3@users.noreply.github.com> Date: Mon, 25 Nov 2024 23:16:01 -0500 Subject: [PATCH 4/6] add stargate support --- packages/multi-test/src/multi/app.rs | 244 +++++++++++++----- packages/multi-test/src/multi/mod.rs | 2 + packages/multi-test/src/multi/module.rs | 7 +- packages/multi-test/src/multi/stargate.rs | 86 ++++++ packages/multi-test/src/multi/test_helpers.rs | 17 +- .../multi/test_helpers/contracts/reflect.rs | 12 +- .../src/multi/test_helpers/mocks.rs | 5 +- 7 files changed, 293 insertions(+), 80 deletions(-) create mode 100644 packages/multi-test/src/multi/stargate.rs diff --git a/packages/multi-test/src/multi/app.rs b/packages/multi-test/src/multi/app.rs index eb03d64..28d4880 100644 --- a/packages/multi-test/src/multi/app.rs +++ b/packages/multi-test/src/multi/app.rs @@ -5,9 +5,9 @@ use anyhow::bail; use anyhow::Result as AnyResult; use cosmwasm_std::testing::{mock_env, MockApi, MockStorage}; use cosmwasm_std::{ - from_slice, to_binary, Addr, Api, Binary, BlockInfo, ContractResult, CosmosMsg, CustomQuery, - Empty, GovMsg, IbcMsg, IbcQuery, Querier, QuerierResult, QuerierWrapper, QueryRequest, Storage, - SystemError, SystemResult, Timestamp, + from_slice, to_binary, Addr, Api, Binary, BlockInfo, ContractResult, CosmosMsg, CustomMsg, + CustomQuery, Empty, GovMsg, IbcMsg, IbcQuery, Querier, QuerierResult, QuerierWrapper, + QueryRequest, Storage, SystemError, SystemResult, Timestamp, }; use schemars::JsonSchema; use serde::de::DeserializeOwned; @@ -22,6 +22,7 @@ use crate::staking::{Distribution, DistributionKeeper, Staking, StakingKeeper, S use crate::transactions::transactional; use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; use crate::Ibc; +use crate::{Stargate, StargateFailing}; pub fn next_block(block: &mut BlockInfo) { block.time = block.time.plus_seconds(5); @@ -38,6 +39,8 @@ pub type BasicApp = App< StakingKeeper, DistributionKeeper, FailingModule, + FailingModule, + StargateFailing, >; /// Router is a persisted state. You can query this. @@ -53,15 +56,16 @@ pub struct App< Distr = DistributionKeeper, Ibc = FailingModule, Gov = FailingModule, + Stargate = StargateFailing, > { - router: Router, + router: Router, api: Api, storage: Storage, block: BlockInfo, } -fn no_init( - _: &mut Router, +fn no_init( + _: &mut Router, _: &dyn Api, _: &mut dyn Storage, ) { @@ -86,6 +90,7 @@ impl BasicApp { DistributionKeeper, FailingModule, FailingModule, + StargateFailing, >, &dyn Api, &mut dyn Storage, @@ -110,6 +115,7 @@ where DistributionKeeper, FailingModule, FailingModule, + StargateFailing, >, &dyn Api, &mut dyn Storage, @@ -118,10 +124,10 @@ where AppBuilder::new_custom().build(init_fn) } -impl Querier - for App +impl Querier + for App where - CustomT::ExecT: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, @@ -132,6 +138,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { self.router @@ -140,10 +147,11 @@ where } } -impl Executor - for App +impl + Executor + for App where - CustomT::ExecT: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, @@ -154,6 +162,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { fn execute( &mut self, @@ -178,10 +187,11 @@ pub type BasicAppBuilder = AppBuilder< DistributionKeeper, FailingModule, FailingModule, + StargateFailing, >; /// Utility to build App in stages. If particular items wont be set, defaults would be used -pub struct AppBuilder { +pub struct AppBuilder { api: Api, block: BlockInfo, storage: Storage, @@ -192,6 +202,7 @@ pub struct AppBuilder, FailingModule, + StargateFailing, > { fn default() -> Self { @@ -223,6 +235,7 @@ impl DistributionKeeper, FailingModule, FailingModule, + StargateFailing, > { /// Creates builder with default components working with empty exec and query messages. @@ -238,6 +251,7 @@ impl distribution: DistributionKeeper::new(), ibc: FailingModule::new(), gov: FailingModule::new(), + stargate: StargateFailing, } } } @@ -253,6 +267,7 @@ impl DistributionKeeper, FailingModule, FailingModule, + StargateFailing, > where ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, @@ -272,12 +287,13 @@ where distribution: DistributionKeeper::new(), ibc: FailingModule::new(), gov: FailingModule::new(), + stargate: StargateFailing, } } } -impl - AppBuilder +impl + AppBuilder { /// Overwrites default wasm executor. /// @@ -291,7 +307,8 @@ impl pub fn with_wasm>( self, wasm: NewWasm, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { bank, api, @@ -302,6 +319,7 @@ impl distribution, ibc, gov, + stargate, .. } = self; @@ -316,6 +334,7 @@ impl distribution, ibc, gov, + stargate, } } @@ -323,7 +342,8 @@ impl pub fn with_bank( self, bank: NewBank, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -334,6 +354,7 @@ impl distribution, ibc, gov, + stargate, .. } = self; @@ -348,6 +369,7 @@ impl distribution, ibc, gov, + stargate, } } @@ -355,7 +377,8 @@ impl pub fn with_api( self, api: NewApi, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, bank, @@ -366,6 +389,7 @@ impl distribution, ibc, gov, + stargate, .. } = self; @@ -380,6 +404,7 @@ impl distribution, ibc, gov, + stargate, } } @@ -387,7 +412,8 @@ impl pub fn with_storage( self, storage: NewStorage, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -398,6 +424,7 @@ impl distribution, ibc, gov, + stargate, .. } = self; @@ -412,6 +439,7 @@ impl distribution, ibc, gov, + stargate, } } @@ -427,7 +455,8 @@ impl pub fn with_custom( self, custom: NewCustom, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, bank, @@ -438,6 +467,7 @@ impl distribution, ibc, gov, + stargate, .. } = self; @@ -452,6 +482,7 @@ impl distribution, ibc, gov, + stargate, } } @@ -459,7 +490,8 @@ impl pub fn with_staking( self, staking: NewStaking, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -470,6 +502,7 @@ impl distribution, ibc, gov, + stargate, .. } = self; @@ -484,6 +517,7 @@ impl distribution, ibc, gov, + stargate, } } @@ -491,8 +525,18 @@ impl pub fn with_distribution( self, distribution: NewDistribution, - ) -> AppBuilder - { + ) -> AppBuilder< + BankT, + ApiT, + StorageT, + CustomT, + WasmT, + StakingT, + NewDistribution, + IbcT, + GovT, + StargateT, + > { let AppBuilder { wasm, api, @@ -503,6 +547,7 @@ impl bank, ibc, gov, + stargate, .. } = self; @@ -517,6 +562,7 @@ impl distribution, ibc, gov, + stargate, } } @@ -524,7 +570,8 @@ impl pub fn with_ibc( self, ibc: NewIbc, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -535,6 +582,7 @@ impl bank, distribution, gov, + stargate, .. } = self; @@ -549,14 +597,51 @@ impl distribution, ibc, gov, + stargate, } } - /// Overwrites default gov interface + /// Overwrites the default gov interface. pub fn with_gov( self, gov: NewGov, - ) -> AppBuilder { + ) -> AppBuilder + { + let AppBuilder { + wasm, + api, + storage, + custom, + block, + staking, + 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, @@ -567,6 +652,7 @@ impl bank, distribution, ibc, + gov, .. } = self; @@ -581,6 +667,7 @@ impl distribution, ibc, gov, + stargate, } } @@ -596,7 +683,7 @@ impl pub fn build( self, init_fn: F, - ) -> App + ) -> App where BankT: Bank, ApiT: Api, @@ -607,8 +694,9 @@ impl DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, F: FnOnce( - &mut Router, + &mut Router, &dyn Api, &mut dyn Storage, ), @@ -621,6 +709,7 @@ impl distribution: self.distribution, ibc: self.ibc, gov: self.gov, + stargate: self.stargate, }; let mut app = App { @@ -634,8 +723,8 @@ impl } } -impl - App +impl + App where WasmT: Wasm, BankT: Bank, @@ -646,11 +735,12 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { pub fn init_modules(&mut self, init_fn: F) -> T where F: FnOnce( - &mut Router, + &mut Router, &dyn Api, &mut dyn Storage, ) -> T, @@ -661,7 +751,7 @@ where pub fn read_module(&self, query_fn: F) -> T where F: FnOnce( - &Router, + &Router, &dyn Api, &dyn Storage, ) -> T, @@ -672,7 +762,7 @@ 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 +impl App< BankT, ApiT, @@ -683,6 +773,7 @@ impl DistrT, IbcT, GovT, + StargateT, > where BankT: Bank, @@ -693,7 +784,8 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - CustomT::ExecT: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + StargateT: Stargate, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, { /// This registers contract code (like uploading wasm bytecode on a chain), @@ -729,10 +821,10 @@ where // } } -impl - App +impl + App where - CustomT::ExecT: std::fmt::Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, @@ -743,6 +835,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { pub fn set_block(&mut self, block: BlockInfo) { self.block = block; @@ -838,23 +931,32 @@ where } } -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 +/// The Router plays a critical role in managing and directing +/// transactions within the Cosmos blockchain. +#[derive(Clone)] +pub struct Router { + /// Wasm module instance to be used in this [Router]. pub(crate) wasm: Wasm, - // these must be pub so we can initialize them (super user) on build + /// Bank module instance to be used in this [Router]. pub bank: Bank, + /// Custom module instance to be used in this [Router]. pub custom: Custom, + /// Staking module instance to be used in this [Router]. pub staking: Staking, + /// Distribution module instance to be used in this [Router]. pub distribution: Distr, + /// IBC module instance to be used in this [Router]. pub ibc: Ibc, + /// Governance module instance to be used in this [Router]. pub gov: Gov, + /// Stargate handler instance to be used in this [Router]. + pub stargate: Stargate, } -impl - Router +impl + Router where - CustomT::ExecT: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, CustomT: Module, WasmT: Wasm, @@ -863,6 +965,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { pub fn querier<'a>( &'a self, @@ -936,10 +1039,10 @@ pub trait CosmosRouter { ) -> AnyResult; } -impl CosmosRouter - for Router +impl CosmosRouter + for Router where - CustomT::ExecT: std::fmt::Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, CustomT: Module, WasmT: Wasm, @@ -948,6 +1051,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { type ExecC = CustomT::ExecT; type QueryC = CustomT::QueryT; @@ -970,6 +1074,10 @@ 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), + // #[cfg(feature = "stargate")] + CosmosMsg::Stargate { type_url, value } => self + .stargate + .execute_stargate(api, storage, self, block, sender, type_url, value), _ => bail!("Cannot execute {:?}", msg), } } @@ -990,6 +1098,11 @@ where QueryRequest::Bank(req) => self.bank.query(api, storage, &querier, block, req), QueryRequest::Custom(req) => self.custom.query(api, storage, &querier, block, req), QueryRequest::Staking(req) => self.staking.query(api, storage, &querier, block, req), + #[allow(deprecated)] + // #[cfg(feature = "stargate")] + QueryRequest::Stargate { path, data } => self + .stargate + .query_stargate(api, storage, &querier, block, path, data), _ => unimplemented!(), } } @@ -1126,7 +1239,7 @@ mod test { use crate::error::Error; use crate::test_helpers::contracts::{caller, echo, error, hackatom, payout, reflect}; - use crate::test_helpers::{CustomMsg, EmptyMsg}; + use crate::test_helpers::{CustomHelperMsg, EmptyMsg}; use crate::transactions::StorageTransaction; fn get_balance( @@ -1134,7 +1247,7 @@ mod test { addr: &Addr, ) -> Vec where - CustomT::ExecT: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, @@ -1297,7 +1410,7 @@ mod test { let owner = Addr::unchecked("owner"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; - let mut app = custom_app::(|router, _, storage| { + let mut app = custom_app::(|router, _, storage| { router .bank .init_balance(storage, &owner, init_funds) @@ -1413,7 +1526,7 @@ mod test { let owner = Addr::unchecked("owner"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; - let mut app = custom_app::(|router, _, storage| { + let mut app = custom_app::(|router, _, storage| { router .bank .init_balance(storage, &owner, init_funds) @@ -1590,17 +1703,19 @@ mod test { const PITY: Item = Item::new("pity"); #[derive(Clone, std::fmt::Debug, PartialEq, JsonSchema, Serialize, Deserialize)] - struct CustomMsg { + struct CustomLotteryMsg { // we mint LOTTERY tokens to this one lucky_winner: String, // we transfer PITY from lucky_winner to runner_up runner_up: String, } + impl CustomMsg for CustomLotteryMsg {} + struct CustomHandler {} impl Module for CustomHandler { - type ExecT = CustomMsg; + type ExecT = CustomLotteryMsg; type QueryT = Empty; type SudoT = Empty; @@ -1692,7 +1807,7 @@ mod test { let lottery = coin(54321, denom); let bonus = coin(12321, denom); - let mut app = BasicAppBuilder::::new_custom() + let mut app = BasicAppBuilder::::new_custom() .with_custom(CustomHandler {}) .build(|router, _, storage| { router @@ -1706,7 +1821,7 @@ mod test { assert_eq!(start, coin(0, denom)); // trigger the custom module - let msg = CosmosMsg::Custom(CustomMsg { + let msg = CosmosMsg::Custom(CustomLotteryMsg { lucky_winner: winner.clone(), runner_up: second.clone(), }); @@ -1727,7 +1842,7 @@ mod test { let random = Addr::unchecked("random"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; - let mut app = custom_app::(|router, _, storage| { + let mut app = custom_app::(|router, _, storage| { router .bank .init_balance(storage, &owner, init_funds) @@ -1826,14 +1941,14 @@ 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::ExecT: Clone + fmt::Debug + PartialEq + JsonSchema, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned, WasmT: Wasm, BankT: Bank, @@ -1859,8 +1974,7 @@ mod test { rcpt: &Addr, ) -> Vec where - CustomT::ExecT: - std::fmt::Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, @@ -2270,7 +2384,7 @@ mod test { let owner = Addr::unchecked("owner"); let init_funds = coins(100, "tgd"); - let mut app = custom_app::(|router, _, storage| { + let mut app = custom_app::(|router, _, storage| { router .bank .init_balance(storage, &owner, init_funds) @@ -2668,7 +2782,7 @@ mod test { let sender = api.addr_validate("sender").unwrap(); let owner = api.addr_validate("owner").unwrap(); - let custom_handler = CachingCustomHandler::::new(); + let custom_handler = CachingCustomHandler::::new(); let custom_handler_state = custom_handler.state(); let mut app = AppBuilder::new_custom() @@ -2685,7 +2799,7 @@ mod test { sender, &contract, &echo::Message { - sub_msg: vec![SubMsg::new(CosmosMsg::Custom(CustomMsg::SetAge { + sub_msg: vec![SubMsg::new(CosmosMsg::Custom(CustomHelperMsg::SetAge { age: 20, }))], ..Default::default() @@ -2696,7 +2810,7 @@ mod test { assert_eq!( custom_handler_state.execs().to_owned(), - vec![CustomMsg::SetAge { age: 20 }] + vec![CustomHelperMsg::SetAge { age: 20 }] ); assert!(custom_handler_state.queries().is_empty()); diff --git a/packages/multi-test/src/multi/mod.rs b/packages/multi-test/src/multi/mod.rs index a75739d..3a0b525 100644 --- a/packages/multi-test/src/multi/mod.rs +++ b/packages/multi-test/src/multi/mod.rs @@ -18,6 +18,7 @@ pub(crate) mod ibc; pub(crate) mod module; pub(crate) mod prefixed_storage; pub(crate) mod staking; +pub(crate) mod stargate; pub(crate) mod test_helpers; pub(crate) mod transactions; pub(crate) mod wasm; @@ -32,5 +33,6 @@ pub use crate::executor::{AppResponse, Executor}; pub use crate::ibc::Ibc; pub use crate::module::{FailingModule, Module}; pub use crate::staking::{Distribution, DistributionKeeper, Staking, StakingKeeper, StakingSudo}; +pub use crate::stargate::{Stargate, StargateAccepting, StargateFailing}; pub use crate::wasm::{Wasm, WasmKeeper, WasmSudo}; pub use nanoid; diff --git a/packages/multi-test/src/multi/module.rs b/packages/multi-test/src/multi/module.rs index 7125a3e..214edab 100644 --- a/packages/multi-test/src/multi/module.rs +++ b/packages/multi-test/src/multi/module.rs @@ -1,11 +1,10 @@ use std::marker::PhantomData; use anyhow::{bail, Result as AnyResult}; -use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomQuery, Querier, Storage}; +use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomMsg, CustomQuery, Querier, Storage}; use crate::app::CosmosRouter; use crate::AppResponse; -use schemars::JsonSchema; use serde::de::DeserializeOwned; pub trait Module { @@ -25,7 +24,7 @@ pub trait Module { msg: Self::ExecT, ) -> AnyResult where - ExecC: std::fmt::Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static; /// sudo runs privileged actions, like minting tokens, or governance proposals. @@ -42,7 +41,7 @@ pub trait Module { msg: Self::SudoT, ) -> AnyResult where - ExecC: std::fmt::Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static; fn query( diff --git a/packages/multi-test/src/multi/stargate.rs b/packages/multi-test/src/multi/stargate.rs new file mode 100644 index 0000000..24c55e7 --- /dev/null +++ b/packages/multi-test/src/multi/stargate.rs @@ -0,0 +1,86 @@ +//! # Handler for `CosmosMsg::Stargate`, `CosmosMsg::Any`, `QueryRequest::Stargate` and `QueryRequest::Grpc` messages + +use crate::{AppResponse, CosmosRouter}; +use anyhow::bail; +use anyhow::Result as AnyResult; +use cosmwasm_std::to_binary; +use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomMsg, CustomQuery, Empty, Querier, Storage}; +use serde::de::DeserializeOwned; + +/// Interface of handlers for processing `Stargate` message variants +pub trait Stargate { + /// Processes `CosmosMsg::Stargate` message variant. + fn execute_stargate( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + sender: Addr, + type_url: String, + value: Binary, + ) -> AnyResult + where + ExecC: CustomMsg + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + bail!( + "Unexpected stargate execute: type_url={}, value={} from {}", + type_url, + value, + sender, + ) + } + + /// Processes `QueryRequest::Stargate` query. + fn query_stargate( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + path: String, + data: Binary, + ) -> AnyResult { + bail!("Unexpected stargate query: path={}, data={}", path, data) + } +} + +/// Always failing handler for `Stargate` message variants and `Stargate` queries. +pub struct StargateFailing; + +impl Stargate for StargateFailing {} + +/// Always accepting handler for `Stargate` message variants and `Stargate` queries. +pub struct StargateAccepting; + +impl Stargate for StargateAccepting { + fn execute_stargate( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + _sender: Addr, + _type_url: String, + _value: Binary, + ) -> AnyResult + where + ExecC: CustomMsg + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + Ok(AppResponse::default()) + } + + fn query_stargate( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + _path: String, + _data: Binary, + ) -> AnyResult { + to_binary(&Empty {}).map_err(Into::into) + } +} diff --git a/packages/multi-test/src/multi/test_helpers.rs b/packages/multi-test/src/multi/test_helpers.rs index 69220da..8122d7d 100644 --- a/packages/multi-test/src/multi/test_helpers.rs +++ b/packages/multi-test/src/multi/test_helpers.rs @@ -1,4 +1,5 @@ #![cfg(test)] +use cosmwasm_std::CustomMsg; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -11,11 +12,19 @@ pub mod mocks; pub struct EmptyMsg {} /// This is just a demo place so we can test custom message handling -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Default)] #[serde(rename = "snake_case")] -pub enum CustomMsg { - SetName { name: String }, - SetAge { age: u32 }, +pub enum CustomHelperMsg { + SetName { + name: String, + }, + SetAge { + age: u32, + }, + #[default] + NoOp, } +impl CustomMsg for CustomHelperMsg {} + const COUNT: Item = Item::new("count"); diff --git a/packages/multi-test/src/multi/test_helpers/contracts/reflect.rs b/packages/multi-test/src/multi/test_helpers/contracts/reflect.rs index 727c3d8..5d533ab 100644 --- a/packages/multi-test/src/multi/test_helpers/contracts/reflect.rs +++ b/packages/multi-test/src/multi/test_helpers/contracts/reflect.rs @@ -7,11 +7,11 @@ use secret_storage_plus::Map; use crate::contracts::{Contract, ContractWrapper}; use crate::test_helpers::contracts::payout; -use crate::test_helpers::{CustomMsg, EmptyMsg, COUNT}; +use crate::test_helpers::{CustomHelperMsg, EmptyMsg, COUNT}; #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Message { - pub messages: Vec>, + pub messages: Vec>, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -27,7 +27,7 @@ fn instantiate( _env: Env, _info: MessageInfo, _msg: EmptyMsg, -) -> Result, StdError> { +) -> Result, StdError> { COUNT.save(deps.storage, &0)?; Ok(Response::default()) } @@ -37,7 +37,7 @@ fn execute( _env: Env, _info: MessageInfo, msg: Message, -) -> Result, StdError> { +) -> Result, StdError> { COUNT.update::<_, StdError>(deps.storage, |old| Ok(old + 1))?; Ok(Response::new().add_submessages(msg.messages)) @@ -57,7 +57,7 @@ fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result { } } -fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result, StdError> { +fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result, StdError> { REFLECT.save(deps.storage, msg.id, &msg)?; // add custom event here to test let event = Event::new("custom") @@ -66,7 +66,7 @@ fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result, St Ok(Response::new().add_event(event)) } -pub fn contract() -> Box> { +pub fn contract() -> Box> { let contract = ContractWrapper::new(execute, instantiate, query).with_reply(reply); Box::new(contract) } diff --git a/packages/multi-test/src/multi/test_helpers/mocks.rs b/packages/multi-test/src/multi/test_helpers/mocks.rs index 53713be..82a5536 100644 --- a/packages/multi-test/src/multi/test_helpers/mocks.rs +++ b/packages/multi-test/src/multi/test_helpers/mocks.rs @@ -1,7 +1,8 @@ use cosmwasm_std::{Empty, GovMsg, IbcMsg, IbcQuery}; use crate::{ - BankKeeper, DistributionKeeper, FailingModule, Router, Staking, StakingKeeper, WasmKeeper, + BankKeeper, DistributionKeeper, FailingModule, Router, StakingKeeper, StargateFailing, + WasmKeeper, }; pub type BasicRouter = Router< @@ -12,6 +13,7 @@ pub type BasicRouter = Router< DistributionKeeper, FailingModule, FailingModule, + StargateFailing, >; pub fn mock_router() -> BasicRouter { @@ -23,5 +25,6 @@ pub fn mock_router() -> BasicRouter { distribution: DistributionKeeper::new(), ibc: FailingModule::new(), gov: FailingModule::new(), + stargate: StargateFailing, } } From 5e9be5656b5950ade249f214284bf22b1c3b8b25 Mon Sep 17 00:00:00 2001 From: kent-3 <100624004+kent-3@users.noreply.github.com> Date: Tue, 26 Nov 2024 00:35:01 -0500 Subject: [PATCH 5/6] potential solution for stargate CodeHashByContractAddress query --- Cargo.lock | 7 ++++ packages/multi-test/Cargo.toml | 1 + packages/multi-test/src/multi/stargate.rs | 42 +++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index abcac08..bb4d9d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,6 +49,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "anybuf" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5f1dee23caf80904249463cc4493b6789c2250f88c8f8d9160de5c6099bfe7" + [[package]] name = "anyhow" version = "1.0.75" @@ -1358,6 +1364,7 @@ dependencies = [ name = "secret-multi-test" version = "0.13.4" dependencies = [ + "anybuf", "anyhow", "derivative", "itertools", diff --git a/packages/multi-test/Cargo.toml b/packages/multi-test/Cargo.toml index d79ea2e..6ae164b 100644 --- a/packages/multi-test/Cargo.toml +++ b/packages/multi-test/Cargo.toml @@ -36,3 +36,4 @@ prost = "0.9" anyhow = "1.0.41" thiserror = "1" derivative = "2" +anybuf = "0.5.0" diff --git a/packages/multi-test/src/multi/stargate.rs b/packages/multi-test/src/multi/stargate.rs index 24c55e7..b13baf2 100644 --- a/packages/multi-test/src/multi/stargate.rs +++ b/packages/multi-test/src/multi/stargate.rs @@ -1,6 +1,7 @@ //! # Handler for `CosmosMsg::Stargate`, `CosmosMsg::Any`, `QueryRequest::Stargate` and `QueryRequest::Grpc` messages use crate::{AppResponse, CosmosRouter}; +use anybuf::Bufany; use anyhow::bail; use anyhow::Result as AnyResult; use cosmwasm_std::to_binary; @@ -84,3 +85,44 @@ impl Stargate for StargateAccepting { to_binary(&Empty {}).map_err(Into::into) } } + +// THIS MAY NOT BE POSSIBLE. I'm assuming the app storage contains the registered contract data. + +use super::wasm::ContractData; +use crate::prefixed_storage::prefixed_read; +use secret_storage_plus::Map; + +const CONTRACTS: Map<&Addr, ContractData> = Map::new("contracts"); +const NAMESPACE_WASM: &[u8] = b"wasm"; + +pub struct StargateCodeHash; + +impl Stargate for StargateCodeHash { + fn query_stargate( + &self, + _api: &dyn Api, + storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + path: String, + data: Binary, + ) -> AnyResult { + match path.as_str() { + "/secret.compute.v1beta1.Query/CodeHashByContractAddress" => { + let deserialized = Bufany::deserialize(data.as_slice())?; + + if let Some(contract_address) = deserialized.string(1) { + let contract = CONTRACTS.load( + &prefixed_read(storage, NAMESPACE_WASM), + &Addr::unchecked(contract_address), + )?; + + Ok(Binary(contract.code_hash.into())) + } else { + bail!("Failed to decode Protobuf message: String not found for field number 1") + } + } + _ => bail!("Unexpected stargate query: path={}, data={}", path, data), + } + } +} From f98171e2f4dc3fdadac8fe4fac6d668b4d0276c9 Mon Sep 17 00:00:00 2001 From: kent-3 <100624004+kent-3@users.noreply.github.com> Date: Tue, 26 Nov 2024 00:41:02 -0500 Subject: [PATCH 6/6] move the CodeHashByContractAddress query support into default trait --- packages/multi-test/src/multi/stargate.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/multi-test/src/multi/stargate.rs b/packages/multi-test/src/multi/stargate.rs index b13baf2..07744bb 100644 --- a/packages/multi-test/src/multi/stargate.rs +++ b/packages/multi-test/src/multi/stargate.rs @@ -37,13 +37,29 @@ pub trait Stargate { fn query_stargate( &self, _api: &dyn Api, - _storage: &dyn Storage, + storage: &dyn Storage, _querier: &dyn Querier, _block: &BlockInfo, path: String, data: Binary, ) -> AnyResult { - bail!("Unexpected stargate query: path={}, data={}", path, data) + match path.as_str() { + "/secret.compute.v1beta1.Query/CodeHashByContractAddress" => { + let deserialized = Bufany::deserialize(data.as_slice())?; + + if let Some(contract_address) = deserialized.string(1) { + let contract = CONTRACTS.load( + &prefixed_read(storage, NAMESPACE_WASM), + &Addr::unchecked(contract_address), + )?; + + Ok(Binary(contract.code_hash.into())) + } else { + bail!("Failed to decode Protobuf message: String not found for field number 1") + } + } + _ => bail!("Unexpected stargate query: path={}, data={}", path, data), + } } }