Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify router args #422

Merged
merged 7 commits into from
Sep 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/multi-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ documentation = "https://docs.cosmwasm.com"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = ["iterator"]
default = ["iterator", "staking"]
iterator = ["cosmwasm-std/iterator"]
stargate = ["cosmwasm-std/stargate"]
staking = ["cosmwasm-std/staking"]
backtrace = ["anyhow/backtrace"]

[dependencies]
Expand Down
134 changes: 81 additions & 53 deletions packages/multi-test/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ use std::fmt::{self, Debug};

use cosmwasm_std::testing::{mock_env, MockApi, MockStorage};
use cosmwasm_std::{
from_slice, to_vec, Addr, Api, Binary, BlockInfo, Coin, ContractResult, CosmosMsg, CustomQuery,
Empty, Querier, QuerierResult, QuerierWrapper, QueryRequest, Storage, SystemError,
SystemResult,
from_slice, to_vec, Addr, Api, Binary, BlockInfo, Coin, ContractResult, CustomQuery, Empty,
Querier, QuerierResult, QuerierWrapper, QueryRequest, Storage, SystemError, SystemResult,
};
use schemars::JsonSchema;
use serde::de::DeserializeOwned;
Expand All @@ -15,6 +14,7 @@ use crate::contracts::Contract;
use crate::custom_handler::{CustomHandler, PanickingCustomHandler};
use crate::executor::{AppResponse, Executor};
use crate::transactions::transactional;
use crate::untyped_msg::CosmosMsg;
use crate::wasm::{ContractData, Wasm, WasmKeeper};
use crate::BankKeeper;

Expand Down Expand Up @@ -101,7 +101,11 @@ where
StorageT: Storage,
CustomT: CustomHandler,
{
fn execute(&mut self, sender: Addr, msg: CosmosMsg<CustomT::ExecC>) -> AnyResult<AppResponse> {
fn execute(
&mut self,
sender: Addr,
msg: cosmwasm_std::CosmosMsg<CustomT::ExecC>,
) -> AnyResult<AppResponse> {
let mut all = self.execute_multi(sender, vec![msg])?;
let res = all.pop().unwrap();
Ok(res)
Expand Down Expand Up @@ -385,7 +389,7 @@ where
pub fn execute_multi(
&mut self,
sender: Addr,
msgs: Vec<CosmosMsg<CustomT::ExecC>>,
msgs: Vec<cosmwasm_std::CosmosMsg<CustomT::ExecC>>,
) -> AnyResult<Vec<AppResponse>> {
// 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
Expand All @@ -400,7 +404,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.into()))
.collect()
})
}
Expand Down Expand Up @@ -449,39 +453,88 @@ pub struct Router<Bank, Custom, Wasm> {
pub(crate) custom: Custom,
}

impl<BankT, CustomT, WasmT> Router<BankT, CustomT, WasmT> {
impl<BankT, CustomT, WasmT> Router<BankT, CustomT, WasmT>
where
CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
CustomT::QueryC: CustomQuery + DeserializeOwned + 'static,
CustomT: CustomHandler,
WasmT: Wasm<CustomT::ExecC, CustomT::QueryC>,
BankT: Bank,
{
pub fn querier<'a>(
&'a self,
api: &'a dyn Api,
storage: &'a dyn Storage,
block_info: &'a BlockInfo,
) -> RouterQuerier<'a, BankT, CustomT, WasmT> {
) -> RouterQuerier<'a, CustomT::ExecC, CustomT::QueryC> {
RouterQuerier {
router: self,
api,
storage,
block_info,
}
}
}

pub trait CosmosRouter {
type ExecC;
type QueryC: CustomQuery;

fn execute(
&self,
api: &dyn Api,
storage: &mut dyn Storage,
block: &BlockInfo,
sender: Addr,
msg: CosmosMsg<Self::ExecC>,
) -> AnyResult<AppResponse>;

fn query(
&self,
api: &dyn Api,
storage: &dyn Storage,
block: &BlockInfo,
request: QueryRequest<Self::QueryC>,
) -> AnyResult<Binary>;
}

impl<BankT, CustomT, WasmT> CosmosRouter for Router<BankT, CustomT, WasmT>
where
CustomT::ExecC: std::fmt::Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static,
CustomT::QueryC: CustomQuery + DeserializeOwned + 'static,
CustomT: CustomHandler,
WasmT: Wasm<CustomT::ExecC, CustomT::QueryC>,
BankT: Bank,
{
type ExecC = CustomT::ExecC;
type QueryC = CustomT::QueryC;

fn execute(
&self,
api: &dyn Api,
storage: &mut dyn Storage,
block: &BlockInfo,
sender: Addr,
msg: CosmosMsg<Self::ExecC>,
) -> AnyResult<AppResponse> {
match msg {
CosmosMsg::Wasm(msg) => self.wasm.execute(api, storage, self, block, sender, msg),
CosmosMsg::Bank(msg) => self.bank.execute(storage, sender, msg),
CosmosMsg::Custom(msg) => self.custom.execute(api, storage, block, sender, msg),
_ => unimplemented!(),
}
}

/// this is used by `RouterQuerier` to actual implement the `Querier` interface.
/// you most likely want to use `router.querier(storage, block).wrap()` to get a
/// QuerierWrapper to interact with
pub fn query(
fn query(
&self,
api: &dyn Api,
storage: &dyn Storage,
block: &BlockInfo,
request: QueryRequest<CustomT::QueryC>,
) -> AnyResult<Binary>
where
CustomT::QueryC: CustomQuery + DeserializeOwned + 'static,
CustomT::ExecC:
std::fmt::Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static,
WasmT: Wasm<CustomT::ExecC, CustomT::QueryC>,
BankT: Bank,
CustomT: CustomHandler,
{
request: QueryRequest<Self::QueryC>,
) -> AnyResult<Binary> {
match request {
QueryRequest::Wasm(req) => {
self.wasm
Expand All @@ -492,40 +545,18 @@ impl<BankT, CustomT, WasmT> Router<BankT, CustomT, WasmT> {
_ => unimplemented!(),
}
}

pub fn execute(
&self,
api: &dyn Api,
storage: &mut dyn Storage,
block: &BlockInfo,
sender: Addr,
msg: CosmosMsg<CustomT::ExecC>,
) -> AnyResult<AppResponse>
where
CustomT::ExecC: std::fmt::Debug + Clone + PartialEq + JsonSchema,
WasmT: Wasm<CustomT::ExecC, CustomT::QueryC>,
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),
CosmosMsg::Custom(msg) => self.custom.execute(api, storage, block, sender, msg),
_ => unimplemented!(),
}
}
}

pub struct RouterQuerier<'a, Bank, Custom, Wasm> {
router: &'a Router<Bank, Custom, Wasm>,
pub struct RouterQuerier<'a, ExecC, QueryC> {
router: &'a dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
api: &'a dyn Api,
storage: &'a dyn Storage,
block_info: &'a BlockInfo,
}

impl<'a, Bank, Custom, Wasm> RouterQuerier<'a, Bank, Custom, Wasm> {
impl<'a, ExecC, QueryC> RouterQuerier<'a, ExecC, QueryC> {
pub fn new(
router: &'a Router<Bank, Custom, Wasm>,
router: &'a dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
api: &'a dyn Api,
storage: &'a dyn Storage,
block_info: &'a BlockInfo,
Expand All @@ -539,16 +570,13 @@ impl<'a, Bank, Custom, Wasm> RouterQuerier<'a, Bank, Custom, Wasm> {
}
}

impl<'a, BankT, CustomT, WasmT> Querier for RouterQuerier<'a, BankT, CustomT, WasmT>
impl<'a, ExecC, QueryC> Querier for RouterQuerier<'a, ExecC, QueryC>
where
CustomT::ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
CustomT::QueryC: CustomQuery + DeserializeOwned + 'static,
WasmT: Wasm<CustomT::ExecC, CustomT::QueryC>,
BankT: Bank,
CustomT: CustomHandler,
ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
QueryC: CustomQuery + DeserializeOwned + 'static,
{
fn raw_query(&self, bin_request: &[u8]) -> QuerierResult {
let request: QueryRequest<CustomT::QueryC> = match from_slice(bin_request) {
let request: QueryRequest<QueryC> = match from_slice(bin_request) {
Ok(v) => v,
Err(e) => {
return SystemResult::Err(SystemError::InvalidRequest {
Expand Down Expand Up @@ -622,7 +650,7 @@ mod test {

// send both tokens
let to_send = vec![coin(30, "eth"), coin(5, "btc")];
let msg: CosmosMsg = BankMsg::Send {
let msg: cosmwasm_std::CosmosMsg = BankMsg::Send {
to_address: rcpt.clone().into(),
amount: to_send,
}
Expand Down
1 change: 1 addition & 0 deletions packages/multi-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod error;
mod executor;
mod test_helpers;
mod transactions;
mod untyped_msg;
mod wasm;

pub use crate::app::{custom_app, next_block, App, AppBuilder, BasicApp, Router};
Expand Down
95 changes: 95 additions & 0 deletions packages/multi-test/src/untyped_msg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::fmt;

use cosmwasm_std::{BankMsg, DistributionMsg, Empty, StakingMsg, WasmMsg};

/// This is needed so we can embed CosmosMsg as a trait bound.
/// See https://github.com/CosmWasm/cosmwasm/pull/1098 for a proper solution
/// (when we can deprecate this one)
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum CosmosMsg<T = Empty> {
Bank(BankMsg),
// by default we use RawMsg, but a contract can override that
// to call into more app-specific code (whatever they define)
Custom(T),
#[cfg(feature = "staking")]
Distribution(DistributionMsg),
#[cfg(feature = "staking")]
Staking(StakingMsg),
Wasm(WasmMsg),
}

impl<T> From<CosmosMsg<T>> for cosmwasm_std::CosmosMsg<T>
where
T: Clone + fmt::Debug + PartialEq + JsonSchema,
{
fn from(input: CosmosMsg<T>) -> Self {
match input {
CosmosMsg::Bank(b) => cosmwasm_std::CosmosMsg::Bank(b),
CosmosMsg::Custom(c) => cosmwasm_std::CosmosMsg::Custom(c),
#[cfg(feature = "staking")]
CosmosMsg::Distribution(d) => cosmwasm_std::CosmosMsg::Distribution(d),
#[cfg(feature = "staking")]
CosmosMsg::Staking(s) => cosmwasm_std::CosmosMsg::Staking(s),
CosmosMsg::Wasm(w) => cosmwasm_std::CosmosMsg::Wasm(w),
}
}
}

impl<T> From<cosmwasm_std::CosmosMsg<T>> for CosmosMsg<T>
where
T: Clone + fmt::Debug + PartialEq + JsonSchema,
{
fn from(input: cosmwasm_std::CosmosMsg<T>) -> CosmosMsg<T> {
match input {
cosmwasm_std::CosmosMsg::Bank(b) => CosmosMsg::Bank(b),
cosmwasm_std::CosmosMsg::Custom(c) => CosmosMsg::Custom(c),
#[cfg(feature = "staking")]
cosmwasm_std::CosmosMsg::Distribution(d) => CosmosMsg::Distribution(d),
#[cfg(feature = "staking")]
cosmwasm_std::CosmosMsg::Staking(s) => CosmosMsg::Staking(s),
cosmwasm_std::CosmosMsg::Wasm(w) => CosmosMsg::Wasm(w),
_ => panic!("Unsupported type"),
}
}
}

impl<T> From<BankMsg> for CosmosMsg<T>
where
T: Clone + fmt::Debug + PartialEq + JsonSchema,
{
fn from(msg: BankMsg) -> Self {
CosmosMsg::Bank(msg)
}
}

#[cfg(feature = "staking")]
impl<T> From<StakingMsg> for CosmosMsg<T>
where
T: Clone + fmt::Debug + PartialEq + JsonSchema,
{
fn from(msg: StakingMsg) -> Self {
CosmosMsg::Staking(msg)
}
}

#[cfg(feature = "staking")]
impl<T> From<DistributionMsg> for CosmosMsg<T>
where
T: Clone + fmt::Debug + PartialEq + JsonSchema,
{
fn from(msg: DistributionMsg) -> Self {
CosmosMsg::Distribution(msg)
}
}

impl<T> From<WasmMsg> for CosmosMsg<T>
where
T: Clone + fmt::Debug + PartialEq + JsonSchema,
{
fn from(msg: WasmMsg) -> Self {
CosmosMsg::Wasm(msg)
}
}
Loading