From 5b99da6abd7c778e174dd7ef046158e0dbd78c8e Mon Sep 17 00:00:00 2001 From: Costa Giannakakis <77694967+costa2400@users.noreply.github.com> Date: Tue, 28 Nov 2023 23:30:10 -0500 Subject: [PATCH 001/250] Update Crates definitions --- src/addons/mod.rs | 10 +++++++--- src/app.rs | 11 ++++++++--- src/app_builder.rs | 1 + src/custom_handler.rs | 12 +++++++++--- src/error.rs | 4 +++- src/tests/test_custom_handler.rs | 3 +++ 6 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/addons/mod.rs b/src/addons/mod.rs index c31658c3..9e29464c 100644 --- a/src/addons/mod.rs +++ b/src/addons/mod.rs @@ -1,7 +1,11 @@ + + //! # MultiTest add-ons -//! -//! Additional components and functionalities used to enhance -//! or customize tests of CosmWasm smart contracts. +//! +//! MultiTest addons provide additional tools for testing smart contracts, +//! simulating complex blockchain scenarios that developers might encounter. +//! They enhance the CosmWasm environment, enabling more advanced and nuanced testing. + mod addresses; mod api; diff --git a/src/app.rs b/src/app.rs index a52c3b58..ea57f3b1 100644 --- a/src/app.rs +++ b/src/app.rs @@ -38,9 +38,14 @@ pub type BasicApp = App< GovFailingModule, >; -/// 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. + +/// The App struct in cw-multi-test serves as a router with persisted state +/// for querying the blockchain's current status. It primarily uses RouterCache for +/// executing transactions, which allows for preliminary testing of operations before +/// they are permanently applied. The provided .execute() method streamlines this process, +/// handling the execution, review, and finalization (commit or rollback) of these operations, +/// simplifying state management and transaction testing in the CosmWasm framework. + #[derive(Clone)] pub struct App< Bank = BankKeeper, diff --git a/src/app_builder.rs b/src/app_builder.rs index 884a5569..9d908211 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -1,4 +1,5 @@ //! Implementation of the builder for [App]. +//!AppBuilder helps you set up your test blockchain environment step by step. use crate::{ App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingModule, Gov, GovFailingModule, diff --git a/src/custom_handler.rs b/src/custom_handler.rs index cb634b59..0ce6c577 100644 --- a/src/custom_handler.rs +++ b/src/custom_handler.rs @@ -7,9 +7,11 @@ use std::cell::{Ref, RefCell}; use std::ops::Deref; use std::rc::Rc; -/// Internal state of `CachingCustomHandler` wrapping internal mutability so it is not exposed to -/// user. Those have to be shared internal state, as after mock is passed to app it is not -/// possible to access mock internals which are not exposed by API. + +/// This struct serves as the internal state of CachingCustomHandler, carefully managing +/// internal mutability to keep it hidden from users. It's essential for maintaining a shared +/// internal state, especially since accessing mock internals becomes impossible once the +/// mock is passed to the app and not exposed by the API. #[derive(Derivative)] #[derivative(Default(bound = "", new = "true"), Clone(bound = ""))] pub struct CachingCustomHandlerState { @@ -34,6 +36,10 @@ impl CachingCustomHandlerState { /// Custom handler storing all the messages it received, so they can be later verified. /// State is thin shared state, so it can be hold after mock is passed to App to read state. +/// +/// Manages the internal state of a custom handler, recording execution and query messages. +/// Useful for tracking contract interactions during tests. +/// #[derive(Clone, Derivative)] #[derivative(Default(bound = "", new = "true"))] pub struct CachingCustomHandler { diff --git a/src/error.rs b/src/error.rs index 8cd06eec..81f26418 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,7 +1,9 @@ pub use anyhow::{anyhow, bail, Context as AnyContext, Error as AnyError, Result as AnyResult}; use cosmwasm_std::{WasmMsg, WasmQuery}; use thiserror::Error; - +///The error module deals with identifying and reporting problems that occur during testing. +///It's like a diagnostic tool that helps you understand what went wrong and where, so you can fix issues +/// more effectively. #[derive(Debug, Error, PartialEq, Eq)] pub enum Error { #[error("Empty attribute key. Value: {value}")] diff --git a/src/tests/test_custom_handler.rs b/src/tests/test_custom_handler.rs index 834f1e73..cb2fe6e7 100644 --- a/src/tests/test_custom_handler.rs +++ b/src/tests/test_custom_handler.rs @@ -4,6 +4,9 @@ use crate::{App, Module}; use cosmwasm_std::testing::MockStorage; use cosmwasm_std::{Addr, Empty}; +///Custom handlers in CosmWasm allow developers to incorporate their own unique logic into tests. +///This feature is valuable for tailoring the testing environment to reflect specific +/// use-cases or behaviors in a CosmWasm-based smart contract. #[test] fn custom_handler_works() { // prepare needed tools From 3ede6d80937ac5cb9b414e6e945adc74fab596c4 Mon Sep 17 00:00:00 2001 From: Costa Giannakakis <77694967+costa2400@users.noreply.github.com> Date: Tue, 28 Nov 2023 23:34:09 -0500 Subject: [PATCH 002/250] Updates crates definition From 721736f6ebc3b63894999a6dfa593bb01eeac887 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 29 Nov 2023 11:04:50 +0100 Subject: [PATCH 003/250] Made no_init function public. --- Cargo.lock | 4 ++-- src/app.rs | 8 +++++--- src/app_builder.rs | 4 ++-- src/lib.rs | 4 +++- src/tests/test_app.rs | 11 +++++------ tests/test_app/test_instantiate2.rs | 4 ++-- tests/test_app_builder/test_with_api.rs | 4 ++-- tests/test_app_builder/test_with_bank.rs | 4 ++-- tests/test_app_builder/test_with_block.rs | 6 ++---- tests/test_app_builder/test_with_distribution.rs | 4 ++-- tests/test_app_builder/test_with_gov.rs | 4 ++-- tests/test_app_builder/test_with_ibc.rs | 4 ++-- tests/test_app_builder/test_with_staking.rs | 6 ++++-- tests/test_app_builder/test_with_storage.rs | 4 ++-- tests/test_app_builder/test_with_wasm.rs | 10 ++++------ tests/test_wasm/test_with_addr_gen.rs | 8 ++++---- tests/test_wasm/test_with_checksum_gen.rs | 6 ++---- 17 files changed, 47 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 548d3c82..e9ffa424 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -794,9 +794,9 @@ dependencies = [ [[package]] name = "spki" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", diff --git a/src/app.rs b/src/app.rs index a52c3b58..5c913275 100644 --- a/src/app.rs +++ b/src/app.rs @@ -59,11 +59,13 @@ pub struct App< pub(crate) block: BlockInfo, } +/// No-op application initialization function. pub fn no_init( - _: &mut Router, - _: &dyn Api, - _: &mut dyn Storage, + router: &mut Router, + api: &dyn Api, + storage: &mut dyn Storage, ) { + let _ = (router, api, storage); } impl Default for BasicApp { diff --git a/src/app_builder.rs b/src/app_builder.rs index 884a5569..8e9e738c 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -16,14 +16,14 @@ use std::fmt::Debug; /// /// ``` /// # use cosmwasm_std::Empty; -/// # use cw_multi_test::{BasicAppBuilder, FailingModule, Module}; +/// # use cw_multi_test::{BasicAppBuilder, FailingModule, Module, no_init}; /// # type MyHandler = FailingModule; /// # type MyExecC = Empty; /// # type MyQueryC = Empty; /// /// let mut app = BasicAppBuilder::::new_custom() /// .with_custom(MyHandler::default()) -/// .build(|_, _, _| {}); +/// .build(no_init); /// ``` pub type BasicAppBuilder = AppBuilder< BankKeeper, diff --git a/src/lib.rs b/src/lib.rs index 91a9f40d..e30c2185 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,7 +28,9 @@ mod transactions; mod wasm; pub use crate::addresses::{AddressGenerator, SimpleAddressGenerator}; -pub use crate::app::{custom_app, next_block, App, BasicApp, CosmosRouter, Router, SudoMsg}; +pub use crate::app::{ + custom_app, next_block, no_init, App, BasicApp, CosmosRouter, Router, SudoMsg, +}; pub use crate::app_builder::{AppBuilder, BasicAppBuilder}; pub use crate::bank::{Bank, BankKeeper, BankSudo}; pub use crate::checksums::ChecksumGenerator; diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 6d9817a1..8e19e3da 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -1,4 +1,3 @@ -use crate::app::no_init; use crate::custom_handler::CachingCustomHandler; use crate::error::{bail, AnyResult}; use crate::test_helpers::echo::EXECUTE_REPLY_BASE_ID; @@ -7,8 +6,8 @@ use crate::transactions::{transactional, StorageTransaction}; use crate::wasm::ContractData; use crate::AppBuilder; use crate::{ - custom_app, next_block, App, AppResponse, Bank, CosmosRouter, Distribution, Executor, Module, - Router, Staking, Wasm, WasmSudo, + custom_app, next_block, no_init, App, AppResponse, Bank, CosmosRouter, Distribution, Executor, + Module, Router, Staking, Wasm, WasmSudo, }; use cosmwasm_std::testing::{mock_env, MockQuerier}; use cosmwasm_std::{ @@ -1705,7 +1704,7 @@ mod protobuf_wrapped_data { #[test] fn instantiate_with_data_works() { let owner = Addr::unchecked("owner"); - let mut app = BasicApp::new(|_, _, _| {}); + let mut app = BasicApp::new(no_init); // set up echo contract let code_id = app.store_code(echo::contract()); @@ -1734,7 +1733,7 @@ mod protobuf_wrapped_data { #[test] fn instantiate_with_reply_works() { let owner = Addr::unchecked("owner"); - let mut app = BasicApp::new(|_, _, _| {}); + let mut app = BasicApp::new(no_init); // set up echo contract let code_id = app.store_code(echo::contract()); @@ -1786,7 +1785,7 @@ mod protobuf_wrapped_data { #[test] fn execute_wrapped_properly() { let owner = Addr::unchecked("owner"); - let mut app = BasicApp::new(|_, _, _| {}); + let mut app = BasicApp::new(no_init); // set up reflect contract let code_id = app.store_code(echo::contract()); diff --git a/tests/test_app/test_instantiate2.rs b/tests/test_app/test_instantiate2.rs index 4e2a810b..13cc8d34 100644 --- a/tests/test_app/test_instantiate2.rs +++ b/tests/test_app/test_instantiate2.rs @@ -3,7 +3,7 @@ use crate::test_contracts::counter; use cosmwasm_std::{instantiate2_address, to_json_binary, Api, Empty, WasmMsg}; use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; -use cw_multi_test::{AppBuilder, Executor, WasmKeeper}; +use cw_multi_test::{no_init, AppBuilder, Executor, WasmKeeper}; use cw_utils::parse_instantiate_response_data; #[test] @@ -12,7 +12,7 @@ fn instantiate2_works() { let mut app = AppBuilder::default() .with_api(MockApiBech32::new("juno")) .with_wasm(WasmKeeper::default().with_address_generator(MockAddressGenerator)) - .build(|_, _, _| {}); + .build(no_init); // prepare addresses for sender and creator let sender = app.api().addr_make("sender"); diff --git a/tests/test_app_builder/test_with_api.rs b/tests/test_app_builder/test_with_api.rs index 46a92b73..c96184d4 100644 --- a/tests/test_app_builder/test_with_api.rs +++ b/tests/test_app_builder/test_with_api.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{Addr, Api, CanonicalAddr, HexBinary}; use cw_multi_test::addons::MockApiBech32; -use cw_multi_test::AppBuilder; +use cw_multi_test::{no_init, AppBuilder}; #[test] fn building_app_with_custom_api_should_work() { @@ -12,7 +12,7 @@ fn building_app_with_custom_api_should_work() { // Bech32 address encoding with 'juno' prefix let app = AppBuilder::default() .with_api(MockApiBech32::new("juno")) - .build(|_, _, _| {}); + .build(no_init); // check address validation function assert_eq!( diff --git a/tests/test_app_builder/test_with_bank.rs b/tests/test_app_builder/test_with_bank.rs index 7dd63fbd..fa9f1758 100644 --- a/tests/test_app_builder/test_with_bank.rs +++ b/tests/test_app_builder/test_with_bank.rs @@ -1,6 +1,6 @@ use crate::test_app_builder::MyKeeper; use cosmwasm_std::{coins, Addr, BankMsg, BankQuery}; -use cw_multi_test::{AppBuilder, Bank, BankSudo, Executor}; +use cw_multi_test::{no_init, AppBuilder, Bank, BankSudo, Executor}; type MyBankKeeper = MyKeeper; @@ -17,7 +17,7 @@ fn building_app_with_custom_bank_should_work() { // build the application with custom bank keeper let app_builder = AppBuilder::default(); - let mut app = app_builder.with_bank(bank_keeper).build(|_, _, _| {}); + let mut app = app_builder.with_bank(bank_keeper).build(no_init); // prepare additional input data let recipient = Addr::unchecked("recipient"); diff --git a/tests/test_app_builder/test_with_block.rs b/tests/test_app_builder/test_with_block.rs index 18178ba7..35faed2b 100644 --- a/tests/test_app_builder/test_with_block.rs +++ b/tests/test_app_builder/test_with_block.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{BlockInfo, Timestamp}; -use cw_multi_test::AppBuilder; +use cw_multi_test::{no_init, AppBuilder}; #[test] fn building_app_with_custom_block_should_work() { @@ -12,9 +12,7 @@ fn building_app_with_custom_block_should_work() { // build the application with custom block let app_builder = AppBuilder::default(); - let app = app_builder - .with_block(block_info.clone()) - .build(|_, _, _| {}); + let app = app_builder.with_block(block_info.clone()).build(no_init); // calling block_info should return the same block used during initialization assert_eq!(block_info, app.block_info()); diff --git a/tests/test_app_builder/test_with_distribution.rs b/tests/test_app_builder/test_with_distribution.rs index a3ec7138..b7e653e1 100644 --- a/tests/test_app_builder/test_with_distribution.rs +++ b/tests/test_app_builder/test_with_distribution.rs @@ -1,6 +1,6 @@ use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; use cosmwasm_std::{Addr, DistributionMsg, Empty}; -use cw_multi_test::{AppBuilder, Distribution, Executor}; +use cw_multi_test::{no_init, AppBuilder, Distribution, Executor}; type MyDistributionKeeper = MyKeeper; @@ -18,7 +18,7 @@ fn building_app_with_custom_distribution_should_work() { let app_builder = AppBuilder::default(); let mut app = app_builder .with_distribution(distribution_keeper) - .build(|_, _, _| {}); + .build(no_init); // prepare additional input data let recipient = Addr::unchecked("recipient"); diff --git a/tests/test_app_builder/test_with_gov.rs b/tests/test_app_builder/test_with_gov.rs index 92536c85..7f47095a 100644 --- a/tests/test_app_builder/test_with_gov.rs +++ b/tests/test_app_builder/test_with_gov.rs @@ -1,6 +1,6 @@ use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; use cosmwasm_std::{Addr, Empty, GovMsg, VoteOption}; -use cw_multi_test::{AppBuilder, Executor, Gov}; +use cw_multi_test::{no_init, AppBuilder, Executor, Gov}; type MyGovKeeper = MyKeeper; @@ -15,7 +15,7 @@ fn building_app_with_custom_gov_should_work() { // build the application with custom gov keeper let app_builder = AppBuilder::default(); - let mut app = app_builder.with_gov(gov_keeper).build(|_, _, _| {}); + let mut app = app_builder.with_gov(gov_keeper).build(no_init); // executing gov message should return an error defined in custom keeper assert_eq!( diff --git a/tests/test_app_builder/test_with_ibc.rs b/tests/test_app_builder/test_with_ibc.rs index 4e4e8a91..431570e0 100644 --- a/tests/test_app_builder/test_with_ibc.rs +++ b/tests/test_app_builder/test_with_ibc.rs @@ -1,6 +1,6 @@ use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; use cosmwasm_std::{Addr, Empty, IbcMsg, IbcQuery, QueryRequest}; -use cw_multi_test::{AppBuilder, Executor, Ibc}; +use cw_multi_test::{no_init, AppBuilder, Executor, Ibc}; type MyIbcKeeper = MyKeeper; @@ -16,7 +16,7 @@ fn building_app_with_custom_ibc_should_work() { // build the application with custom ibc keeper let app_builder = AppBuilder::default(); - let mut app = app_builder.with_ibc(ibc_keeper).build(|_, _, _| {}); + let mut app = app_builder.with_ibc(ibc_keeper).build(no_init); // executing ibc message should return an error defined in custom keeper assert_eq!( diff --git a/tests/test_app_builder/test_with_staking.rs b/tests/test_app_builder/test_with_staking.rs index 97990dcd..798b42d5 100644 --- a/tests/test_app_builder/test_with_staking.rs +++ b/tests/test_app_builder/test_with_staking.rs @@ -1,7 +1,9 @@ use crate::test_app_builder::MyKeeper; use cosmwasm_std::{Addr, Api, BlockInfo, Coin, CustomQuery, StakingMsg, StakingQuery, Storage}; use cw_multi_test::error::AnyResult; -use cw_multi_test::{AppBuilder, AppResponse, CosmosRouter, Executor, Staking, StakingSudo}; +use cw_multi_test::{ + no_init, AppBuilder, AppResponse, CosmosRouter, Executor, Staking, StakingSudo, +}; type MyStakeKeeper = MyKeeper; @@ -29,7 +31,7 @@ fn building_app_with_custom_staking_should_work() { // build the application with custom stake keeper let app_builder = AppBuilder::default(); - let mut app = app_builder.with_staking(stake_keeper).build(|_, _, _| {}); + let mut app = app_builder.with_staking(stake_keeper).build(no_init); // prepare additional input data let validator = Addr::unchecked("recipient"); diff --git a/tests/test_app_builder/test_with_storage.rs b/tests/test_app_builder/test_with_storage.rs index 378b321c..b6106d7f 100644 --- a/tests/test_app_builder/test_with_storage.rs +++ b/tests/test_app_builder/test_with_storage.rs @@ -1,6 +1,6 @@ use crate::{test_contracts, CounterQueryMsg, CounterResponseMsg}; use cosmwasm_std::{to_json_binary, Addr, Empty, Order, Record, Storage, WasmMsg}; -use cw_multi_test::{AppBuilder, Executor}; +use cw_multi_test::{no_init, AppBuilder, Executor}; use std::collections::BTreeMap; use std::iter; @@ -44,7 +44,7 @@ fn building_app_with_custom_storage_should_work() { let app_builder = AppBuilder::default(); let mut app = app_builder .with_storage(MyStorage::default()) - .build(|_, _, _| {}); + .build(no_init); // store a contract code let code_id = app.store_code(test_contracts::counter::contract()); diff --git a/tests/test_app_builder/test_with_wasm.rs b/tests/test_app_builder/test_with_wasm.rs index 96a5bb71..13f4b05f 100644 --- a/tests/test_app_builder/test_with_wasm.rs +++ b/tests/test_app_builder/test_with_wasm.rs @@ -5,8 +5,8 @@ use cosmwasm_std::{ }; use cw_multi_test::error::{bail, AnyResult}; use cw_multi_test::{ - AppBuilder, AppResponse, Contract, ContractData, CosmosRouter, Executor, Wasm, WasmKeeper, - WasmSudo, + no_init, AppBuilder, AppResponse, Contract, ContractData, CosmosRouter, Executor, Wasm, + WasmKeeper, WasmSudo, }; use once_cell::sync::Lazy; @@ -84,7 +84,7 @@ fn building_app_with_custom_wasm_should_work() { // build the application with custom wasm keeper let app_builder = AppBuilder::default(); - let mut app = app_builder.with_wasm(wasm_keeper).build(|_, _, _| {}); + let mut app = app_builder.with_wasm(wasm_keeper).build(no_init); // prepare additional input data let contract_addr = Addr::unchecked("contract"); @@ -155,7 +155,5 @@ fn compiling_with_wasm_keeper_should_work() { // this verifies only compilation errors // while our WasmKeeper does not implement Module let app_builder = AppBuilder::default(); - let _ = app_builder - .with_wasm(WasmKeeper::default()) - .build(|_, _, _| {}); + let _ = app_builder.with_wasm(WasmKeeper::default()).build(no_init); } diff --git a/tests/test_wasm/test_with_addr_gen.rs b/tests/test_wasm/test_with_addr_gen.rs index ef7bdaa5..61bb4601 100644 --- a/tests/test_wasm/test_with_addr_gen.rs +++ b/tests/test_wasm/test_with_addr_gen.rs @@ -1,7 +1,7 @@ use crate::test_contracts; use cosmwasm_std::{Addr, Empty}; use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; -use cw_multi_test::{AppBuilder, Executor, WasmKeeper}; +use cw_multi_test::{no_init, AppBuilder, Executor, WasmKeeper}; #[test] fn contract_address_should_work() { @@ -13,7 +13,7 @@ fn contract_address_should_work() { let mut app = AppBuilder::default() .with_api(MockApiBech32::new("purple")) .with_wasm(wasm_keeper) - .build(|_, _, _| {}); + .build(no_init); // store contract's code let code_id = app.store_code_with_creator( @@ -56,7 +56,7 @@ fn predictable_contract_address_should_work() { let mut app = AppBuilder::default() .with_api(MockApiBech32::new("juno")) .with_wasm(wasm_keeper) - .build(|_, _, _| {}); + .build(no_init); let creator = app.api().addr_make("creator"); @@ -114,7 +114,7 @@ fn creating_contract_with_the_same_predictable_address_should_fail() { let mut app = AppBuilder::default() .with_api(MockApiBech32::new("juno")) .with_wasm(wasm_keeper) - .build(|_, _, _| {}); + .build(no_init); let creator = app.api().addr_make("creator"); diff --git a/tests/test_wasm/test_with_checksum_gen.rs b/tests/test_wasm/test_with_checksum_gen.rs index 56029b92..8917a29c 100644 --- a/tests/test_wasm/test_with_checksum_gen.rs +++ b/tests/test_wasm/test_with_checksum_gen.rs @@ -2,7 +2,7 @@ use crate::test_contracts; use cosmwasm_std::{Addr, Empty, HexBinary}; -use cw_multi_test::{App, AppBuilder, ChecksumGenerator, WasmKeeper}; +use cw_multi_test::{no_init, App, AppBuilder, ChecksumGenerator, WasmKeeper}; #[test] fn default_checksum_generator_should_work() { @@ -41,9 +41,7 @@ fn custom_checksum_generator_should_work() { WasmKeeper::default().with_checksum_generator(MyChecksumGenerator); // prepare application with custom wasm keeper - let mut app = AppBuilder::default() - .with_wasm(wasm_keeper) - .build(|_, _, _| {}); + let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init); // store contract's code let code_id = app.store_code_with_creator( From 2b916ad115626f5e2539088847529914a4221cb8 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 29 Nov 2023 11:38:06 +0100 Subject: [PATCH 004/250] Added separated test helper contracts for gov and ibc. --- src/test_helpers/gov.rs | 27 ++++++++++ src/test_helpers/ibc.rs | 26 +++++++++ src/test_helpers/mod.rs | 3 +- src/test_helpers/stargate.rs | 42 --------------- src/tests/test_gov.rs | 102 +++++++---------------------------- src/tests/test_ibc.rs | 44 +++++++-------- 6 files changed, 94 insertions(+), 150 deletions(-) create mode 100644 src/test_helpers/gov.rs create mode 100644 src/test_helpers/ibc.rs delete mode 100644 src/test_helpers/stargate.rs diff --git a/src/test_helpers/gov.rs b/src/test_helpers/gov.rs new file mode 100644 index 00000000..bc5a413b --- /dev/null +++ b/src/test_helpers/gov.rs @@ -0,0 +1,27 @@ +use crate::{Contract, ContractWrapper}; +use cosmwasm_std::{ + Binary, CosmosMsg, Deps, DepsMut, Empty, Env, GovMsg, MessageInfo, Response, StdResult, +}; + +fn instantiate(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { + Ok(Response::new()) +} + +fn execute(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { + let msg: CosmosMsg = GovMsg::Vote { + proposal_id: 1, + vote: cosmwasm_std::VoteOption::No, + } + .into(); + let resp = Response::new().add_message(msg); + Ok(resp) +} + +fn query(_deps: Deps, _env: Env, _msg: Empty) -> StdResult { + Ok(Binary::default()) +} + +pub fn contract() -> Box> { + let contract = ContractWrapper::new(execute, instantiate, query); + Box::new(contract) +} diff --git a/src/test_helpers/ibc.rs b/src/test_helpers/ibc.rs new file mode 100644 index 00000000..402edda6 --- /dev/null +++ b/src/test_helpers/ibc.rs @@ -0,0 +1,26 @@ +use crate::{Contract, ContractWrapper}; +use cosmwasm_std::{ + Binary, CosmosMsg, Deps, DepsMut, Empty, Env, IbcMsg, MessageInfo, Response, StdResult, +}; + +fn instantiate(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { + Ok(Response::new()) +} + +fn execute(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { + let msg: CosmosMsg = IbcMsg::CloseChannel { + channel_id: "channel".to_string(), + } + .into(); + let resp = Response::new().add_message(msg); + Ok(resp) +} + +fn query(_deps: Deps, _env: Env, _msg: Empty) -> StdResult { + Ok(Binary::default()) +} + +pub fn contract() -> Box> { + let contract = ContractWrapper::new(execute, instantiate, query); + Box::new(contract) +} diff --git a/src/test_helpers/mod.rs b/src/test_helpers/mod.rs index f67efbc5..dc87c895 100644 --- a/src/test_helpers/mod.rs +++ b/src/test_helpers/mod.rs @@ -7,10 +7,11 @@ use serde::{Deserialize, Serialize}; pub mod caller; pub mod echo; pub mod error; +pub mod gov; pub mod hackatom; +pub mod ibc; pub mod payout; pub mod reflect; -pub mod stargate; /// Custom message for testing purposes. #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] diff --git a/src/test_helpers/stargate.rs b/src/test_helpers/stargate.rs deleted file mode 100644 index 0a31efcb..00000000 --- a/src/test_helpers/stargate.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::{Contract, ContractWrapper}; -use cosmwasm_std::{ - Binary, CosmosMsg, Deps, DepsMut, Empty, Env, GovMsg, IbcMsg, MessageInfo, Response, StdResult, -}; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum ExecMsg { - Ibc {}, - Gov {}, -} - -fn instantiate(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { - Ok(Response::new()) -} - -fn execute(_deps: DepsMut, _env: Env, _info: MessageInfo, msg: ExecMsg) -> StdResult { - let msg: CosmosMsg = if let ExecMsg::Ibc {} = msg { - IbcMsg::CloseChannel { - channel_id: "channel".to_string(), - } - .into() - } else { - GovMsg::Vote { - proposal_id: 1, - vote: cosmwasm_std::VoteOption::No, - } - .into() - }; - - let resp = Response::new().add_message(msg); - Ok(resp) -} - -fn query(_deps: Deps, _env: Env, _msg: Empty) -> StdResult { - Ok(Binary::default()) -} - -pub fn contract() -> Box> { - let contract = ContractWrapper::new(execute, instantiate, query); - Box::new(contract) -} diff --git a/src/tests/test_gov.rs b/src/tests/test_gov.rs index e900c40f..68897735 100644 --- a/src/tests/test_gov.rs +++ b/src/tests/test_gov.rs @@ -1,99 +1,37 @@ -use crate::error::AnyResult; -use crate::test_helpers::{stargate, stargate::ExecMsg}; -use crate::{App, AppBuilder, AppResponse, CosmosRouter, Executor, Gov, Module}; -use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomQuery, Empty, GovMsg, Querier, Storage}; -use schemars::JsonSchema; -use serde::de::DeserializeOwned; -use std::fmt::Debug; - -struct AcceptingModule; - -impl Module for AcceptingModule { - type ExecT = GovMsg; - type QueryT = Empty; - type SudoT = Empty; - - fn execute( - &self, - _api: &dyn Api, - _storage: &mut dyn Storage, - _router: &dyn CosmosRouter, - _block: &BlockInfo, - _sender: Addr, - _msg: Self::ExecT, - ) -> AnyResult - where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, - QueryC: CustomQuery + DeserializeOwned + 'static, - { - Ok(AppResponse::default()) - } - - fn sudo( - &self, - _api: &dyn Api, - _storage: &mut dyn Storage, - _router: &dyn CosmosRouter, - _block: &BlockInfo, - _msg: Self::SudoT, - ) -> AnyResult - where - ExecC: Debug + Clone + PartialEq + schemars::JsonSchema + DeserializeOwned + 'static, - QueryC: CustomQuery + DeserializeOwned + 'static, - { - Ok(AppResponse::default()) - } - - fn query( - &self, - _api: &dyn Api, - _storage: &dyn Storage, - _querier: &dyn Querier, - _block: &BlockInfo, - _request: Self::QueryT, - ) -> AnyResult { - Ok(Binary::default()) - } -} - -impl Gov for AcceptingModule {} +use crate::test_helpers::gov; +use crate::{no_init, App, AppBuilder, Executor, GovAcceptingModule}; +use cosmwasm_std::Empty; #[test] fn default_gov() { let mut app = App::default(); - let code = app.store_code(stargate::contract()); + + let creator_addr = app.api().addr_make("creator"); + let code = app.store_code_with_creator(creator_addr, gov::contract()); + + let owner_addr = app.api().addr_make("owner"); let contract = app - .instantiate_contract( - code, - Addr::unchecked("owner"), - &Empty {}, - &[], - "contract", - None, - ) + .instantiate_contract(code, owner_addr.clone(), &Empty {}, &[], "govenius", None) .unwrap(); - app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Gov {}, &[]) + app.execute_contract(owner_addr, contract, &Empty {}, &[]) .unwrap_err(); } #[test] -fn substituting_gov() { +fn accepting_gov() { let mut app = AppBuilder::new() - .with_gov(AcceptingModule) - .build(|_, _, _| ()); - let code = app.store_code(stargate::contract()); + .with_gov(GovAcceptingModule::new()) + .build(no_init); + + let creator_addr = app.api().addr_make("creator"); + let code = app.store_code_with_creator(creator_addr, gov::contract()); + + let owner_addr = app.api().addr_make("owner"); let contract = app - .instantiate_contract( - code, - Addr::unchecked("owner"), - &Empty {}, - &[], - "contract", - None, - ) + .instantiate_contract(code, owner_addr.clone(), &Empty {}, &[], "govenius", None) .unwrap(); - app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Gov {}, &[]) + app.execute_contract(owner_addr, contract, &Empty {}, &[]) .unwrap(); } diff --git a/src/tests/test_ibc.rs b/src/tests/test_ibc.rs index 2497478c..ed32377e 100644 --- a/src/tests/test_ibc.rs +++ b/src/tests/test_ibc.rs @@ -1,43 +1,37 @@ -use crate::test_helpers::{stargate, stargate::ExecMsg}; -use crate::{App, AppBuilder, Executor, IbcAcceptingModule}; -use cosmwasm_std::{Addr, Empty}; +use crate::test_helpers::ibc; +use crate::{no_init, App, AppBuilder, Executor, IbcAcceptingModule}; +use cosmwasm_std::Empty; #[test] fn default_ibc() { let mut app = App::default(); - let code = app.store_code(stargate::contract()); + + let creator_addr = app.api().addr_make("creator"); + let code = app.store_code_with_creator(creator_addr, ibc::contract()); + + let owner_addr = app.api().addr_make("owner"); let contract = app - .instantiate_contract( - code, - Addr::unchecked("owner"), - &Empty {}, - &[], - "contract", - None, - ) + .instantiate_contract(code, owner_addr.clone(), &Empty {}, &[], "ibanera", None) .unwrap(); - app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Ibc {}, &[]) + app.execute_contract(owner_addr, contract, &Empty {}, &[]) .unwrap_err(); } #[test] -fn substituting_ibc() { +fn accepting_ibc() { let mut app = AppBuilder::new() .with_ibc(IbcAcceptingModule::new()) - .build(|_, _, _| ()); - let code = app.store_code(stargate::contract()); + .build(no_init); + + let creator_addr = app.api().addr_make("creator"); + let code = app.store_code_with_creator(creator_addr, ibc::contract()); + + let owner_addr = app.api().addr_make("owner"); let contract = app - .instantiate_contract( - code, - Addr::unchecked("owner"), - &Empty {}, - &[], - "contract", - None, - ) + .instantiate_contract(code, owner_addr.clone(), &Empty {}, &[], "ibanera", None) .unwrap(); - app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Ibc {}, &[]) + app.execute_contract(owner_addr, contract, &Empty {}, &[]) .unwrap(); } From cbaa8619f9cc3a53cd192cf823c8aecfd8f676f7 Mon Sep 17 00:00:00 2001 From: Costa Giannakakis <77694967+costa2400@users.noreply.github.com> Date: Wed, 29 Nov 2023 14:48:49 -0500 Subject: [PATCH 005/250] Updated Crates definitions --- src/app_builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app_builder.rs b/src/app_builder.rs index 9d908211..91d9c8df 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -1,5 +1,5 @@ -//! Implementation of the builder for [App]. -//!AppBuilder helps you set up your test blockchain environment step by step. + +//!AppBuilder helps you set up your test blockchain environment step by step [App]. use crate::{ App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingModule, Gov, GovFailingModule, From bff33fafeb5cd08b58b6280584ff19f3fe90b85e Mon Sep 17 00:00:00 2001 From: Costa Giannakakis <77694967+costa2400@users.noreply.github.com> Date: Wed, 29 Nov 2023 17:02:31 -0500 Subject: [PATCH 006/250] added definitions --- src/addons/mod.rs | 1 - src/app.rs | 13 +++++++++---- src/app_builder.rs | 3 +++ src/bank.rs | 11 +++++++++-- src/checksums.rs | 5 ++++- src/contracts.rs | 9 ++++++--- src/error.rs | 2 ++ src/executor.rs | 8 ++++++-- src/gov.rs | 11 ++++++++--- src/ibc.rs | 12 +++++++++--- src/module.rs | 13 +++++++++---- src/staking.rs | 7 ++++++- src/wasm.rs | 4 +++- tests/test_app_builder/test_with_distribution.rs | 4 +++- 14 files changed, 77 insertions(+), 26 deletions(-) diff --git a/src/addons/mod.rs b/src/addons/mod.rs index 9e29464c..5031943b 100644 --- a/src/addons/mod.rs +++ b/src/addons/mod.rs @@ -1,6 +1,5 @@ -//! # MultiTest add-ons //! //! MultiTest addons provide additional tools for testing smart contracts, //! simulating complex blockchain scenarios that developers might encounter. diff --git a/src/app.rs b/src/app.rs index 34d8b836..773afa5b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -19,13 +19,15 @@ use schemars::JsonSchema; use serde::{de::DeserializeOwned, Serialize}; use std::fmt::Debug; use std::marker::PhantomData; - +/// Advances the blockchain environment to the next block in tests, enabling developers to simulate +/// time-dependent contract behaviors and block-related triggers efficiently. pub fn next_block(block: &mut BlockInfo) { block.time = block.time.plus_seconds(5); block.height += 1; } -/// Type alias for default build `App` to make its storing simpler in typical scenario +/// A type alias for the default-built App. It simplifies storage and handling in typical scenarios, +/// streamlining the use of the App structure in standard test setups. pub type BasicApp = App< BankKeeper, MockApi, @@ -437,7 +439,8 @@ where }) } } - +/// The Router plays a critical role in managing and directing +/// transactions within the Cosmos blockchain. #[derive(Clone)] pub struct Router { // this can remain crate-only as all special functions are wired up to app currently @@ -506,7 +509,9 @@ impl From for SudoMsg { SudoMsg::Staking(staking) } } - +///This trait is designed for routing messages within the Cosmos ecosystem. +/// It's key to ensuring that transactions and contract calls are directed to the +/// correct destinations during testing, simulating real-world blockchain operations. pub trait CosmosRouter { type ExecC; type QueryC: CustomQuery; diff --git a/src/app_builder.rs b/src/app_builder.rs index efb21671..6db59913 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -26,6 +26,9 @@ use std::fmt::Debug; /// .with_custom(MyHandler::default()) /// .build(no_init); /// ``` +/// This type alias is crucial for constructing a custom app with specific modules. +/// It provides a streamlined approach to building and configuring an App tailored to +/// particular testing needs or scenarios. pub type BasicAppBuilder = AppBuilder< BankKeeper, MockApi, diff --git a/src/bank.rs b/src/bank.rs index a2574dcf..bf609bf7 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -25,10 +25,16 @@ pub enum BankSudo { amount: Vec, }, } - +/// This trait defines the interface for simulating banking operations in the test +/// environment. It's essential for testing financial transactions, like transfers +/// and balance checks, within your smart contracts. pub trait Bank: Module {} + #[derive(Default)] +/// Manages financial interactions in CosmWasm tests, such as simulating token transactions +/// and account balances. This is particularly important for contracts that deal with financial +/// operations in the Cosmos ecosystem. pub struct BankKeeper {} impl BankKeeper { @@ -137,7 +143,8 @@ fn coins_to_string(coins: &[Coin]) -> String { .map(|c| format!("{}{}", c.amount, c.denom)) .join(",") } - +///This trait defines the interface for simulating banking operations within the testing environment, +/// essential for creating and testing scenarios involving financial transactions and account management in smart contracts. impl Bank for BankKeeper {} impl Module for BankKeeper { diff --git a/src/checksums.rs b/src/checksums.rs index 0499f8f0..f4d3f428 100644 --- a/src/checksums.rs +++ b/src/checksums.rs @@ -3,7 +3,10 @@ use cosmwasm_std::{Addr, HexBinary}; use sha2::{Digest, Sha256}; -/// An interface to call custom checksum generator for contract's code. +/// Provides a custom interface for generating checksums for contract code. +/// This is crucial for ensuring code integrity and is particularly useful +/// in environments where code verification is a key part of the contract +/// deployment process. /// /// This trait defines a method to calculate checksum based on /// the creator's address and a unique code identifier. diff --git a/src/contracts.rs b/src/contracts.rs index e5f11f12..0650da6b 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -9,7 +9,9 @@ use std::error::Error; use std::fmt::{Debug, Display}; use std::ops::Deref; -/// Interface to call into a `Contract`. +/// Serves as the primary interface for interacting with contracts. +/// It includes methods for executing, querying, and managing contract states, +/// making it a fundamental trait for testing contract functionalities. pub trait Contract where T: Clone + Debug + PartialEq + JsonSchema, @@ -52,8 +54,9 @@ type PermissionedClosure = Box, Env, T) -> Result< type ReplyClosure = Box, Env, Reply) -> Result, E>>; type QueryClosure = Box, Env, T) -> Result>; -/// Wraps the exported functions from a contract and provides the normalized format -/// Place T4 and E4 at the end, as we just want default placeholders for most contracts that don't have sudo +/// Standardizes interactions with contracts in CosmWasm tests, especially useful for contracts that +/// do not possess extensive privileges. It simplifies and unifies the way developers interact with +/// different contracts. pub struct ContractWrapper< T1, T2, diff --git a/src/error.rs b/src/error.rs index 81f26418..1a8a5b4d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,6 +5,8 @@ use thiserror::Error; ///It's like a diagnostic tool that helps you understand what went wrong and where, so you can fix issues /// more effectively. #[derive(Debug, Error, PartialEq, Eq)] +///This module handles error definitions and management within `cw_multi_test``, ensuring that issues +///and exceptions encountered during the testing process are effectively identified and reported. pub enum Error { #[error("Empty attribute key. Value: {value}")] EmptyAttributeKey { value: String }, diff --git a/src/executor.rs b/src/executor.rs index 694894af..24c0ca28 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -7,7 +7,9 @@ use cw_utils::{parse_execute_response_data, parse_instantiate_response_data}; use schemars::JsonSchema; use serde::Serialize; use std::fmt::Debug; - +/// AppResponse likely refers to a standardized response format from the App. +/// It's mentioned in the cw-multi-test-main package, which suggests it's used for returning +/// information about the processing of transactions or queries. #[derive(Default, Clone, Debug)] pub struct AppResponse { pub events: Vec, @@ -58,7 +60,9 @@ impl From for AppResponse { } } } - +///Defines the interface for executing transactions and contract interactions. +/// It's a central component in the testing framework, managing the operational flow and +/// ensuring that contract calls are processed correctly. pub trait Executor where C: Clone + Debug + PartialEq + JsonSchema + 'static, diff --git a/src/gov.rs b/src/gov.rs index 286333a7..f2fe7e21 100644 --- a/src/gov.rs +++ b/src/gov.rs @@ -1,12 +1,17 @@ use crate::{AcceptingModule, FailingModule, Module}; use cosmwasm_std::{Empty, GovMsg}; - +/// Handles governance-related operations within the test environment. +/// This trait is essential for testing contracts that interact with governance mechanisms, +/// simulating proposals, voting, and other governance activities. pub trait Gov: Module {} - +/// A type alias for a module that accepts governance-related interactions. +/// It's used in scenarios where you need to test how your contract interacts +/// with governance processes and messages. pub type GovAcceptingModule = AcceptingModule; impl Gov for GovAcceptingModule {} - +/// This type alias represents a module designed to fail in response to governance operations. +/// It's useful for testing how contracts behave when governance actions do not proceed as expected. pub type GovFailingModule = FailingModule; impl Gov for GovFailingModule {} diff --git a/src/ibc.rs b/src/ibc.rs index 97e5b026..efa27b99 100644 --- a/src/ibc.rs +++ b/src/ibc.rs @@ -1,12 +1,18 @@ use crate::{AcceptingModule, FailingModule, Module}; use cosmwasm_std::{Empty, IbcMsg, IbcQuery}; - +///Manages Inter-Blockchain Communication (IBC) functionalities. +///This trait is critical for testing contracts that involve cross-chain interactions, +///reflecting the interconnected nature of the Cosmos ecosystem. pub trait Ibc: Module {} - +/// Ideal for testing contracts that involve IBC, this module is designed to successfully +/// handle cross-chain messages. It's key for ensuring that your contract can smoothly interact +/// with other blockchains in the Cosmos network. pub type IbcAcceptingModule = AcceptingModule; impl Ibc for IbcAcceptingModule {} - +/// Use this to test how your contract deals with problematic IBC scenarios. +/// It's a module that deliberately fails in handling IBC messages, allowing you +/// to check how your contract behaves in less-than-ideal cross-chain communication situations. pub type IbcFailingModule = FailingModule; impl Ibc for IbcFailingModule {} diff --git a/src/module.rs b/src/module.rs index 3bbe452c..eb9ba0cf 100644 --- a/src/module.rs +++ b/src/module.rs @@ -7,7 +7,9 @@ use serde::de::DeserializeOwned; use std::fmt::Debug; use std::marker::PhantomData; -/// Module interface. +/// Provides a generic interface for modules within the test environment. +/// It's essential for creating modular and extensible testing setups, allowing developers +/// to integrate custom functionalities or test specific scenarios. pub trait Module { type ExecT; type QueryT; @@ -56,9 +58,11 @@ pub trait Module { ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static; } - +/// This could be a diagnostic or testing tool within the Cosmos ecosystem, designed to +/// intentionally fail under certain conditions to test the robustness and error-handling +/// capabilities of the network. pub struct FailingModule(PhantomData<(ExecT, QueryT, SudoT)>); - + impl FailingModule { pub fn new() -> Self { Self(PhantomData) @@ -118,7 +122,8 @@ where bail!("Unexpected sudo msg {:?}", msg) } } - +///This struct might represent a module in the Cosmos ecosystem designed to accept certain types of transactions +/// or interactions. The specific functionality would depend on the context of its use. pub struct AcceptingModule(PhantomData<(ExecT, QueryT, SudoT)>); impl AcceptingModule { diff --git a/src/staking.rs b/src/staking.rs index 5155c672..05466d86 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -117,6 +117,8 @@ pub enum StakingSudo { ProcessQueue {}, } +///Manages staking operations, vital for testing contracts in proof-of-stake (PoS) blockchain environments. +///This trait simulates staking behaviors, including delegation, validator operations, and reward mechanisms. pub trait Staking: Module { /// This is called from the end blocker (`update_block` / `set_block`) to process the /// staking queue. @@ -132,7 +134,7 @@ pub trait Staking: Module {} - +/// pub struct StakeKeeper { module_addr: Addr, } @@ -865,6 +867,9 @@ impl Module for StakeKeeper { } } +/// This module likely manages the distribution of rewards and fees within the blockchain network. +/// It could handle tasks like distributing block rewards to validators and delegators, +/// and managing community funding mechanisms. #[derive(Default)] pub struct DistributionKeeper {} diff --git a/src/wasm.rs b/src/wasm.rs index 4e7fe130..ab48ea3b 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -71,7 +71,9 @@ struct CodeData { code_base_id: usize, } -/// Interface to call into a `Wasm` module. +/// Acts as the interface for interacting with WebAssembly (Wasm) modules. +/// This trait is crucial for testing smart contracts written in languages that compile to WebAssembly, +/// which is common in the Cosmos and CosmWasm ecosystems. pub trait Wasm { /// Handles all `WasmQuery` requests. fn query( diff --git a/tests/test_app_builder/test_with_distribution.rs b/tests/test_app_builder/test_with_distribution.rs index b7e653e1..e9924b41 100644 --- a/tests/test_app_builder/test_with_distribution.rs +++ b/tests/test_app_builder/test_with_distribution.rs @@ -7,7 +7,9 @@ type MyDistributionKeeper = MyKeeper; impl Distribution for MyDistributionKeeper {} const EXECUTE_MSG: &str = "distribution execute called"; - +/// Manages the distribution aspects within tests, simulating scenarios ] +/// like reward distribution or token allocation. This trait is important +/// for contracts that involve distributing assets in a certain way. #[test] fn building_app_with_custom_distribution_should_work() { // build custom distribution keeper From 914da3db732217218489818764cfbb56057f5b9d Mon Sep 17 00:00:00 2001 From: Timofey <5527315+epanchee@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:35:26 +0400 Subject: [PATCH 007/250] add failing test demonstrating custom address generator is broken --- tests/test_wasm/test_with_addr_gen.rs | 37 +++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/tests/test_wasm/test_with_addr_gen.rs b/tests/test_wasm/test_with_addr_gen.rs index 61bb4601..992deeb0 100644 --- a/tests/test_wasm/test_with_addr_gen.rs +++ b/tests/test_wasm/test_with_addr_gen.rs @@ -1,7 +1,7 @@ use crate::test_contracts; -use cosmwasm_std::{Addr, Empty}; +use cosmwasm_std::{Addr, Empty, Storage}; use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; -use cw_multi_test::{no_init, AppBuilder, Executor, WasmKeeper}; +use cw_multi_test::{no_init, AddressGenerator, AppBuilder, Executor, WasmKeeper}; #[test] fn contract_address_should_work() { @@ -45,6 +45,39 @@ fn contract_address_should_work() { ); } +#[test] +fn custom_address_generator_should_work() { + struct CustomAddressGenerator; + + impl AddressGenerator for CustomAddressGenerator { + fn next_address(&self, _storage: &mut dyn Storage) -> Addr { + Addr::unchecked("test_address") + } + } + + // prepare wasm module with custom address generator + let wasm_keeper = WasmKeeper::new().with_address_generator(CustomAddressGenerator); + + let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init); + + // store contract's code + let code_id = app.store_code(test_contracts::counter::contract()); + + let contract_addr = app + .instantiate_contract( + code_id, + Addr::unchecked("owner"), + &Empty {}, + &[], + "Counter", + None, + ) + .unwrap(); + + // make sure that contract address equals to "test_address" generated by custom address generator + assert_eq!(contract_addr.as_str(), "test_address"); +} + #[test] #[cfg(feature = "cosmwasm_1_2")] fn predictable_contract_address_should_work() { From 174d08e6253c6e7ba64f91113ac73aa7d71b39e4 Mon Sep 17 00:00:00 2001 From: Costa Giannakakis <77694967+costa2400@users.noreply.github.com> Date: Thu, 30 Nov 2023 19:18:18 -0500 Subject: [PATCH 008/250] changed lines --- src/addons/mod.rs | 2 -- src/checksums.rs | 1 - src/custom_handler.rs | 1 - 3 files changed, 4 deletions(-) diff --git a/src/addons/mod.rs b/src/addons/mod.rs index 5031943b..b59559db 100644 --- a/src/addons/mod.rs +++ b/src/addons/mod.rs @@ -1,6 +1,4 @@ - -//! //! MultiTest addons provide additional tools for testing smart contracts, //! simulating complex blockchain scenarios that developers might encounter. //! They enhance the CosmWasm environment, enabling more advanced and nuanced testing. diff --git a/src/checksums.rs b/src/checksums.rs index f4d3f428..e8a9bc2d 100644 --- a/src/checksums.rs +++ b/src/checksums.rs @@ -7,7 +7,6 @@ use sha2::{Digest, Sha256}; /// This is crucial for ensuring code integrity and is particularly useful /// in environments where code verification is a key part of the contract /// deployment process. -/// /// This trait defines a method to calculate checksum based on /// the creator's address and a unique code identifier. pub trait ChecksumGenerator { diff --git a/src/custom_handler.rs b/src/custom_handler.rs index 0ce6c577..45aad7c2 100644 --- a/src/custom_handler.rs +++ b/src/custom_handler.rs @@ -39,7 +39,6 @@ impl CachingCustomHandlerState { /// /// Manages the internal state of a custom handler, recording execution and query messages. /// Useful for tracking contract interactions during tests. -/// #[derive(Clone, Derivative)] #[derivative(Default(bound = "", new = "true"))] pub struct CachingCustomHandler { From 5af51e9e38f3926790d3cdb9e1948b6a8e353e14 Mon Sep 17 00:00:00 2001 From: Costa Giannakakis <77694967+costa2400@users.noreply.github.com> Date: Thu, 30 Nov 2023 20:15:25 -0500 Subject: [PATCH 009/250] spacing --- src/addons/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/addons/mod.rs b/src/addons/mod.rs index b59559db..5cbc3dfe 100644 --- a/src/addons/mod.rs +++ b/src/addons/mod.rs @@ -1,5 +1,5 @@ -//! MultiTest addons provide additional tools for testing smart contracts, +//! MultiTest addons provide additional tools for testing smart contracts, //! simulating complex blockchain scenarios that developers might encounter. //! They enhance the CosmWasm environment, enabling more advanced and nuanced testing. From a344015929047a1a197ada9f9dc76fb4e732e77a Mon Sep 17 00:00:00 2001 From: Timofey <5527315+epanchee@users.noreply.github.com> Date: Fri, 1 Dec 2023 14:24:26 +0400 Subject: [PATCH 010/250] update test to comply with new AddressGenerator trait --- tests/test_wasm/test_with_addr_gen.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/tests/test_wasm/test_with_addr_gen.rs b/tests/test_wasm/test_with_addr_gen.rs index 992deeb0..f536b695 100644 --- a/tests/test_wasm/test_with_addr_gen.rs +++ b/tests/test_wasm/test_with_addr_gen.rs @@ -1,8 +1,11 @@ -use crate::test_contracts; -use cosmwasm_std::{Addr, Empty, Storage}; +use cosmwasm_std::{Addr, Api, Empty, Storage}; + use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; +use cw_multi_test::error::AnyResult; use cw_multi_test::{no_init, AddressGenerator, AppBuilder, Executor, WasmKeeper}; +use crate::test_contracts; + #[test] fn contract_address_should_work() { // prepare wasm module with custom address generator @@ -50,8 +53,21 @@ fn custom_address_generator_should_work() { struct CustomAddressGenerator; impl AddressGenerator for CustomAddressGenerator { + // deprecated from version 0.18.0 fn next_address(&self, _storage: &mut dyn Storage) -> Addr { - Addr::unchecked("test_address") + // Panic in case of calling this function + unreachable!("this function should not be called") + } + + // use this function instead of next_address + fn contract_address( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _code_id: u64, + _instance_id: u64, + ) -> AnyResult { + Ok(Addr::unchecked("test_address")) } } From fa7c0531b64856c0f9f585a09b2d78e1f9372b78 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 28 Nov 2023 13:59:09 +0100 Subject: [PATCH 011/250] Initial version. --- src/app.rs | 64 ++++++++++++++++-------- src/app_builder.rs | 111 ++++++++++++++++++++++++++++++++++++------ src/lib.rs | 1 + src/staking.rs | 3 ++ src/stargate.rs | 60 +++++++++++++++++++++++ src/tests/test_app.rs | 4 +- src/wasm.rs | 3 ++ 7 files changed, 208 insertions(+), 38 deletions(-) create mode 100644 src/stargate.rs diff --git a/src/app.rs b/src/app.rs index 5c913275..91e886b4 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::{Stargate, StargateFailing}; use crate::transactions::transactional; use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; use crate::{AppBuilder, GovFailingModule, IbcFailingModule}; @@ -36,6 +37,7 @@ pub type BasicApp = App< DistributionKeeper, IbcFailingModule, GovFailingModule, + StargateFailing, >; /// Router is a persisted state. You can query this. @@ -52,16 +54,17 @@ pub struct App< Distr = DistributionKeeper, Ibc = IbcFailingModule, Gov = GovFailingModule, + Stargate = StargateFailing, > { - pub(crate) router: Router, + pub(crate) router: Router, pub(crate) api: Api, pub(crate) storage: Storage, pub(crate) block: BlockInfo, } /// No-op application initialization function. -pub fn no_init( - router: &mut Router, +pub fn no_init( + router: &mut Router, api: &dyn Api, storage: &mut dyn Storage, ) { @@ -87,6 +90,7 @@ impl BasicApp { DistributionKeeper, IbcFailingModule, GovFailingModule, + StargateFailing, >, &dyn Api, &mut dyn Storage, @@ -111,6 +115,7 @@ where DistributionKeeper, IbcFailingModule, GovFailingModule, + StargateFailing, >, &dyn Api, &mut dyn Storage, @@ -119,8 +124,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, @@ -133,6 +138,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { self.router @@ -141,8 +147,9 @@ where } } -impl Executor - for App +impl + Executor + for App where CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -155,6 +162,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])?; @@ -163,8 +171,8 @@ where } } -impl - App +impl + App where WasmT: Wasm, BankT: Bank, @@ -175,9 +183,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 } @@ -199,7 +210,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, @@ -210,7 +221,7 @@ where pub fn read_module(&self, query_fn: F) -> T where F: FnOnce( - &Router, + &Router, &dyn Api, &dyn Storage, ) -> T, @@ -221,8 +232,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, @@ -233,6 +244,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, { @@ -320,8 +332,8 @@ where } } -impl - App +impl + App where CustomT::ExecT: Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -334,6 +346,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { pub fn set_block(&mut self, block: BlockInfo) { self.router @@ -434,7 +447,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, @@ -445,10 +458,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, @@ -459,6 +473,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { pub fn querier<'a>( &'a self, @@ -532,8 +547,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, @@ -544,6 +559,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { type ExecC = CustomT::ExecT; type QueryC = CustomT::QueryT; @@ -566,6 +582,9 @@ 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, type_url, value), _ => bail!("Cannot execute {:?}", msg), } } @@ -587,6 +606,9 @@ 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, path, data), _ => unimplemented!(), } } diff --git a/src/app_builder.rs b/src/app_builder.rs index 8e9e738c..4b2f4b33 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -1,5 +1,6 @@ //! Implementation of the builder for [App]. +use crate::stargate::{Stargate, StargateFailing}; use crate::{ App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingModule, Gov, GovFailingModule, Ibc, IbcFailingModule, Module, Router, StakeKeeper, Staking, Wasm, WasmKeeper, @@ -35,11 +36,12 @@ pub type BasicAppBuilder = AppBuilder< DistributionKeeper, IbcFailingModule, GovFailingModule, + StargateFailing, >; /// 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 { fn default() -> Self { @@ -81,6 +85,7 @@ impl DistributionKeeper, IbcFailingModule, GovFailingModule, + StargateFailing, > { /// Creates builder with default components working with empty exec and query messages. @@ -96,6 +101,7 @@ impl distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), + stargate: StargateFailing, } } } @@ -111,6 +117,7 @@ impl DistributionKeeper, IbcFailingModule, GovFailingModule, + StargateFailing, > where ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, @@ -130,12 +137,13 @@ where distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), + stargate: StargateFailing, } } } -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 e30c2185..ab37cceb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ mod ibc; mod module; mod prefixed_storage; mod staking; +mod stargate; mod test_helpers; mod tests; mod transactions; diff --git a/src/staking.rs b/src/staking.rs index 5155c672..f92d056d 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1015,6 +1015,7 @@ impl Module for DistributionKeeper { #[cfg(test)] mod test { use super::*; + use crate::stargate::StargateFailing; use crate::{ app::MockRouter, BankKeeper, FailingModule, GovFailingModule, IbcFailingModule, Router, WasmKeeper, @@ -1034,6 +1035,7 @@ mod test { DistributionKeeper, IbcFailingModule, GovFailingModule, + StargateFailing, >; fn mock_router() -> BasicRouter { @@ -1045,6 +1047,7 @@ mod test { distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), + stargate: StargateFailing, } } diff --git a/src/stargate.rs b/src/stargate.rs new file mode 100644 index 00000000..dc8ee592 --- /dev/null +++ b/src/stargate.rs @@ -0,0 +1,60 @@ +//! add-docs + +use crate::error::AnyResult; +use crate::{AppResponse, CosmosRouter}; +use anyhow::bail; +use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomQuery, Querier, Storage}; +use schemars::JsonSchema; +use serde::de::DeserializeOwned; +use std::fmt::Debug; + +/// Stargate interface. +pub trait Stargate { + /// Processes stargate messages. + fn execute( + &self, + api: &dyn Api, + storage: &mut dyn Storage, + router: &dyn CosmosRouter, + block: &BlockInfo, + sender: Addr, + type_url: String, + value: Binary, + ) -> AnyResult + where + ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + let _ = (api, storage, router, block); + bail!( + "Unexpected stargate message: (type_ur = {}, value = {:?}) from {:?}", + type_url, + value, + sender + ) + } + + /// Processes stargate queries. + fn query( + &self, + api: &dyn Api, + storage: &dyn Storage, + querier: &dyn Querier, + block: &BlockInfo, + path: String, + data: Binary, + ) -> AnyResult { + let _ = (api, storage, querier, block); + bail!( + "Unexpected stargate query: path = {:?}, data = {:?}", + path, + data + ) + } +} + +/// Always failing stargate mock implementation. +#[derive(Default)] +pub struct StargateFailing; + +impl Stargate for StargateFailing {} diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 8e19e3da..f6d41f18 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -39,8 +39,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 4e7fe130..c2debac2 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::StargateFailing; use crate::test_helpers::{caller, error, payout}; use crate::transactions::StorageTransaction; use crate::{GovFailingModule, IbcFailingModule}; @@ -1135,6 +1136,7 @@ mod test { DistributionKeeper, IbcFailingModule, GovFailingModule, + StargateFailing, >; fn wasm_keeper() -> WasmKeeper { @@ -1150,6 +1152,7 @@ mod test { distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), + stargate: StargateFailing, } } From a7223d13a546b125e6df6c0bb4ffe5617161be21 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 28 Nov 2023 15:45:28 +0100 Subject: [PATCH 012/250] Added tests. --- src/lib.rs | 1 + src/stargate.rs | 79 ++++++++++++++++- tests/test_app_builder/mod.rs | 1 + tests/test_app_builder/test_with_stargate.rs | 93 ++++++++++++++++++++ 4 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 tests/test_app_builder/test_with_stargate.rs diff --git a/src/lib.rs b/src/lib.rs index ab37cceb..7f44d300 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,4 +43,5 @@ pub use crate::module::{AcceptingModule, FailingModule, Module}; pub use crate::staking::{ Distribution, DistributionKeeper, StakeKeeper, Staking, StakingInfo, StakingSudo, }; +pub use crate::stargate::{Stargate, StargateAccepting, StargateFailing}; pub use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; diff --git a/src/stargate.rs b/src/stargate.rs index dc8ee592..610ed25e 100644 --- a/src/stargate.rs +++ b/src/stargate.rs @@ -54,7 +54,82 @@ pub trait Stargate { } /// Always failing stargate mock implementation. -#[derive(Default)] pub struct StargateFailing; -impl Stargate for StargateFailing {} +impl Stargate for StargateFailing { + /// Rejects all stargate messages. + fn execute( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + sender: Addr, + type_url: String, + value: Binary, + ) -> AnyResult + where + ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + bail!( + "Unexpected stargate message: (type_ur = {}, value = {:?}) from {:?}", + type_url, + value, + sender + ) + } + + /// Rejects stargate queries. + fn query( + &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 accepting stargate mock implementation. +pub struct StargateAccepting; + +impl Stargate for StargateAccepting { + /// Accepts all stargate messages. + fn execute( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + _sender: Addr, + _type_url: String, + _value: Binary, + ) -> AnyResult + where + ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + Ok(AppResponse::default()) + } + + /// Accepts all stargate queries. + fn query( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + _path: String, + _data: Binary, + ) -> AnyResult { + Ok(Binary::default()) + } +} diff --git a/tests/test_app_builder/mod.rs b/tests/test_app_builder/mod.rs index 2a2412ee..476df228 100644 --- a/tests/test_app_builder/mod.rs +++ b/tests/test_app_builder/mod.rs @@ -13,6 +13,7 @@ mod test_with_distribution; mod test_with_gov; mod test_with_ibc; 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..18276366 --- /dev/null +++ b/tests/test_app_builder/test_with_stargate.rs @@ -0,0 +1,93 @@ +use anyhow::bail; +use cosmwasm_std::{ + to_json_vec, Addr, Api, Binary, BlockInfo, CosmosMsg, CustomQuery, Empty, Querier, + QueryRequest, Storage, +}; +use cw_multi_test::error::AnyResult; +use cw_multi_test::{AppBuilder, AppResponse, CosmosRouter, Executor, Stargate}; +use schemars::JsonSchema; +use serde::de::DeserializeOwned; +use std::fmt::Debug; + +const EXECUTE_MSG: &str = "stargate execute called"; +const QUERY_MSG: &str = "stargate query called"; + +struct MyStargateKeeper; + +impl Stargate for MyStargateKeeper { + /// Custom processing of stargate messages. + fn execute( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + _sender: Addr, + type_url: String, + value: Binary, + ) -> AnyResult + where + ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + assert_eq!("test", type_url); + assert_eq!(Binary::default(), value); + bail!(EXECUTE_MSG); + } + + /// Custom stargate queries. + fn query( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + path: String, + data: Binary, + ) -> AnyResult { + assert_eq!("test", path); + assert_eq!(Binary::default(), data); + bail!(QUERY_MSG); + } +} + +#[test] +fn building_app_with_custom_stargate_should_work() { + // build custom stargate keeper + let stargate_keeper = MyStargateKeeper; + + // 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 stargate keeper + assert_eq!( + app.execute( + Addr::unchecked("sender"), + CosmosMsg::Stargate { + type_url: "test".to_string(), + value: Default::default() + }, + ) + .unwrap_err() + .to_string(), + EXECUTE_MSG, + ); + + // executing stargate query should return + // an error defined in custom stargate keeper + let query: QueryRequest = QueryRequest::Stargate { + path: "test".to_string(), + data: Default::default(), + }; + assert_eq!( + app.wrap() + .raw_query(to_json_vec(&query).unwrap().as_slice()) + .unwrap() + .unwrap_err(), + QUERY_MSG + ); +} From a5fdbe7c2440d0eb87111bf31f86029a0aee819f Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 28 Nov 2023 16:25:21 +0100 Subject: [PATCH 013/250] Added tests. --- src/stargate.rs | 20 +------- tests/test_app_builder/test_with_stargate.rs | 54 +++++++++++++++++++- 2 files changed, 55 insertions(+), 19 deletions(-) diff --git a/src/stargate.rs b/src/stargate.rs index 610ed25e..657ab63c 100644 --- a/src/stargate.rs +++ b/src/stargate.rs @@ -23,16 +23,7 @@ pub trait Stargate { ) -> AnyResult where ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, - QueryC: CustomQuery + DeserializeOwned + 'static, - { - let _ = (api, storage, router, block); - bail!( - "Unexpected stargate message: (type_ur = {}, value = {:?}) from {:?}", - type_url, - value, - sender - ) - } + QueryC: CustomQuery + DeserializeOwned + 'static; /// Processes stargate queries. fn query( @@ -43,14 +34,7 @@ pub trait Stargate { block: &BlockInfo, path: String, data: Binary, - ) -> AnyResult { - let _ = (api, storage, querier, block); - bail!( - "Unexpected stargate query: path = {:?}, data = {:?}", - path, - data - ) - } + ) -> AnyResult; } /// Always failing stargate mock implementation. diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index 18276366..fb668557 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -4,7 +4,9 @@ use cosmwasm_std::{ QueryRequest, Storage, }; use cw_multi_test::error::AnyResult; -use cw_multi_test::{AppBuilder, AppResponse, CosmosRouter, Executor, Stargate}; +use cw_multi_test::{ + AppBuilder, AppResponse, CosmosRouter, Executor, Stargate, StargateAccepting, StargateFailing, +}; use schemars::JsonSchema; use serde::de::DeserializeOwned; use std::fmt::Debug; @@ -91,3 +93,53 @@ fn building_app_with_custom_stargate_should_work() { QUERY_MSG ); } + +#[test] +fn building_app_with_accepting_stargate_should_work() { + let app_builder = AppBuilder::default(); + let mut app = app_builder + .with_stargate(StargateAccepting) + .build(|_, _, _| {}); + + app.execute( + Addr::unchecked("sender"), + CosmosMsg::Stargate { + type_url: "test".to_string(), + value: Default::default(), + }, + ) + .unwrap(); + + let _ = app + .wrap() + .query::(&QueryRequest::Stargate { + path: "test".to_string(), + data: Default::default(), + }) + .is_ok(); +} + +#[test] +fn building_app_with_failing_stargate_should_work() { + let app_builder = AppBuilder::default(); + let mut app = app_builder + .with_stargate(StargateFailing) + .build(|_, _, _| {}); + + app.execute( + Addr::unchecked("sender"), + CosmosMsg::Stargate { + type_url: "test".to_string(), + value: Default::default(), + }, + ) + .unwrap_err(); + + let _ = app + .wrap() + .query::(&QueryRequest::Stargate { + path: "test".to_string(), + data: Default::default(), + }) + .unwrap_err(); +} From b866413a4113464f9a1f5229b102f946517d6bde Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 29 Nov 2023 10:36:39 +0100 Subject: [PATCH 014/250] Added tests. --- src/stargate.rs | 48 ++++++++----------------------- src/test_helpers/stargate.rs | 24 ++++++++++++++++ src/tests/mod.rs | 1 + src/tests/test_stargate.rs | 56 ++++++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 36 deletions(-) create mode 100644 src/test_helpers/stargate.rs create mode 100644 src/tests/test_stargate.rs diff --git a/src/stargate.rs b/src/stargate.rs index 657ab63c..23b26f31 100644 --- a/src/stargate.rs +++ b/src/stargate.rs @@ -21,41 +21,11 @@ pub trait Stargate { type_url: String, value: Binary, ) -> AnyResult - where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, - QueryC: CustomQuery + DeserializeOwned + 'static; - - /// Processes stargate queries. - fn query( - &self, - api: &dyn Api, - storage: &dyn Storage, - querier: &dyn Querier, - block: &BlockInfo, - path: String, - data: Binary, - ) -> AnyResult; -} - -/// Always failing stargate mock implementation. -pub struct StargateFailing; - -impl Stargate for StargateFailing { - /// Rejects all stargate messages. - fn execute( - &self, - _api: &dyn Api, - _storage: &mut dyn Storage, - _router: &dyn CosmosRouter, - _block: &BlockInfo, - sender: Addr, - type_url: String, - value: Binary, - ) -> AnyResult where ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { + let _ = (api, storage, router, block); bail!( "Unexpected stargate message: (type_ur = {}, value = {:?}) from {:?}", type_url, @@ -64,16 +34,17 @@ impl Stargate for StargateFailing { ) } - /// Rejects stargate queries. + /// Processes stargate queries. fn query( &self, - _api: &dyn Api, - _storage: &dyn Storage, - _querier: &dyn Querier, - _block: &BlockInfo, + api: &dyn Api, + storage: &dyn Storage, + querier: &dyn Querier, + block: &BlockInfo, path: String, data: Binary, ) -> AnyResult { + let _ = (api, storage, querier, block); bail!( "Unexpected stargate query: path = {:?}, data = {:?}", path, @@ -82,6 +53,11 @@ impl Stargate for StargateFailing { } } +/// Always failing stargate mock implementation. +pub struct StargateFailing; + +impl Stargate for StargateFailing {} + /// Always accepting stargate mock implementation. pub struct StargateAccepting; diff --git a/src/test_helpers/stargate.rs b/src/test_helpers/stargate.rs new file mode 100644 index 00000000..ca090e75 --- /dev/null +++ b/src/test_helpers/stargate.rs @@ -0,0 +1,24 @@ +use crate::{Contract, ContractWrapper}; +use cosmwasm_std::{ + Binary, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdResult, +}; + +fn instantiate(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { + Ok(Response::new()) +} + +fn execute(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { + Ok(Response::new().add_message(CosmosMsg::Stargate { + type_url: "/this.is.a.stargate.test.helper".to_string(), + value: Default::default(), + })) +} + +fn query(_deps: Deps, _env: Env, _msg: Empty) -> StdResult { + Ok(Binary::default()) +} + +pub fn contract() -> Box> { + let contract = ContractWrapper::new(execute, instantiate, query); + Box::new(contract) +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 2a190c34..53370229 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -4,3 +4,4 @@ mod test_app; mod test_custom_handler; mod test_gov; mod test_ibc; +mod test_stargate; diff --git a/src/tests/test_stargate.rs b/src/tests/test_stargate.rs new file mode 100644 index 00000000..47464e04 --- /dev/null +++ b/src/tests/test_stargate.rs @@ -0,0 +1,56 @@ +use crate::test_helpers::stargate; +use crate::{no_init, App, AppBuilder, Executor, StargateAccepting}; +use cosmwasm_std::Empty; + +#[test] +fn default_stargate() { + let mut app = App::default(); + + // store the contract + let creator_addr = app.api().addr_make("creator"); + let code = app.store_code_with_creator(creator_addr, stargate::contract()); + + // instantiate contract + let owner_addr = app.api().addr_make("owner"); + let contract_addr = app + .instantiate_contract(code, owner_addr, &Empty {}, &[], "tauri", None) + .unwrap(); + + // execute empty message on the contract, this contract returns stargate message + // which is rejected by default failing stargate keeper + let sender_addr = app.api().addr_make("sender"); + let err = app + .execute_contract(sender_addr, contract_addr, &Empty {}, &[]) + .unwrap_err(); + + // source error message comes from failing stargate keeper + assert!(err + .source() + .unwrap() + .to_string() + .starts_with("Unexpected stargate message")); +} + +#[test] +fn accepting_stargate() { + let mut app = AppBuilder::default() + .with_stargate(StargateAccepting) + .build(no_init); + + // store the contract + let creator_addr = app.api().addr_make("creator"); + let code = app.store_code_with_creator(creator_addr, stargate::contract()); + + // instantiate contract + let owner_addr = app.api().addr_make("owner"); + let contract_addr = app + .instantiate_contract(code, owner_addr, &Empty {}, &[], "tauri", None) + .unwrap(); + + // execute empty message on the contract, this contract returns stargate message + // which is just silently processed by accepting stargate keeper + let sender_addr = app.api().addr_make("sender"); + assert!(app + .execute_contract(sender_addr, contract_addr, &Empty {}, &[]) + .is_ok()); +} From 76ef259b3b7ffd67c50b02d1c196484f3ba70ec2 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 29 Nov 2023 12:11:19 +0100 Subject: [PATCH 015/250] Refactoring. --- src/test_helpers/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test_helpers/mod.rs b/src/test_helpers/mod.rs index dc87c895..16d23082 100644 --- a/src/test_helpers/mod.rs +++ b/src/test_helpers/mod.rs @@ -12,6 +12,7 @@ pub mod hackatom; pub mod ibc; pub mod payout; pub mod reflect; +pub mod stargate; /// Custom message for testing purposes. #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] From 2d4dd795c129df069e41edec2e888e763f8e2bfe Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 29 Nov 2023 12:16:13 +0100 Subject: [PATCH 016/250] Refactored tests. --- src/tests/test_stargate.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/tests/test_stargate.rs b/src/tests/test_stargate.rs index 47464e04..92fcb69c 100644 --- a/src/tests/test_stargate.rs +++ b/src/tests/test_stargate.rs @@ -13,14 +13,13 @@ fn default_stargate() { // instantiate contract let owner_addr = app.api().addr_make("owner"); let contract_addr = app - .instantiate_contract(code, owner_addr, &Empty {}, &[], "tauri", None) + .instantiate_contract(code, owner_addr.clone(), &Empty {}, &[], "tauri", None) .unwrap(); // execute empty message on the contract, this contract returns stargate message // which is rejected by default failing stargate keeper - let sender_addr = app.api().addr_make("sender"); let err = app - .execute_contract(sender_addr, contract_addr, &Empty {}, &[]) + .execute_contract(owner_addr, contract_addr, &Empty {}, &[]) .unwrap_err(); // source error message comes from failing stargate keeper @@ -44,13 +43,12 @@ fn accepting_stargate() { // instantiate contract let owner_addr = app.api().addr_make("owner"); let contract_addr = app - .instantiate_contract(code, owner_addr, &Empty {}, &[], "tauri", None) + .instantiate_contract(code, owner_addr.clone(), &Empty {}, &[], "tauri", None) .unwrap(); // execute empty message on the contract, this contract returns stargate message // which is just silently processed by accepting stargate keeper - let sender_addr = app.api().addr_make("sender"); assert!(app - .execute_contract(sender_addr, contract_addr, &Empty {}, &[]) + .execute_contract(owner_addr, contract_addr, &Empty {}, &[]) .is_ok()); } From 01859745a789ae0a04e837a945419b39758ca295 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 29 Nov 2023 12:40:00 +0100 Subject: [PATCH 017/250] Updated documentation. --- src/stargate.rs | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/stargate.rs b/src/stargate.rs index 23b26f31..39d23aac 100644 --- a/src/stargate.rs +++ b/src/stargate.rs @@ -1,5 +1,3 @@ -//! add-docs - use crate::error::AnyResult; use crate::{AppResponse, CosmosRouter}; use anyhow::bail; @@ -9,8 +7,15 @@ use serde::de::DeserializeOwned; use std::fmt::Debug; /// Stargate interface. +/// +/// This trait provides the default behaviour for all functions +/// that is equal to [StargateFailing] implementation. pub trait Stargate { /// Processes stargate messages. + /// + /// The `CosmosMsg::Stargate` message is unwrapped before processing. + /// The `type_url` and `value` attributes of `CosmosMsg::Stargate` + /// are passed directly to this handler. fn execute( &self, api: &dyn Api, @@ -35,6 +40,10 @@ pub trait Stargate { } /// Processes stargate queries. + /// + /// The `QueryRequest::Stargate` query request is unwrapped before processing. + /// The `path` and `data` attributes of `QueryRequest::Stargate` are passed + /// directly to this handler. fn query( &self, api: &dyn Api, @@ -62,34 +71,36 @@ impl Stargate for StargateFailing {} pub struct StargateAccepting; impl Stargate for StargateAccepting { - /// Accepts all stargate messages. + /// Accepts all stargate messages. Returns default `AppResponse`. fn execute( &self, - _api: &dyn Api, - _storage: &mut dyn Storage, - _router: &dyn CosmosRouter, - _block: &BlockInfo, - _sender: Addr, - _type_url: String, - _value: Binary, + api: &dyn Api, + storage: &mut dyn Storage, + router: &dyn CosmosRouter, + block: &BlockInfo, + sender: Addr, + type_url: String, + value: Binary, ) -> AnyResult where ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { + let _ = (api, storage, router, block, sender, type_url, value); Ok(AppResponse::default()) } - /// Accepts all stargate queries. + /// Accepts all stargate queries. Returns default `Binary`. fn query( &self, - _api: &dyn Api, - _storage: &dyn Storage, - _querier: &dyn Querier, - _block: &BlockInfo, - _path: String, - _data: Binary, + api: &dyn Api, + storage: &dyn Storage, + querier: &dyn Querier, + block: &BlockInfo, + path: String, + data: Binary, ) -> AnyResult { + let _ = (api, storage, querier, block, path, data); Ok(Binary::default()) } } From 93ebb12722e828924d674b73b951f1a770124d01 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 29 Nov 2023 12:46:32 +0100 Subject: [PATCH 018/250] Refactoring --- src/app_builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app_builder.rs b/src/app_builder.rs index 4b2f4b33..dd4c83e4 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -1,9 +1,9 @@ //! Implementation of the builder for [App]. -use crate::stargate::{Stargate, StargateFailing}; use crate::{ App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingModule, Gov, GovFailingModule, - Ibc, IbcFailingModule, Module, Router, StakeKeeper, Staking, Wasm, WasmKeeper, + Ibc, IbcFailingModule, Module, Router, StakeKeeper, Staking, Stargate, StargateFailing, Wasm, + WasmKeeper, }; use cosmwasm_std::testing::{mock_env, MockApi, MockStorage}; use cosmwasm_std::{Api, BlockInfo, CustomQuery, Empty, Storage}; From 7754d8993fac78d464bd64f7f0ad58172b595526 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 29 Nov 2023 13:34:06 +0100 Subject: [PATCH 019/250] Refactoring. --- tests/test_app_builder/test_with_stargate.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index fb668557..624e701f 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -5,7 +5,8 @@ use cosmwasm_std::{ }; use cw_multi_test::error::AnyResult; use cw_multi_test::{ - AppBuilder, AppResponse, CosmosRouter, Executor, Stargate, StargateAccepting, StargateFailing, + no_init, AppBuilder, AppResponse, CosmosRouter, Executor, Stargate, StargateAccepting, + StargateFailing, }; use schemars::JsonSchema; use serde::de::DeserializeOwned; @@ -60,9 +61,7 @@ fn building_app_with_custom_stargate_should_work() { // build the application with custom stargate keeper let app_builder = AppBuilder::default(); - let mut app = app_builder - .with_stargate(stargate_keeper) - .build(|_, _, _| {}); + let mut app = app_builder.with_stargate(stargate_keeper).build(no_init); // executing stargate message should return // an error defined in custom stargate keeper @@ -97,9 +96,7 @@ fn building_app_with_custom_stargate_should_work() { #[test] fn building_app_with_accepting_stargate_should_work() { let app_builder = AppBuilder::default(); - let mut app = app_builder - .with_stargate(StargateAccepting) - .build(|_, _, _| {}); + let mut app = app_builder.with_stargate(StargateAccepting).build(no_init); app.execute( Addr::unchecked("sender"), @@ -122,9 +119,7 @@ fn building_app_with_accepting_stargate_should_work() { #[test] fn building_app_with_failing_stargate_should_work() { let app_builder = AppBuilder::default(); - let mut app = app_builder - .with_stargate(StargateFailing) - .build(|_, _, _| {}); + let mut app = app_builder.with_stargate(StargateFailing).build(no_init); app.execute( Addr::unchecked("sender"), From 18b2932a7192f2f2c2a1b318fd312770a0305daa Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 5 Dec 2023 16:13:01 +0100 Subject: [PATCH 020/250] Bumped version. --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e9ffa424..f6031bd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -248,7 +248,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "0.19.0" +version = "0.20.0" dependencies = [ "anyhow", "bech32", diff --git a/Cargo.toml b/Cargo.toml index 871cd61c..018812c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "0.19.0" +version = "0.20.0" authors = ["Ethan Frey "] edition = "2021" description = "Testing tools for multi-contract interactions" From 763fe1177b7cec62e0e192976e473fb28a988b2b Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 5 Dec 2023 16:28:05 +0100 Subject: [PATCH 021/250] Updated CHANGELOG. --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d84531fb..75fc5d19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## [v0.20.0](https://github.com/CosmWasm/cw-multi-test/tree/v0.20.0) (2023-12-06) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.19.0...v0.20.0) + +**Closed issues:** + +- Unit testing IBC with mock module fails: Cannot execute Stargate [\#37](https://github.com/CosmWasm/cw-multi-test/issues/37) +- Allow mocking Stargate messages [\#40](https://github.com/CosmWasm/cw-multi-test/issues/40) +- MultiTest does not support CosmosMsg::Stargate [\#88](https://github.com/CosmWasm/cw-multi-test/issues/88) + +**Merged pull requests:** + +- Stargate mock support [\#106](https://github.com/CosmWasm/cw-multi-test/pull/106) ([DariuszDepta](https://github.com/DariuszDepta)) +- Made `no_init` function public [\#107](https://github.com/CosmWasm/cw-multi-test/pull/107) ([DariuszDepta](https://github.com/DariuszDepta)) +- Separated test helper contracts for Gov and IBC [\#108](https://github.com/CosmWasm/cw-multi-test/pull/108) ([DariuszDepta](https://github.com/DariuszDepta)) +- Add test to check custom `AddressGenerator` implementation [\#110](https://github.com/CosmWasm/cw-multi-test/pull/110) ([epanchee](https://github.com/epanchee)) + ## [v0.19.0](https://github.com/CosmWasm/cw-multi-test/tree/v0.19.0) (2023-11-28) [Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.18.1...v0.19.0) From fc41f6dac159c3f446255b09fa65c86cff3e0c3b Mon Sep 17 00:00:00 2001 From: Costa Giannakakis <77694967+costa2400@users.noreply.github.com> Date: Tue, 12 Dec 2023 16:22:14 -0500 Subject: [PATCH 022/250] format upgrades --- src/addons/mod.rs | 6 ++---- src/app.rs | 21 +++++++++---------- src/app_builder.rs | 3 +-- src/bank.rs | 9 ++++---- src/checksums.rs | 4 ++-- src/contracts.rs | 4 ++-- src/custom_handler.rs | 9 ++++---- src/error.rs | 6 +++--- src/executor.rs | 6 +++--- src/gov.rs | 6 +++--- src/ibc.rs | 8 +++---- src/module.rs | 10 ++++----- src/staking.rs | 2 +- src/tests/test_custom_handler.rs | 4 ++-- src/wasm.rs | 2 +- .../test_with_distribution.rs | 2 +- 16 files changed, 48 insertions(+), 54 deletions(-) diff --git a/src/addons/mod.rs b/src/addons/mod.rs index 5cbc3dfe..be056c11 100644 --- a/src/addons/mod.rs +++ b/src/addons/mod.rs @@ -1,9 +1,7 @@ - -//! MultiTest addons provide additional tools for testing smart contracts, -//! simulating complex blockchain scenarios that developers might encounter. +//! MultiTest addons provide additional tools for testing smart contracts, +//! simulating complex blockchain scenarios that developers might encounter. //! They enhance the CosmWasm environment, enabling more advanced and nuanced testing. - mod addresses; mod api; diff --git a/src/app.rs b/src/app.rs index ffd7aef3..17ef8fba 100644 --- a/src/app.rs +++ b/src/app.rs @@ -20,14 +20,14 @@ use schemars::JsonSchema; use serde::{de::DeserializeOwned, Serialize}; use std::fmt::Debug; use std::marker::PhantomData; -/// Advances the blockchain environment to the next block in tests, enabling developers to simulate +/// Advances the blockchain environment to the next block in tests, enabling developers to simulate /// time-dependent contract behaviors and block-related triggers efficiently. pub fn next_block(block: &mut BlockInfo) { block.time = block.time.plus_seconds(5); block.height += 1; } -/// A type alias for the default-built App. It simplifies storage and handling in typical scenarios, +/// A type alias for the default-built App. It simplifies storage and handling in typical scenarios, /// streamlining the use of the App structure in standard test setups. pub type BasicApp = App< BankKeeper, @@ -42,12 +42,11 @@ pub type BasicApp = App< StargateFailing, >; - -/// The App struct in cw-multi-test serves as a router with persisted state -/// for querying the blockchain's current status. It primarily uses RouterCache for -/// executing transactions, which allows for preliminary testing of operations before -/// they are permanently applied. The provided .execute() method streamlines this process, -/// handling the execution, review, and finalization (commit or rollback) of these operations, +/// The App struct in cw-multi-test serves as a router with persisted state +/// for querying the blockchain's current status. It primarily uses RouterCache for +/// executing transactions, which allows for preliminary testing of operations before +/// they are permanently applied. The provided .execute() method streamlines this process, +/// handling the execution, review, and finalization (commit or rollback) of these operations, /// simplifying state management and transaction testing in the CosmWasm framework. #[derive(Clone)] @@ -452,7 +451,7 @@ where }) } } -/// The Router plays a critical role in managing and directing +/// The Router plays a critical role in managing and directing /// transactions within the Cosmos blockchain. #[derive(Clone)] pub struct Router { @@ -524,8 +523,8 @@ impl From for SudoMsg { SudoMsg::Staking(staking) } } -///This trait is designed for routing messages within the Cosmos ecosystem. -/// It's key to ensuring that transactions and contract calls are directed to the +///This trait is designed for routing messages within the Cosmos ecosystem. +/// It's key to ensuring that transactions and contract calls are directed to the /// correct destinations during testing, simulating real-world blockchain operations. pub trait CosmosRouter { type ExecC; diff --git a/src/app_builder.rs b/src/app_builder.rs index a2d4f4ec..eb5b7821 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -1,4 +1,3 @@ - //!AppBuilder helps you set up your test blockchain environment step by step [App]. use crate::{ @@ -28,7 +27,7 @@ use std::fmt::Debug; /// .build(no_init); /// ``` /// This type alias is crucial for constructing a custom app with specific modules. -/// It provides a streamlined approach to building and configuring an App tailored to +/// It provides a streamlined approach to building and configuring an App tailored to /// particular testing needs or scenarios. pub type BasicAppBuilder = AppBuilder< BankKeeper, diff --git a/src/bank.rs b/src/bank.rs index bf609bf7..6bd9d264 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -25,15 +25,14 @@ pub enum BankSudo { amount: Vec, }, } -/// This trait defines the interface for simulating banking operations in the test +/// This trait defines the interface for simulating banking operations in the test /// environment. It's essential for testing financial transactions, like transfers /// and balance checks, within your smart contracts. pub trait Bank: Module {} - #[derive(Default)] -/// Manages financial interactions in CosmWasm tests, such as simulating token transactions -/// and account balances. This is particularly important for contracts that deal with financial +/// Manages financial interactions in CosmWasm tests, such as simulating token transactions +/// and account balances. This is particularly important for contracts that deal with financial /// operations in the Cosmos ecosystem. pub struct BankKeeper {} @@ -143,7 +142,7 @@ fn coins_to_string(coins: &[Coin]) -> String { .map(|c| format!("{}{}", c.amount, c.denom)) .join(",") } -///This trait defines the interface for simulating banking operations within the testing environment, +///This trait defines the interface for simulating banking operations within the testing environment, /// essential for creating and testing scenarios involving financial transactions and account management in smart contracts. impl Bank for BankKeeper {} diff --git a/src/checksums.rs b/src/checksums.rs index e8a9bc2d..994ee79e 100644 --- a/src/checksums.rs +++ b/src/checksums.rs @@ -4,8 +4,8 @@ use cosmwasm_std::{Addr, HexBinary}; use sha2::{Digest, Sha256}; /// Provides a custom interface for generating checksums for contract code. -/// This is crucial for ensuring code integrity and is particularly useful -/// in environments where code verification is a key part of the contract +/// This is crucial for ensuring code integrity and is particularly useful +/// in environments where code verification is a key part of the contract /// deployment process. /// This trait defines a method to calculate checksum based on /// the creator's address and a unique code identifier. diff --git a/src/contracts.rs b/src/contracts.rs index 0650da6b..44842939 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -10,7 +10,7 @@ use std::fmt::{Debug, Display}; use std::ops::Deref; /// Serves as the primary interface for interacting with contracts. -/// It includes methods for executing, querying, and managing contract states, +/// It includes methods for executing, querying, and managing contract states, /// making it a fundamental trait for testing contract functionalities. pub trait Contract where @@ -55,7 +55,7 @@ type ReplyClosure = Box, Env, Reply) -> Result = Box, Env, T) -> Result>; /// Standardizes interactions with contracts in CosmWasm tests, especially useful for contracts that -/// do not possess extensive privileges. It simplifies and unifies the way developers interact with +/// do not possess extensive privileges. It simplifies and unifies the way developers interact with /// different contracts. pub struct ContractWrapper< T1, diff --git a/src/custom_handler.rs b/src/custom_handler.rs index 45aad7c2..02552a86 100644 --- a/src/custom_handler.rs +++ b/src/custom_handler.rs @@ -7,10 +7,9 @@ use std::cell::{Ref, RefCell}; use std::ops::Deref; use std::rc::Rc; - /// This struct serves as the internal state of CachingCustomHandler, carefully managing -/// internal mutability to keep it hidden from users. It's essential for maintaining a shared -/// internal state, especially since accessing mock internals becomes impossible once the +/// internal mutability to keep it hidden from users. It's essential for maintaining a shared +/// internal state, especially since accessing mock internals becomes impossible once the /// mock is passed to the app and not exposed by the API. #[derive(Derivative)] #[derivative(Default(bound = "", new = "true"), Clone(bound = ""))] @@ -36,8 +35,8 @@ impl CachingCustomHandlerState { /// Custom handler storing all the messages it received, so they can be later verified. /// State is thin shared state, so it can be hold after mock is passed to App to read state. -/// -/// Manages the internal state of a custom handler, recording execution and query messages. +/// +/// Manages the internal state of a custom handler, recording execution and query messages. /// Useful for tracking contract interactions during tests. #[derive(Clone, Derivative)] #[derivative(Default(bound = "", new = "true"))] diff --git a/src/error.rs b/src/error.rs index 1a8a5b4d..7dc5925e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,11 +1,11 @@ pub use anyhow::{anyhow, bail, Context as AnyContext, Error as AnyError, Result as AnyResult}; use cosmwasm_std::{WasmMsg, WasmQuery}; use thiserror::Error; -///The error module deals with identifying and reporting problems that occur during testing. +///The error module deals with identifying and reporting problems that occur during testing. ///It's like a diagnostic tool that helps you understand what went wrong and where, so you can fix issues -/// more effectively. +/// more effectively. #[derive(Debug, Error, PartialEq, Eq)] -///This module handles error definitions and management within `cw_multi_test``, ensuring that issues +///This module handles error definitions and management within `cw_multi_test``, ensuring that issues ///and exceptions encountered during the testing process are effectively identified and reported. pub enum Error { #[error("Empty attribute key. Value: {value}")] diff --git a/src/executor.rs b/src/executor.rs index 24c0ca28..ec1672d2 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -7,7 +7,7 @@ use cw_utils::{parse_execute_response_data, parse_instantiate_response_data}; use schemars::JsonSchema; use serde::Serialize; use std::fmt::Debug; -/// AppResponse likely refers to a standardized response format from the App. +/// AppResponse likely refers to a standardized response format from the App. /// It's mentioned in the cw-multi-test-main package, which suggests it's used for returning /// information about the processing of transactions or queries. #[derive(Default, Clone, Debug)] @@ -60,8 +60,8 @@ impl From for AppResponse { } } } -///Defines the interface for executing transactions and contract interactions. -/// It's a central component in the testing framework, managing the operational flow and +///Defines the interface for executing transactions and contract interactions. +/// It's a central component in the testing framework, managing the operational flow and /// ensuring that contract calls are processed correctly. pub trait Executor where diff --git a/src/gov.rs b/src/gov.rs index f2fe7e21..f2c01940 100644 --- a/src/gov.rs +++ b/src/gov.rs @@ -1,16 +1,16 @@ use crate::{AcceptingModule, FailingModule, Module}; use cosmwasm_std::{Empty, GovMsg}; /// Handles governance-related operations within the test environment. -/// This trait is essential for testing contracts that interact with governance mechanisms, +/// This trait is essential for testing contracts that interact with governance mechanisms, /// simulating proposals, voting, and other governance activities. pub trait Gov: Module {} -/// A type alias for a module that accepts governance-related interactions. +/// A type alias for a module that accepts governance-related interactions. /// It's used in scenarios where you need to test how your contract interacts /// with governance processes and messages. pub type GovAcceptingModule = AcceptingModule; impl Gov for GovAcceptingModule {} -/// This type alias represents a module designed to fail in response to governance operations. +/// This type alias represents a module designed to fail in response to governance operations. /// It's useful for testing how contracts behave when governance actions do not proceed as expected. pub type GovFailingModule = FailingModule; diff --git a/src/ibc.rs b/src/ibc.rs index efa27b99..e8442c2b 100644 --- a/src/ibc.rs +++ b/src/ibc.rs @@ -1,16 +1,16 @@ use crate::{AcceptingModule, FailingModule, Module}; use cosmwasm_std::{Empty, IbcMsg, IbcQuery}; -///Manages Inter-Blockchain Communication (IBC) functionalities. +///Manages Inter-Blockchain Communication (IBC) functionalities. ///This trait is critical for testing contracts that involve cross-chain interactions, ///reflecting the interconnected nature of the Cosmos ecosystem. pub trait Ibc: Module {} -/// Ideal for testing contracts that involve IBC, this module is designed to successfully -/// handle cross-chain messages. It's key for ensuring that your contract can smoothly interact +/// Ideal for testing contracts that involve IBC, this module is designed to successfully +/// handle cross-chain messages. It's key for ensuring that your contract can smoothly interact /// with other blockchains in the Cosmos network. pub type IbcAcceptingModule = AcceptingModule; impl Ibc for IbcAcceptingModule {} -/// Use this to test how your contract deals with problematic IBC scenarios. +/// Use this to test how your contract deals with problematic IBC scenarios. /// It's a module that deliberately fails in handling IBC messages, allowing you /// to check how your contract behaves in less-than-ideal cross-chain communication situations. pub type IbcFailingModule = FailingModule; diff --git a/src/module.rs b/src/module.rs index eb9ba0cf..79f7b3f3 100644 --- a/src/module.rs +++ b/src/module.rs @@ -7,7 +7,7 @@ use serde::de::DeserializeOwned; use std::fmt::Debug; use std::marker::PhantomData; -/// Provides a generic interface for modules within the test environment. +/// Provides a generic interface for modules within the test environment. /// It's essential for creating modular and extensible testing setups, allowing developers /// to integrate custom functionalities or test specific scenarios. pub trait Module { @@ -58,11 +58,11 @@ pub trait Module { ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static; } -/// This could be a diagnostic or testing tool within the Cosmos ecosystem, designed to -/// intentionally fail under certain conditions to test the robustness and error-handling +/// This could be a diagnostic or testing tool within the Cosmos ecosystem, designed to +/// intentionally fail under certain conditions to test the robustness and error-handling /// capabilities of the network. pub struct FailingModule(PhantomData<(ExecT, QueryT, SudoT)>); - + impl FailingModule { pub fn new() -> Self { Self(PhantomData) @@ -122,7 +122,7 @@ where bail!("Unexpected sudo msg {:?}", msg) } } -///This struct might represent a module in the Cosmos ecosystem designed to accept certain types of transactions +///This struct might represent a module in the Cosmos ecosystem designed to accept certain types of transactions /// or interactions. The specific functionality would depend on the context of its use. pub struct AcceptingModule(PhantomData<(ExecT, QueryT, SudoT)>); diff --git a/src/staking.rs b/src/staking.rs index 09146808..9e6fd0a0 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -867,7 +867,7 @@ impl Module for StakeKeeper { } } -/// This module likely manages the distribution of rewards and fees within the blockchain network. +/// This module likely manages the distribution of rewards and fees within the blockchain network. /// It could handle tasks like distributing block rewards to validators and delegators, /// and managing community funding mechanisms. #[derive(Default)] diff --git a/src/tests/test_custom_handler.rs b/src/tests/test_custom_handler.rs index cb2fe6e7..2bc821bc 100644 --- a/src/tests/test_custom_handler.rs +++ b/src/tests/test_custom_handler.rs @@ -4,8 +4,8 @@ use crate::{App, Module}; use cosmwasm_std::testing::MockStorage; use cosmwasm_std::{Addr, Empty}; -///Custom handlers in CosmWasm allow developers to incorporate their own unique logic into tests. -///This feature is valuable for tailoring the testing environment to reflect specific +///Custom handlers in CosmWasm allow developers to incorporate their own unique logic into tests. +///This feature is valuable for tailoring the testing environment to reflect specific /// use-cases or behaviors in a CosmWasm-based smart contract. #[test] fn custom_handler_works() { diff --git a/src/wasm.rs b/src/wasm.rs index daee5d96..72c497bd 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -71,7 +71,7 @@ struct CodeData { code_base_id: usize, } -/// Acts as the interface for interacting with WebAssembly (Wasm) modules. +/// Acts as the interface for interacting with WebAssembly (Wasm) modules. /// This trait is crucial for testing smart contracts written in languages that compile to WebAssembly, /// which is common in the Cosmos and CosmWasm ecosystems. pub trait Wasm { diff --git a/tests/test_app_builder/test_with_distribution.rs b/tests/test_app_builder/test_with_distribution.rs index e9924b41..9a27f582 100644 --- a/tests/test_app_builder/test_with_distribution.rs +++ b/tests/test_app_builder/test_with_distribution.rs @@ -8,7 +8,7 @@ impl Distribution for MyDistributionKeeper {} const EXECUTE_MSG: &str = "distribution execute called"; /// Manages the distribution aspects within tests, simulating scenarios ] -/// like reward distribution or token allocation. This trait is important +/// like reward distribution or token allocation. This trait is important /// for contracts that involve distributing assets in a certain way. #[test] fn building_app_with_custom_distribution_should_work() { From cb7aa74808acd839f83b430ca9c608d9618cf16a Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 15 Dec 2023 17:24:10 +0100 Subject: [PATCH 023/250] Documentation updates. --- Cargo.lock | 60 +++++++--- Cargo.toml | 3 +- src/addons/addresses/mock.rs | 2 +- src/addons/api/bech32.rs | 4 +- src/addons/api/bech32m.rs | 4 +- src/addons/mod.rs | 4 +- src/addresses.rs | 4 + src/app.rs | 44 +++++--- src/bank.rs | 30 +++-- src/contracts.rs | 19 +++- src/custom_handler.rs | 45 ++++---- src/error.rs | 37 +++--- src/executor.rs | 47 +++++--- src/lib.rs | 131 ++++++++++++++++++++-- src/module.rs | 29 +++-- src/staking.rs | 38 +++++-- src/tests/test_custom_handler.rs | 2 +- src/wasm.rs | 82 ++++++++++++++ tests/test_wasm/test_with_addr_gen.rs | 2 +- tests/test_wasm/test_with_checksum_gen.rs | 5 +- 20 files changed, 463 insertions(+), 129 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f6031bd1..3b15d773 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -129,9 +129,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-crypto" @@ -255,6 +255,7 @@ dependencies = [ "cosmwasm-std", "cw-storage-plus", "cw-utils", + "cw1-whitelist", "derivative", "hex", "hex-literal", @@ -293,6 +294,35 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cw1" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1605722190afd93bfea6384b88224d1cfe50ebf70d2e10641535da79fa70e83" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "schemars", + "serde", +] + +[[package]] +name = "cw1-whitelist" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bb3e9dc87f4ff26547f4e27e0ba3c82034372f21b2f55527fb52b542637d8d" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "cw-utils", + "cw1", + "cw2", + "schemars", + "serde", + "thiserror", +] + [[package]] name = "cw2" version = "1.1.2" @@ -515,9 +545,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "k256" @@ -535,9 +565,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.150" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "memchr" @@ -565,9 +595,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" @@ -614,7 +644,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -659,9 +689,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "schemars" @@ -733,7 +763,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -827,9 +857,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" dependencies = [ "proc-macro2", "quote", @@ -853,7 +883,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 018812c0..8e3391f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,4 +33,5 @@ thiserror = "1.0.50" [dev-dependencies] hex = "0.4.3" hex-literal = "0.4.1" -once_cell = "1.18.0" +once_cell = "1.19.0" +cw1-whitelist = "1.1.2" diff --git a/src/addons/addresses/mock.rs b/src/addons/addresses/mock.rs index 081199cc..c9292816 100644 --- a/src/addons/addresses/mock.rs +++ b/src/addons/addresses/mock.rs @@ -4,7 +4,7 @@ use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage}; use sha2::digest::Update; use sha2::{Digest, Sha256}; -/// Address generator that mimics the original `wasmd` behavior. +/// Address generator that mimics the [wasmd](https://github.com/CosmWasm/wasmd) behaviour. /// /// [MockAddressGenerator] implements [AddressGenerator] trait in terms of /// [`contract_address`](AddressGenerator::contract_address) and diff --git a/src/addons/api/bech32.rs b/src/addons/api/bech32.rs index f2fd739f..923b3961 100644 --- a/src/addons/api/bech32.rs +++ b/src/addons/api/bech32.rs @@ -5,10 +5,10 @@ use cosmwasm_std::{ }; use sha2::{Digest, Sha256}; -/// Implementation of the `Api` trait that uses [`Bech32`] format +/// Implementation of the [Api](cosmwasm_std::Api) trait that uses [Bech32] format /// for humanizing canonical addresses. /// -/// [`Bech32`]:https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki +/// [Bech32]: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki pub struct MockApiBech32 { api: MockApi, prefix: &'static str, diff --git a/src/addons/api/bech32m.rs b/src/addons/api/bech32m.rs index d630f2b0..40311cd1 100644 --- a/src/addons/api/bech32m.rs +++ b/src/addons/api/bech32m.rs @@ -2,10 +2,10 @@ use crate::addons::MockApiBech32; use bech32::Variant; use cosmwasm_std::{Addr, Api, CanonicalAddr, RecoverPubkeyError, StdResult, VerificationError}; -/// Implementation of the `Api` trait that uses [`Bech32m`] format +/// Implementation of the [Api](cosmwasm_std::Api) trait that uses [Bech32m] format /// for humanizing canonical addresses. /// -/// [`Bech32m`]:https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki +/// [Bech32m]: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki pub struct MockApiBech32m(MockApiBech32); impl MockApiBech32m { diff --git a/src/addons/mod.rs b/src/addons/mod.rs index be056c11..5dd4401b 100644 --- a/src/addons/mod.rs +++ b/src/addons/mod.rs @@ -1,4 +1,6 @@ -//! MultiTest addons provide additional tools for testing smart contracts, +//! # Additional testing tools (extensions) +//! +//! **CosmWasm MultiTest** addons provide additional tools for testing smart contracts, //! simulating complex blockchain scenarios that developers might encounter. //! They enhance the CosmWasm environment, enabling more advanced and nuanced testing. diff --git a/src/addresses.rs b/src/addresses.rs index 3a0b1669..bf918313 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -16,6 +16,10 @@ pub trait AddressGenerator { since = "0.18.0", note = "use `contract_address` or `predictable_contract_address` instead; will be removed in version 1.0.0" )] + /// Generates a _non-predictable_ contract address based on the number of contract's instances. + /// This is a simplified version of simulating contract addresses that is deprecated in favour of + /// [contract_address](Self::contract_address) and + /// [predictable_contract_address](Self::predictable_contract_address) functions. fn next_address(&self, storage: &mut dyn Storage) -> Addr { //TODO After removing this function in version 1.0, make `CONTRACTS` and `NAMESPACE_WASM` private in `wasm.rs`. let count = CONTRACTS diff --git a/src/app.rs b/src/app.rs index 17ef8fba..fc542c38 100644 --- a/src/app.rs +++ b/src/app.rs @@ -42,13 +42,9 @@ pub type BasicApp = App< StargateFailing, >; -/// The App struct in cw-multi-test serves as a router with persisted state -/// for querying the blockchain's current status. It primarily uses RouterCache for -/// executing transactions, which allows for preliminary testing of operations before -/// they are permanently applied. The provided .execute() method streamlines this process, -/// handling the execution, review, and finalization (commit or rollback) of these operations, -/// simplifying state management and transaction testing in the CosmWasm framework. - +/// # Blockchain application simulator +/// +/// This structure is the main component of the real-life blockchain simulator. #[derive(Clone)] pub struct App< Bank = BankKeeper, @@ -198,7 +194,7 @@ where &self.router } - /// Returns a shared reference to application's api. + /// Returns a shared reference to application's API. pub fn api(&self) -> &ApiT { &self.api } @@ -213,6 +209,7 @@ where &mut self.storage } + /// Initializes modules. pub fn init_modules(&mut self, init_fn: F) -> T where F: FnOnce( @@ -224,6 +221,7 @@ where init_fn(&mut self.router, &self.api, &mut self.storage) } + /// Queries a module. pub fn read_module(&self, query_fn: F) -> T where F: FnOnce( @@ -354,6 +352,7 @@ where GovT: Gov, StargateT: Stargate, { + /// Sets the initial block properties. pub fn set_block(&mut self, block: BlockInfo) { self.router .staking @@ -362,7 +361,7 @@ where self.block = block; } - // this let's use use "next block" steps that add eg. one height and 5 seconds + /// Advances the current block to "next block" steps and adds one height and 5 seconds. pub fn update_block(&mut self, action: F) { self.router .staking @@ -455,16 +454,21 @@ where /// transactions within the Cosmos blockchain. #[derive(Clone)] 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 + /// 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 module instance to be used in this [Router]. pub stargate: Stargate, } @@ -482,6 +486,7 @@ where GovT: Gov, StargateT: Stargate, { + /// Returns a querier populated with the instance if this [Router]. pub fn querier<'a>( &'a self, api: &'a dyn Api, @@ -500,9 +505,13 @@ where /// We use it to allow calling into modules from another module in sudo mode. /// Things like gov proposals belong here. pub enum SudoMsg { + /// Bank privileged actions. Bank(BankSudo), + /// Custom privileged actions. Custom(Empty), + /// Staking privileged actions. Staking(StakingSudo), + /// Wasm privileged actions. Wasm(WasmSudo), } @@ -523,13 +532,18 @@ impl From for SudoMsg { SudoMsg::Staking(staking) } } -///This trait is designed for routing messages within the Cosmos ecosystem. -/// It's key to ensuring that transactions and contract calls are directed to the +/// A trait representing the Cosmos based chain's router. +/// +/// This trait is designed for routing messages within the Cosmos ecosystem. +/// It is key to ensuring that transactions and contract calls are directed to the /// correct destinations during testing, simulating real-world blockchain operations. pub trait CosmosRouter { + /// Type of the executed custom message. type ExecC; + /// Type of the query custom message. type QueryC: CustomQuery; + /// Executes messages. fn execute( &self, api: &dyn Api, @@ -539,6 +553,7 @@ pub trait CosmosRouter { msg: CosmosMsg, ) -> AnyResult; + /// Evaluates queries. fn query( &self, api: &dyn Api, @@ -547,6 +562,7 @@ pub trait CosmosRouter { request: QueryRequest, ) -> AnyResult; + /// Evaluates privileged actions. fn sudo( &self, api: &dyn Api, diff --git a/src/bank.rs b/src/bank.rs index 6bd9d264..d198e435 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -14,34 +14,46 @@ use cw_utils::NativeBalance; use itertools::Itertools; use schemars::JsonSchema; +/// Collection of bank balances. const BALANCES: Map<&Addr, NativeBalance> = Map::new("balances"); +/// Default namespace for bank module. pub const NAMESPACE_BANK: &[u8] = b"bank"; -#[derive(Clone, std::fmt::Debug, PartialEq, Eq, JsonSchema)] +/// A message representing privileged actions in bank module. +#[derive(Clone, Debug, PartialEq, Eq, JsonSchema)] pub enum BankSudo { + /// Minting privileged action. Mint { + /// Destination address the tokens will be minted for. to_address: String, + /// Amount of the minted tokens. amount: Vec, }, } -/// This trait defines the interface for simulating banking operations in the test -/// environment. It's essential for testing financial transactions, like transfers -/// and balance checks, within your smart contracts. + +/// This trait defines the interface for simulating banking operations. +/// +/// In the test environment, it is essential for testing financial transactions, +/// like transfers and balance checks, within your smart contracts. +/// This trait implements all of these functionalities. pub trait Bank: Module {} -#[derive(Default)] +/// A structure representing a default bank keeper. +/// /// Manages financial interactions in CosmWasm tests, such as simulating token transactions /// and account balances. This is particularly important for contracts that deal with financial /// operations in the Cosmos ecosystem. +#[derive(Default)] pub struct BankKeeper {} impl BankKeeper { + /// Creates a new instance of a bank keeper with default settings. pub fn new() -> Self { - BankKeeper {} + Self::default() } - // this is an "admin" function to let us adjust bank accounts in genesis + /// _Admin_ function for adjusting bank accounts in genesis. pub fn init_balance( &self, storage: &mut dyn Storage, @@ -52,7 +64,7 @@ impl BankKeeper { self.set_balance(&mut bank_storage, account, amount) } - // this is an "admin" function to let us adjust bank accounts + /// _Admin_ function for adjusting bank accounts. fn set_balance( &self, bank_storage: &mut dyn Storage, @@ -125,7 +137,7 @@ impl BankKeeper { self.set_balance(bank_storage, &from_address, a.into_vec()) } - /// Filters out all 0 value coins and returns an error if the resulting Vec is empty + /// Filters out all `0` value coins and returns an error if the resulting vector is empty. fn normalize_amount(&self, amount: Vec) -> AnyResult> { let res: Vec<_> = amount.into_iter().filter(|x| !x.amount.is_zero()).collect(); if res.is_empty() { diff --git a/src/contracts.rs b/src/contracts.rs index 44842939..954f49c7 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -1,3 +1,5 @@ +#![allow(clippy::type_complexity)] + use crate::error::{anyhow, bail, AnyError, AnyResult}; use cosmwasm_std::{ from_json, Binary, CosmosMsg, CustomQuery, Deps, DepsMut, Empty, Env, MessageInfo, @@ -10,13 +12,15 @@ use std::fmt::{Debug, Display}; use std::ops::Deref; /// Serves as the primary interface for interacting with contracts. +/// /// It includes methods for executing, querying, and managing contract states, -/// making it a fundamental trait for testing contract functionalities. +/// making it a fundamental trait for testing contracts. pub trait Contract where T: Clone + Debug + PartialEq + JsonSchema, Q: CustomQuery, { + /// Evaluates contract's `execute` entry-point. fn execute( &self, deps: DepsMut, @@ -25,6 +29,7 @@ where msg: Vec, ) -> AnyResult>; + /// Evaluates contract's `instantiate` entry-point. fn instantiate( &self, deps: DepsMut, @@ -33,12 +38,16 @@ where msg: Vec, ) -> AnyResult>; + /// Evaluates contract's `query` entry-point. fn query(&self, deps: Deps, env: Env, msg: Vec) -> AnyResult; + /// Evaluates contract's `sudo` entry-point. fn sudo(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult>; + /// Evaluates contract's `reply` entry-point. fn reply(&self, deps: DepsMut, env: Env, msg: Reply) -> AnyResult>; + /// Evaluates contract's `migrate` entry-point. fn migrate(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult>; } @@ -105,6 +114,7 @@ where C: Clone + Debug + PartialEq + JsonSchema + 'static, Q: CustomQuery + DeserializeOwned + 'static, { + /// Creates a new contract wrapper with default settings. pub fn new( execute_fn: ContractFn, instantiate_fn: ContractFn, @@ -155,6 +165,7 @@ where C: Clone + Debug + PartialEq + JsonSchema + 'static, Q: CustomQuery + DeserializeOwned + 'static, { + /// Populates [ContractWrapper] with contract's `sudo` entry-point and custom message type. pub fn with_sudo( self, sudo_fn: PermissionedFn, @@ -173,6 +184,7 @@ where } } + /// Populates [ContractWrapper] with contract's `sudo` entry-point and `Empty` as a custom message. pub fn with_sudo_empty( self, sudo_fn: PermissionedFn, @@ -191,6 +203,7 @@ where } } + /// Populates [ContractWrapper] with contract's `reply` entry-point and custom message type. pub fn with_reply( self, reply_fn: ReplyFn, @@ -208,7 +221,7 @@ where } } - /// A correlate of new_with_empty + /// Populates [ContractWrapper] with contract's `reply` entry-point and `Empty` as a custom message. pub fn with_reply_empty( self, reply_fn: ReplyFn, @@ -226,6 +239,7 @@ where } } + /// Populates [ContractWrapper] with contract's `migrate` entry-point and custom message type. pub fn with_migrate( self, migrate_fn: PermissionedFn, @@ -244,6 +258,7 @@ where } } + /// Populates [ContractWrapper] with contract's `migrate` entry-point and `Empty` as a custom message. pub fn with_migrate_empty( self, migrate_fn: PermissionedFn, diff --git a/src/custom_handler.rs b/src/custom_handler.rs index 02552a86..a29f30d8 100644 --- a/src/custom_handler.rs +++ b/src/custom_handler.rs @@ -1,3 +1,5 @@ +//! # Custom message and query handler + use crate::app::CosmosRouter; use crate::error::{bail, AnyResult}; use crate::{AppResponse, Module}; @@ -7,44 +9,46 @@ use std::cell::{Ref, RefCell}; use std::ops::Deref; use std::rc::Rc; -/// This struct serves as the internal state of CachingCustomHandler, carefully managing -/// internal mutability to keep it hidden from users. It's essential for maintaining a shared -/// internal state, especially since accessing mock internals becomes impossible once the -/// mock is passed to the app and not exposed by the API. +/// A cache for messages and queries processes by the custom module. #[derive(Derivative)] #[derivative(Default(bound = "", new = "true"), Clone(bound = ""))] pub struct CachingCustomHandlerState { + /// Cache for processes custom messages. execs: Rc>>, + /// Cache for processed custom queries. queries: Rc>>, } impl CachingCustomHandlerState { + /// Returns a slice of processed custom messages. pub fn execs(&self) -> impl Deref + '_ { Ref::map(self.execs.borrow(), Vec::as_slice) } + /// Returns a slice of processed custom queries. pub fn queries(&self) -> impl Deref + '_ { Ref::map(self.queries.borrow(), Vec::as_slice) } + /// Clears the cache. pub fn reset(&self) { self.execs.borrow_mut().clear(); self.queries.borrow_mut().clear(); } } -/// Custom handler storing all the messages it received, so they can be later verified. -/// State is thin shared state, so it can be hold after mock is passed to App to read state. +/// Custom handler that stores all received messages and queries. /// -/// Manages the internal state of a custom handler, recording execution and query messages. -/// Useful for tracking contract interactions during tests. +/// State is thin shared state, so it can be hold after mock is passed to [App](crate::App) to read state. #[derive(Clone, Derivative)] #[derivative(Default(bound = "", new = "true"))] pub struct CachingCustomHandler { + /// Cached state. state: CachingCustomHandlerState, } impl CachingCustomHandler { + /// Returns the cached state. pub fn state(&self) -> CachingCustomHandlerState { self.state.clone() } @@ -55,8 +59,7 @@ impl Module for CachingCustomHandler { type QueryT = Query; type SudoT = Empty; - // TODO: how to assert - // where ExecC: Exec, QueryC: Query + // TODO: how to assert like `where ExecC: Exec, QueryC: Query` fn execute( &self, _api: &dyn Api, @@ -70,17 +73,6 @@ impl Module for CachingCustomHandler { Ok(AppResponse::default()) } - fn sudo( - &self, - _api: &dyn Api, - _storage: &mut dyn Storage, - _router: &dyn CosmosRouter, - _block: &BlockInfo, - msg: Self::SudoT, - ) -> AnyResult { - bail!("Unexpected sudo msg {:?}", msg) - } - fn query( &self, _api: &dyn Api, @@ -92,4 +84,15 @@ impl Module for CachingCustomHandler { self.state.queries.borrow_mut().push(request); Ok(Binary::default()) } + + fn sudo( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + msg: Self::SudoT, + ) -> AnyResult { + bail!("Unexpected custom sudo message {:?}", msg) + } } diff --git a/src/error.rs b/src/error.rs index 7dc5925e..bd2576e4 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,60 +1,71 @@ +//! # Error definitions + pub use anyhow::{anyhow, bail, Context as AnyContext, Error as AnyError, Result as AnyResult}; use cosmwasm_std::{WasmMsg, WasmQuery}; use thiserror::Error; -///The error module deals with identifying and reporting problems that occur during testing. -///It's like a diagnostic tool that helps you understand what went wrong and where, so you can fix issues -/// more effectively. + +/// An enumeration of errors reported across the **CosmWasm MultiTest** library. #[derive(Debug, Error, PartialEq, Eq)] -///This module handles error definitions and management within `cw_multi_test``, ensuring that issues -///and exceptions encountered during the testing process are effectively identified and reported. pub enum Error { - #[error("Empty attribute key. Value: {value}")] - EmptyAttributeKey { value: String }, + /// Error variant for reporting an empty attribute key. + #[error("Empty attribute key. Value: {0}")] + EmptyAttributeKey(String), - #[error("Empty attribute value. Key: {key}")] - EmptyAttributeValue { key: String }, + /// Error variant for reporting an empty attribute value. + #[error("Empty attribute value. Key: {0}")] + EmptyAttributeValue(String), + /// Error variant for reporting a usage of reserved key prefix. #[error("Attribute key starts with reserved prefix _: {0}")] ReservedAttributeKey(String), + /// Error variant for reporting too short event types. #[error("Event type too short: {0}")] EventTypeTooShort(String), + /// Error variant for reporting that unsupported wasm query was encountered during processing. #[error("Unsupported wasm query: {0:?}")] UnsupportedWasmQuery(WasmQuery), + /// Error variant for reporting that unsupported wasm message was encountered during processing. #[error("Unsupported wasm message: {0:?}")] UnsupportedWasmMsg(WasmMsg), + /// Error variant for reporting invalid contract code. #[error("code id: invalid")] InvalidCodeId, + /// Error variant for reporting unregistered contract code. #[error("code id {0}: no such code")] UnregisteredCodeId(u64), + /// Error variant for reporting duplicated contract addresses. #[error("Contract with this address already exists: {0}")] DuplicatedContractAddress(String), } impl Error { + /// Creates an instance of the [Error](Self) for empty attribute key. pub fn empty_attribute_key(value: impl Into) -> Self { - Self::EmptyAttributeKey { - value: value.into(), - } + Self::EmptyAttributeKey(value.into()) } + /// Creates an instance of the [Error](Self) for empty attribute value. pub fn empty_attribute_value(key: impl Into) -> Self { - Self::EmptyAttributeValue { key: key.into() } + Self::EmptyAttributeValue(key.into()) } + /// Creates an instance of the [Error](Self) when reserved attribute key was used. pub fn reserved_attribute_key(key: impl Into) -> Self { Self::ReservedAttributeKey(key.into()) } + /// Creates an instance of the [Error](Self) for too short event types. pub fn event_type_too_short(ty: impl Into) -> Self { Self::EventTypeTooShort(ty.into()) } + /// Creates an instance of the [Error](Self) for duplicated contract addresses. pub fn duplicated_contract_address(address: impl Into) -> Self { Self::DuplicatedContractAddress(address.into()) } diff --git a/src/executor.rs b/src/executor.rs index ec1672d2..3c08feb9 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -7,25 +7,29 @@ use cw_utils::{parse_execute_response_data, parse_instantiate_response_data}; use schemars::JsonSchema; use serde::Serialize; use std::fmt::Debug; -/// AppResponse likely refers to a standardized response format from the App. -/// It's mentioned in the cw-multi-test-main package, which suggests it's used for returning -/// information about the processing of transactions or queries. + +/// A subset of data returned as a response of a contract entry point, +/// such as `instantiate`, `execute` or `migrate`. #[derive(Default, Clone, Debug)] pub struct AppResponse { + /// Response events. pub events: Vec, + /// Response data. pub data: Option, } impl AppResponse { - // Return all custom attributes returned by the contract in the `idx` event. - // We assert the type is wasm, and skip the contract_address attribute. + /// Returns all custom attributes returned by the contract in the `idx` event. + /// + /// We assert the type is wasm, and skip the contract_address attribute. #[track_caller] pub fn custom_attrs(&self, idx: usize) -> &[Attribute] { assert_eq!(self.events[idx].ty.as_str(), "wasm"); &self.events[idx].attributes[1..] } - /// Check if there is an Event that is a super-set of this. + /// Checks if there is an Event that is a super-set of this. + /// /// It has the same type, and all compare.attributes are included in it as well. /// You don't need to specify them all. pub fn has_event(&self, expected: &Event) -> bool { @@ -38,7 +42,7 @@ impl AppResponse { }) } - /// Like has_event but panics if no match + /// Like [has_event](Self::has_event) but panics if there is no match. #[track_caller] pub fn assert_event(&self, expected: &Event) { assert!( @@ -60,16 +64,19 @@ impl From for AppResponse { } } } -///Defines the interface for executing transactions and contract interactions. -/// It's a central component in the testing framework, managing the operational flow and -/// ensuring that contract calls are processed correctly. +/// A trait defining a default behaviour of the message executor. +/// +/// Defines the interface for executing transactions and contract interactions. +/// It is a central component in the testing framework, managing the operational +/// flow and ensuring that contract _calls_ are processed correctly. pub trait Executor where C: Clone + Debug + PartialEq + JsonSchema + 'static, { - /// Runs arbitrary CosmosMsg. - /// This will create a cache before the execution, so no state changes are persisted if this - /// returns an error, but all are persisted on success. + /// Processes (executes) an arbitrary `CosmosMsg`. + /// This will create a cache before the execution, + /// so no state changes are persisted if this returns an error, + /// but all are persisted on success. fn execute(&mut self, sender: Addr, msg: CosmosMsg) -> AnyResult; /// Create a contract and get the new address. @@ -132,8 +139,9 @@ where } /// Execute a contract and process all returned messages. - /// This is just a helper around execute(), - /// but we parse out the data field to that what is returned by the contract (not the protobuf wrapper) + /// This is just a helper function around [execute()](Self::execute) + /// with `WasmMsg::Execute` message, but in this case we parse out the data field + /// to that what is returned by the contract (not the protobuf wrapper). fn execute_contract( &mut self, sender: Addr, @@ -154,8 +162,10 @@ where Ok(res) } - /// Migrate a contract. Sender must be registered admin. - /// This is just a helper around execute() + /// Migrates a contract. + /// Sender must be registered admin. + /// This is just a helper function around [execute()](Self::execute) + /// with `WasmMsg::Migrate` message. fn migrate_contract( &mut self, sender: Addr, @@ -172,6 +182,9 @@ where self.execute(sender, msg.into()) } + /// Sends tokens to specified recipient. + /// This is just a helper function around [execute()](Self::execute) + /// with `BankMsg::Send` message. fn send_tokens( &mut self, sender: Addr, diff --git a/src/lib.rs b/src/lib.rs index 7f44d300..ea0bdcb6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,128 @@ -//! Multitest is a design to simulate a blockchain environment in pure Rust. -//! This allows us to run unit tests that involve contract -> contract, -//! and contract -> bank interactions. This is not intended to be a full blockchain app -//! but to simulate the Cosmos SDK x/wasm module close enough to gain confidence in -//! multi-contract deployments before testing them on a live blockchain. +//! # CosmWasm MultiTest //! -//! To understand the design of this module, please refer to `../DESIGN.md` +//! **CosmWasm MultiTest** is designed to simulate a blockchain environment in pure Rust. +//! This allows to run unit tests that involve **contract 🡘 contract**, +//! and **contract 🡘 module** interactions. **CosmWasm MultiTest** is not intended +//! to be a full blockchain application, but to simulate the Cosmos SDK x/wasm module close enough +//! to gain confidence in multi-contract deployments, before testing them on a live blockchain. +//! +//! The following sections explains some of the design for those who want to use the API, +//! as well as those who want to take a look under the hood of **CosmWasm MultiTest**. +//! +//! ## Key APIs +//! +//! ### App +//! +//! The main entry point to the system is called [App], which represents a blockchain application. +//! It maintains an idea of block height and time, which can be updated to simulate multiple +//! blocks. You can use application's [update_block](App::update_block) method to increment +//! the timestamp by 5 seconds and the height by 1 (simulating a new block) or you can write +//! any other mutator of [BlockInfo](cosmwasm_std::BlockInfo) to advance more. +//! +//! [App] exposes an entry point [execute](App::execute) that allows to execute +//! any [CosmosMsg](cosmwasm_std::CosmosMsg) and wraps it in an atomic transaction. +//! That is, only if [execute](App::execute) returns a success, then the state will be committed. +//! It returns the data and a list of [Event](cosmwasm_std::Event)s on successful execution +//! or an **`Err(String)`** on error. There are some helper methods tied to the [Executor] trait +//! that create the [CosmosMsg](cosmwasm_std::CosmosMsg) for you to provide a less verbose API. +//! [App]'s methods like [instantiate_contract](App::instantiate_contract), +//! [execute_contract](App::execute_contract), and [send_tokens](App::send_tokens) are exposed +//! for your convenience in writing tests. +//! Each method executes one [CosmosMsg](cosmwasm_std::CosmosMsg) atomically, as if it was submitted by a user. +//! You can also use [execute_multi](App::execute_multi) if you wish to execute multiple messages together +//! that revert the state as a whole in case of any failure. +//! +//! The other key entry point to [App] is the [Querier](cosmwasm_std::Querier) interface that it implements. +//! In particular, you can use [wrap](App::wrap) to get a [QuerierWrapper](cosmwasm_std::QuerierWrapper), +//! which provides all kinds of interesting APIs to query the blockchain, like +//! [query_all_balances](cosmwasm_std::QuerierWrapper::query_all_balances) and +//! [query_wasm_smart](cosmwasm_std::QuerierWrapper::query_wasm_smart). +//! Putting this all together, you have one [Storage](cosmwasm_std::Storage) wrapped into an application, +//! where you can execute contracts and bank, query them easily, and update the current +//! [BlockInfo](cosmwasm_std::BlockInfo), in an API that is not very verbose or cumbersome. +//! Under the hood it will process all messages returned from contracts, move _bank_ tokens +//! and call into other contracts. +//! +//! You can easily create an [App] for use in your testcode like shown below. +//! Having a single utility function for creating and configuring the [App] is the common +//! pattern while testing contracts with **CosmWasm MultiTest**. +//! +//! ``` +//! use cw_multi_test::App; +//! +//! fn mock_app() -> App { +//! App::default() +//! } +//! ``` +//! +//! The [App] maintains the root [Storage](cosmwasm_std::Storage), and the [BlockInfo](cosmwasm_std::BlockInfo) +//! for the current block. It also contains a [Router] (discussed below), which can process +//! any [CosmosMsg](cosmwasm_std::CosmosMsg) variant by passing it to the proper keeper. +//! +//! > **Note**: [App] properly handles submessages and reply blocks. +//! +//! > **Note**: While the API currently supports custom messages, we don't currently have an implementation +//! > of the default keeper, except of experimental [CachingCustomHandler](custom_handler::CachingCustomHandler). +//! +//! ### Contracts +//! +//! Before you can call contracts, you must **instantiate** them. And to instantiate them, you need a `code_id`. +//! In `wasmd`, this `code_id` points to some stored Wasm code that is then run. In multitest, we use it to +//! point to a `Box` that should be run. That is, you need to implement the [Contract] trait +//! and then add the contract to the [App] via [store_code](App::store_code) function. +//! +//! The [Contract] trait defines the major entry points to any CosmWasm contract: +//! [instantiate](Contract::instantiate), [execute](Contract::execute), [query](Contract::query), +//! [sudo](Contract::sudo), [reply](Contract::reply) (for submessages) and [migrate](Contract::migrate). +//! +//! In order to easily implement [Contract] from some existing contract code, we use the [ContractWrapper] struct, +//! which takes some function pointers and combines them. You can take a look at **test_helpers** module +//! for some examples or how to do so (and useful mocks for some test cases). +//! Here is an example of wrapping a CosmWasm contract into a [Contract] trait to be added to an [App]: +//! +//! ``` +//! use cosmwasm_std::Empty; +//! use cw1_whitelist::contract::{execute, instantiate, query}; +//! use cw_multi_test::{App, Contract, ContractWrapper}; +//! +//! pub fn contract_whitelist() -> Box> { +//! Box::new(ContractWrapper::new(execute, instantiate, query)) +//! } +//! +//! let mut app = App::default(); +//! let code_id = app.store_code(contract_whitelist()); +//! // use this code_id to instantiate a contract +//! ``` +//! +//! ### Modules +//! +//! There is only one root [Storage](cosmwasm_std::Storage), stored inside [App]. +//! This is wrapped into a transaction, and then passed down to other functions to work with. +//! The code that modifies the Storage is divided into _modules_ much like the CosmosSDK. +//! Currently the message processing logic is divided into one _module_ for every [CosmosMsg](cosmwasm_std) variant. +//! [Bank] handles [BankMsg](cosmwasm_std::BankMsg) and [BankQuery](cosmwasm_std::BankQuery), +//! [Wasm] handles [WasmMsg](cosmwasm_std::WasmMsg) and [WasmQuery](cosmwasm_std::WasmQuery), etc. +//! +//! ### Router +//! +//! The [Router] groups all modules in the system into one "macro-module" that can handle +//! any [CosmosMsg](cosmwasm_std::CosmosMsg). While [Bank] handles [BankMsg](cosmwasm_std::BankMsg), +//! and [Wasm] handles [WasmMsg](cosmwasm_std::WasmMsg), we need to combine them into a larger composite +//! to let them process messages from [App]. This is the whole concept of the [Router]. +//! If you take a look at the [execute](Router::execute) method, you will see it is quite straightforward. +//! +//! Note that the only way one module can call or query another module is by dispatching messages via the [Router]. +//! This allows us to implement an independent [Wasm] in a way that it can process [SubMsg](cosmwasm_std::SubMsg) +//! that call into [Bank]. You can see an example of that in _send_ method of the [WasmKeeper], +//! where it moves bank tokens from one account to another. +//! +//! ### Addons +//! +//! (tbd) + +#![deny(missing_docs)] +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::missing_crate_level_docs)] pub mod addons; mod addresses; @@ -12,7 +130,6 @@ mod app; mod app_builder; mod bank; mod checksums; -#[allow(clippy::type_complexity)] mod contracts; pub mod custom_handler; pub mod error; diff --git a/src/module.rs b/src/module.rs index 79f7b3f3..aac82ba4 100644 --- a/src/module.rs +++ b/src/module.rs @@ -7,12 +7,18 @@ use serde::de::DeserializeOwned; use std::fmt::Debug; use std::marker::PhantomData; +/// # General module +/// /// Provides a generic interface for modules within the test environment. -/// It's essential for creating modular and extensible testing setups, allowing developers -/// to integrate custom functionalities or test specific scenarios. +/// It is essential for creating modular and extensible testing setups, +/// allowing developers to integrate custom functionalities +/// or test specific scenarios. pub trait Module { + /// Type of messages processed by the module instance. type ExecT; + /// Type of queries processed by the module instance. type QueryT; + /// Type of privileged messages used by the module instance. type SudoT; /// Runs any [ExecT](Self::ExecT) message, @@ -58,18 +64,21 @@ pub trait Module { ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static; } -/// This could be a diagnostic or testing tool within the Cosmos ecosystem, designed to -/// intentionally fail under certain conditions to test the robustness and error-handling -/// capabilities of the network. +/// # Always failing module +/// +/// This could be a diagnostic or testing tool within the Cosmos ecosystem, +/// designed to intentionally fail during processing any message, query or privileged action. pub struct FailingModule(PhantomData<(ExecT, QueryT, SudoT)>); impl FailingModule { + /// Creates an instance of a failing module. pub fn new() -> Self { Self(PhantomData) } } impl Default for FailingModule { + /// Creates a default instance of a failing module. fn default() -> Self { Self::new() } @@ -122,17 +131,21 @@ where bail!("Unexpected sudo msg {:?}", msg) } } -///This struct might represent a module in the Cosmos ecosystem designed to accept certain types of transactions -/// or interactions. The specific functionality would depend on the context of its use. +/// # Always accepting module +/// +/// This struct represents a module in the Cosmos ecosystem designed to +/// always accept all processed messages, queries and privileged actions. pub struct AcceptingModule(PhantomData<(ExecT, QueryT, SudoT)>); impl AcceptingModule { + /// Creates an instance of an accepting module. pub fn new() -> Self { Self(PhantomData) } } impl Default for AcceptingModule { + /// Creates an instance of an accepting module with default settings. fn default() -> Self { Self::new() } @@ -161,7 +174,7 @@ where Ok(AppResponse::default()) } - /// Runs any [QueryT](Self::QueryT) message, always returns an empty binary. + /// Runs any [QueryT](Self::QueryT) message, always returns a default (empty) binary. fn query( &self, _api: &dyn Api, diff --git a/src/staking.rs b/src/staking.rs index 9e6fd0a0..ccbf914a 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -14,7 +14,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::collections::{BTreeSet, VecDeque}; -// Contains some general staking parameters +/// A structure containing some general staking parameters. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct StakingInfo { /// The denominator of the staking token @@ -26,6 +26,7 @@ pub struct StakingInfo { } impl Default for StakingInfo { + /// Creates staking info with default settings. fn default() -> Self { StakingInfo { bonded_denom: "TOKEN".to_string(), @@ -101,13 +102,17 @@ pub const NAMESPACE_STAKING: &[u8] = b"staking"; // https://github.com/cosmos/cosmos-sdk/blob/4f6f6c00021f4b5ee486bbb71ae2071a8ceb47c9/x/distribution/types/keys.go#L16 pub const NAMESPACE_DISTRIBUTION: &[u8] = b"distribution"; -// We need to expand on this, but we will need this to properly test out staking -#[derive(Clone, std::fmt::Debug, PartialEq, Eq, JsonSchema)] +/// Staking privileged action definition. +/// +/// We need to expand on this, but we will need this to properly test out staking +#[derive(Clone, Debug, PartialEq, Eq, JsonSchema)] pub enum StakingSudo { /// Slashes the given percentage of the validator's stake. /// For now, you cannot slash retrospectively in tests. Slash { + /// Validator's address. validator: String, + /// Percentage of the validator's stake. percentage: Decimal, }, /// Causes the unbonding queue to be processed. @@ -117,12 +122,13 @@ pub enum StakingSudo { ProcessQueue {}, } -///Manages staking operations, vital for testing contracts in proof-of-stake (PoS) blockchain environments. -///This trait simulates staking behaviors, including delegation, validator operations, and reward mechanisms. +/// A trait defining a behaviour of the stake keeper. +/// +/// Manages staking operations, vital for testing contracts in proof-of-stake (PoS) blockchain environments. +/// This trait simulates staking behaviors, including delegation, validator operations, and reward mechanisms. pub trait Staking: Module { /// This is called from the end blocker (`update_block` / `set_block`) to process the - /// staking queue. - /// Needed because unbonding has a waiting time. + /// staking queue. Needed because unbonding has a waiting time. /// If you're implementing a dummy staking module, this can be a no-op. fn process_queue( &self, @@ -133,19 +139,24 @@ pub trait Staking: Module AnyResult; } +/// A trait defining a behaviour of the distribution keeper. pub trait Distribution: Module {} -/// + +/// A structure representing a default stake keeper. pub struct StakeKeeper { + /// Module address of a default stake keeper. module_addr: Addr, } impl Default for StakeKeeper { + /// Creates a new stake keeper with default settings. fn default() -> Self { Self::new() } } impl StakeKeeper { + /// Creates a new stake keeper with default module address. pub fn new() -> Self { StakeKeeper { // The address of the staking module. This holds all staked tokens. @@ -156,7 +167,6 @@ impl StakeKeeper { /// Provides some general parameters to the stake keeper pub fn setup(&self, storage: &mut dyn Storage, staking_info: StakingInfo) -> AnyResult<()> { let mut storage = prefixed(storage, NAMESPACE_STAKING); - STAKING_INFO.save(&mut storage, &staking_info)?; Ok(()) } @@ -867,6 +877,8 @@ impl Module for StakeKeeper { } } +/// A structure representing a default distribution keeper. +/// /// This module likely manages the distribution of rewards and fees within the blockchain network. /// It could handle tasks like distributing block rewards to validators and delegators, /// and managing community funding mechanisms. @@ -874,8 +886,9 @@ impl Module for StakeKeeper { pub struct DistributionKeeper {} impl DistributionKeeper { + /// Creates a new distribution keeper with default settings. pub fn new() -> Self { - DistributionKeeper {} + Self::default() } /// Removes all rewards from the given (delegator, validator) pair and returns the amount @@ -902,6 +915,7 @@ impl DistributionKeeper { Ok(rewards) } + /// Returns the withdraw address for specified delegator. pub fn get_withdraw_address(storage: &dyn Storage, delegator: &Addr) -> AnyResult { Ok(match WITHDRAW_ADDRESS.may_load(storage, delegator)? { Some(a) => a, @@ -909,7 +923,9 @@ impl DistributionKeeper { }) } - // https://docs.cosmos.network/main/modules/distribution#msgsetwithdrawaddress + /// Sets (changes) the [withdraw address] of the delegator. + /// + /// [withdraw address]: https://docs.cosmos.network/main/modules/distribution#msgsetwithdrawaddress pub fn set_withdraw_address( storage: &mut dyn Storage, delegator: &Addr, diff --git a/src/tests/test_custom_handler.rs b/src/tests/test_custom_handler.rs index 2bc821bc..7ded4f72 100644 --- a/src/tests/test_custom_handler.rs +++ b/src/tests/test_custom_handler.rs @@ -71,7 +71,7 @@ fn custom_handler_has_no_sudo() { // run sudo function assert_eq!( - "Unexpected sudo msg Empty", + "Unexpected custom sudo message Empty", custom_handler .sudo( app.api(), diff --git a/src/wasm.rs b/src/wasm.rs index 72c497bd..94c3c46a 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -30,13 +30,17 @@ pub(crate) const NAMESPACE_WASM: &[u8] = b"wasm"; /// See const CONTRACT_ATTR: &str = "_contract_address"; +/// A structure representing a privileged message. #[derive(Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct WasmSudo { + /// Address of a contract the privileged action will be sent to. pub contract_addr: Addr, + /// Message representing privileged action to be executed by contract `sudo` entry-point. pub msg: Binary, } impl WasmSudo { + /// Creates a new privileged message for specified contract address and action to be executed. pub fn new(contract_addr: &Addr, msg: &T) -> StdResult { Ok(WasmSudo { contract_addr: contract_addr.clone(), @@ -121,6 +125,7 @@ pub trait Wasm { fn dump_wasm_raw(&self, storage: &dyn Storage, address: &Addr) -> Vec; } +/// A structure representing a default wasm keeper. pub struct WasmKeeper { /// Contract codes that stand for wasm code in real-life blockchain. code_base: Vec>>, @@ -357,6 +362,19 @@ where ExecC: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { + /// Creates a wasm keeper with default settings. + /// + /// # Example + /// + /// ``` + /// use cw_multi_test::{AppBuilder, no_init, WasmKeeper}; + /// + /// // create wasm keeper + /// let wasm_keeper = WasmKeeper::new(); + /// + /// // create and use the application with newly created wasm keeper + /// let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init); + /// ``` pub fn new() -> Self { Self::default() } @@ -365,6 +383,9 @@ where since = "0.18.0", note = "use `WasmKeeper::new().with_address_generator` instead; will be removed in version 1.0.0" )] + /// Populates an existing [WasmKeeper] with custom contract address generator. + /// + /// See description of [with_address_generator](Self::with_address_generator) function for details. pub fn new_with_custom_address_generator( address_generator: impl AddressGenerator + 'static, ) -> Self { @@ -374,6 +395,36 @@ where } } + /// Populates an existing [WasmKeeper] with custom contract address generator. + /// + /// # Example + /// + /// ``` + /// use cosmwasm_std::{Addr, Api, Storage}; + /// use cw_multi_test::{AddressGenerator, AppBuilder, no_init, WasmKeeper}; + /// use cw_multi_test::error::AnyResult; + /// + /// struct CustomAddressGenerator; + /// + /// impl AddressGenerator for CustomAddressGenerator { + /// fn contract_address( + /// &self, + /// api: &dyn Api, + /// storage: &mut dyn Storage, + /// code_id: u64, + /// instance_id: u64, + /// ) -> AnyResult { + /// // here implement your address generation logic + /// # Ok(Addr::unchecked("test_address")) + /// } + /// } + /// + /// // populate wasm with your custom address generator + /// let wasm_keeper = WasmKeeper::new().with_address_generator(CustomAddressGenerator); + /// + /// // create and use the application with customized wasm keeper + /// let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init); + /// ``` pub fn with_address_generator( mut self, address_generator: impl AddressGenerator + 'static, @@ -382,6 +433,29 @@ where self } + /// Populates an existing [WasmKeeper] with custom checksum generator for the contract code. + /// + /// # Example + /// + /// ``` + /// use cosmwasm_std::{Addr, HexBinary}; + /// use cw_multi_test::{AppBuilder, ChecksumGenerator, no_init, WasmKeeper}; + /// + /// struct MyChecksumGenerator; + /// + /// impl ChecksumGenerator for MyChecksumGenerator { + /// fn checksum(&self, creator: &Addr, code_id: u64) -> HexBinary { + /// // here implement your custom checksum generator + /// # HexBinary::default() + /// } + /// } + /// + /// // populate wasm keeper with your custom checksum generator + /// let wasm_keeper = WasmKeeper::new().with_checksum_generator(MyChecksumGenerator); + /// + /// // create and use the application with customized wasm keeper + /// let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init); + /// ``` pub fn with_checksum_generator( mut self, checksum_generator: impl ChecksumGenerator + 'static, @@ -390,6 +464,7 @@ where self } + /// Executes contract's `query` entry-point. pub fn query_smart( &self, address: Addr, @@ -409,6 +484,7 @@ where ) } + /// Returns the value stored under specified key in contracts storage. pub fn query_raw(&self, address: Addr, storage: &dyn Storage, key: &[u8]) -> Binary { let storage = self.contract_storage_readonly(storage, &address); let data = storage.get(key).unwrap_or_default(); @@ -882,6 +958,7 @@ where Ok(addr) } + /// Executes contract's `execute` entry-point. pub fn call_execute( &self, api: &dyn Api, @@ -902,6 +979,7 @@ where )?) } + /// Executes contract's `instantiate` entry-point. pub fn call_instantiate( &self, address: Addr, @@ -922,6 +1000,7 @@ where )?) } + /// Executes contract's `reply` entry-point. pub fn call_reply( &self, address: Addr, @@ -941,6 +1020,7 @@ where )?) } + /// Executes contract's `sudo` entry-point. pub fn call_sudo( &self, address: Addr, @@ -960,6 +1040,7 @@ where )?) } + /// Executes contract's `migrate` entry-point. pub fn call_migrate( &self, address: Addr, @@ -1048,6 +1129,7 @@ where }) } + /// Saves contract data in a storage under specified address. pub fn save_contract( &self, storage: &mut dyn Storage, diff --git a/tests/test_wasm/test_with_addr_gen.rs b/tests/test_wasm/test_with_addr_gen.rs index f536b695..af0035c4 100644 --- a/tests/test_wasm/test_with_addr_gen.rs +++ b/tests/test_wasm/test_with_addr_gen.rs @@ -53,7 +53,7 @@ fn custom_address_generator_should_work() { struct CustomAddressGenerator; impl AddressGenerator for CustomAddressGenerator { - // deprecated from version 0.18.0 + // deprecated since version 0.18.0 fn next_address(&self, _storage: &mut dyn Storage) -> Addr { // Panic in case of calling this function unreachable!("this function should not be called") diff --git a/tests/test_wasm/test_with_checksum_gen.rs b/tests/test_wasm/test_with_checksum_gen.rs index 8917a29c..89b7d600 100644 --- a/tests/test_wasm/test_with_checksum_gen.rs +++ b/tests/test_wasm/test_with_checksum_gen.rs @@ -1,7 +1,7 @@ #![cfg(feature = "cosmwasm_1_2")] use crate::test_contracts; -use cosmwasm_std::{Addr, Empty, HexBinary}; +use cosmwasm_std::{Addr, HexBinary}; use cw_multi_test::{no_init, App, AppBuilder, ChecksumGenerator, WasmKeeper}; #[test] @@ -37,8 +37,7 @@ impl ChecksumGenerator for MyChecksumGenerator { #[test] fn custom_checksum_generator_should_work() { // prepare wasm keeper with custom checksum generator - let wasm_keeper: WasmKeeper = - WasmKeeper::default().with_checksum_generator(MyChecksumGenerator); + let wasm_keeper = WasmKeeper::new().with_checksum_generator(MyChecksumGenerator); // prepare application with custom wasm keeper let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init); From 3adc8fc8eb2177692c559c192f5361bb0d131498 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 15 Dec 2023 17:35:39 +0100 Subject: [PATCH 024/250] Fixes. --- src/addons/addresses/mock.rs | 2 +- src/app.rs | 5 +++-- src/executor.rs | 2 +- src/staking.rs | 4 ++-- src/stargate.rs | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/addons/addresses/mock.rs b/src/addons/addresses/mock.rs index c9292816..ab166f95 100644 --- a/src/addons/addresses/mock.rs +++ b/src/addons/addresses/mock.rs @@ -4,7 +4,7 @@ use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage}; use sha2::digest::Update; use sha2::{Digest, Sha256}; -/// Address generator that mimics the [wasmd](https://github.com/CosmWasm/wasmd) behaviour. +/// Address generator that mimics the [wasmd](https://github.com/CosmWasm/wasmd) behavior. /// /// [MockAddressGenerator] implements [AddressGenerator] trait in terms of /// [`contract_address`](AddressGenerator::contract_address) and diff --git a/src/app.rs b/src/app.rs index fc542c38..29c97188 100644 --- a/src/app.rs +++ b/src/app.rs @@ -20,6 +20,7 @@ use schemars::JsonSchema; use serde::{de::DeserializeOwned, Serialize}; use std::fmt::Debug; use std::marker::PhantomData; + /// Advances the blockchain environment to the next block in tests, enabling developers to simulate /// time-dependent contract behaviors and block-related triggers efficiently. pub fn next_block(block: &mut BlockInfo) { @@ -361,7 +362,7 @@ where self.block = block; } - /// Advances the current block to "next block" steps and adds one height and 5 seconds. + /// Updates the current block applying the specified closure, usually [next_block]. pub fn update_block(&mut self, action: F) { self.router .staking @@ -486,7 +487,7 @@ where GovT: Gov, StargateT: Stargate, { - /// Returns a querier populated with the instance if this [Router]. + /// Returns a querier populated with the instance of this [Router]. pub fn querier<'a>( &'a self, api: &'a dyn Api, diff --git a/src/executor.rs b/src/executor.rs index 3c08feb9..d5932ca8 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -64,7 +64,7 @@ impl From for AppResponse { } } } -/// A trait defining a default behaviour of the message executor. +/// A trait defining a default behavior of the message executor. /// /// Defines the interface for executing transactions and contract interactions. /// It is a central component in the testing framework, managing the operational diff --git a/src/staking.rs b/src/staking.rs index ccbf914a..8e11e569 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -122,7 +122,7 @@ pub enum StakingSudo { ProcessQueue {}, } -/// A trait defining a behaviour of the stake keeper. +/// A trait defining a behavior of the stake keeper. /// /// Manages staking operations, vital for testing contracts in proof-of-stake (PoS) blockchain environments. /// This trait simulates staking behaviors, including delegation, validator operations, and reward mechanisms. @@ -139,7 +139,7 @@ pub trait Staking: Module AnyResult; } -/// A trait defining a behaviour of the distribution keeper. +/// A trait defining a behavior of the distribution keeper. pub trait Distribution: Module {} /// A structure representing a default stake keeper. diff --git a/src/stargate.rs b/src/stargate.rs index 39d23aac..b8127c2d 100644 --- a/src/stargate.rs +++ b/src/stargate.rs @@ -8,7 +8,7 @@ use std::fmt::Debug; /// Stargate interface. /// -/// This trait provides the default behaviour for all functions +/// This trait provides the default behavior for all functions /// that is equal to [StargateFailing] implementation. pub trait Stargate { /// Processes stargate messages. From f29d0ffabdcbc3ec09da1d035b8920df3fd78484 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 18 Dec 2023 10:28:51 +0100 Subject: [PATCH 025/250] Covered prefixed storage. --- src/prefixed_storage/mod.rs | 45 +++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/prefixed_storage/mod.rs b/src/prefixed_storage/mod.rs index 0e7a6e44..a6cfa41e 100644 --- a/src/prefixed_storage/mod.rs +++ b/src/prefixed_storage/mod.rs @@ -134,6 +134,35 @@ mod tests { assert_eq!(s2.get(b"elsewhere"), None); } + #[test] + fn prefixed_storage_range() { + // prepare prefixed storage + let mut storage = MockStorage::new(); + let mut ps1 = PrefixedStorage::new(&mut storage, b"foo"); + ps1.set(b"a", b"A"); + ps1.set(b"l", b"L"); + ps1.set(b"p", b"P"); + ps1.set(b"z", b"Z"); + assert_eq!(storage.get(b"\x00\x03fooa").unwrap(), b"A".to_vec()); + assert_eq!(storage.get(b"\x00\x03fool").unwrap(), b"L".to_vec()); + assert_eq!(storage.get(b"\x00\x03foop").unwrap(), b"P".to_vec()); + assert_eq!(storage.get(b"\x00\x03fooz").unwrap(), b"Z".to_vec()); + // query prefixed storage using range function + let ps2 = PrefixedStorage::new(&mut storage, b"foo"); + assert_eq!( + vec![b"A".to_vec(), b"L".to_vec(), b"P".to_vec()], + ps2.range(Some(b"a"), Some(b"z"), Order::Ascending) + .map(|(_, value)| value) + .collect::>>() + ); + assert_eq!( + vec![b"Z".to_vec(), b"P".to_vec(), b"L".to_vec(), b"A".to_vec()], + ps2.range(Some(b"a"), None, Order::Descending) + .map(|(_, value)| value) + .collect::>>() + ); + } + #[test] fn prefixed_storage_multilevel_set_and_get() { let mut storage = MockStorage::new(); @@ -167,6 +196,22 @@ mod tests { assert_eq!(s2.get(b"obar"), None); } + #[test] + #[should_panic(expected = "not implemented")] + fn readonly_prefixed_storage_set() { + let mut storage = MockStorage::new(); + let mut rps = ReadonlyPrefixedStorage::new(&mut storage, b"foo"); + rps.set(b"bar", b"gotcha"); + } + + #[test] + #[should_panic(expected = "not implemented")] + fn readonly_prefixed_storage_remove() { + let mut storage = MockStorage::new(); + let mut rps = ReadonlyPrefixedStorage::new(&mut storage, b"foo"); + rps.remove(b"gotcha"); + } + #[test] fn readonly_prefixed_storage_multilevel_get() { let mut storage = MockStorage::new(); From a61882769c695f762303a785112065988a69202c Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 18 Dec 2023 10:52:45 +0100 Subject: [PATCH 026/250] Covered bank module. --- Cargo.lock | 8 ++++---- src/bank.rs | 4 ++-- src/prefixed_storage/mod.rs | 2 ++ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3b15d773..29661721 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -868,18 +868,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", diff --git a/src/bank.rs b/src/bank.rs index d198e435..63a6f2ad 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -193,7 +193,7 @@ impl Module for BankKeeper { self.burn(&mut bank_storage, sender, amount)?; Ok(AppResponse::default()) } - m => bail!("Unsupported bank message: {:?}", m), + _ => unimplemented!("bank message: {msg:?}"), } } @@ -248,7 +248,7 @@ impl Module for BankKeeper { res.amount = amount; Ok(to_json_binary(&res)?) } - q => bail!("Unsupported bank query: {:?}", q), + _ => unimplemented!("bank query: {request:?}",), } } } diff --git a/src/prefixed_storage/mod.rs b/src/prefixed_storage/mod.rs index a6cfa41e..9e9da867 100644 --- a/src/prefixed_storage/mod.rs +++ b/src/prefixed_storage/mod.rs @@ -198,6 +198,7 @@ mod tests { #[test] #[should_panic(expected = "not implemented")] + #[allow(clippy::unnecessary_mut_passed)] fn readonly_prefixed_storage_set() { let mut storage = MockStorage::new(); let mut rps = ReadonlyPrefixedStorage::new(&mut storage, b"foo"); @@ -206,6 +207,7 @@ mod tests { #[test] #[should_panic(expected = "not implemented")] + #[allow(clippy::unnecessary_mut_passed)] fn readonly_prefixed_storage_remove() { let mut storage = MockStorage::new(); let mut rps = ReadonlyPrefixedStorage::new(&mut storage, b"foo"); From 56ef29d31096112f88292f80f913bcf35f9f51fa Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 18 Dec 2023 11:20:15 +0100 Subject: [PATCH 027/250] Covered errors. --- src/error.rs | 20 +++++++++++++++++ src/tests/mod.rs | 1 + src/tests/test_error.rs | 50 +++++++++++++++++++++++++++++++++++++++++ src/wasm.rs | 8 +++---- 4 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 src/tests/test_error.rs diff --git a/src/error.rs b/src/error.rs index bd2576e4..013e0aed 100644 --- a/src/error.rs +++ b/src/error.rs @@ -65,6 +65,26 @@ impl Error { Self::EventTypeTooShort(ty.into()) } + /// Creates an instance of the [Error](Self) for unsupported wasm queries. + pub fn unsupported_wasm_query(query: WasmQuery) -> Self { + Self::UnsupportedWasmQuery(query) + } + + /// Creates an instance of the [Error](Self) for unsupported wasm messages. + pub fn unsupported_wasm_message(msg: WasmMsg) -> Self { + Self::UnsupportedWasmMsg(msg) + } + + /// Creates an instance of the [Error](Self) for invalid contract code identifier. + pub fn invalid_contract_code_id() -> Self { + Self::InvalidCodeId + } + + /// Creates an instance of the [Error](Self) for unregistered contract code identifier. + pub fn unregistered_code_id(code_id: u64) -> Self { + Self::UnregisteredCodeId(code_id) + } + /// Creates an instance of the [Error](Self) for duplicated contract addresses. pub fn duplicated_contract_address(address: impl Into) -> Self { Self::DuplicatedContractAddress(address.into()) diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 53370229..2f5d2092 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -2,6 +2,7 @@ mod test_app; mod test_custom_handler; +mod test_error; mod test_gov; mod test_ibc; mod test_stargate; diff --git a/src/tests/test_error.rs b/src/tests/test_error.rs new file mode 100644 index 00000000..eb113e72 --- /dev/null +++ b/src/tests/test_error.rs @@ -0,0 +1,50 @@ +use crate::error::Error; +use cosmwasm_std::{WasmMsg, WasmQuery}; + +#[test] +fn instantiating_error_should_work() { + assert_eq!( + "Empty attribute key. Value: alpha", + Error::empty_attribute_key("alpha").to_string() + ); + assert_eq!( + "Empty attribute value. Key: beta", + Error::empty_attribute_value("beta").to_string() + ); + assert_eq!( + "Attribute key starts with reserved prefix _: gamma", + Error::reserved_attribute_key("gamma").to_string() + ); + assert_eq!( + "Event type too short: event_type", + Error::event_type_too_short("event_type").to_string() + ); + assert_eq!( + r#"Unsupported wasm query: ContractInfo { contract_addr: "contract1984" }"#, + Error::unsupported_wasm_query(WasmQuery::ContractInfo { + contract_addr: "contract1984".to_string() + }) + .to_string() + ); + assert_eq!( + r#"Unsupported wasm message: Migrate { contract_addr: "contract1984", new_code_id: 1984, msg: }"#, + Error::unsupported_wasm_message(WasmMsg::Migrate { + contract_addr: "contract1984".to_string(), + new_code_id: 1984, + msg: Default::default(), + }) + .to_string() + ); + assert_eq!( + "code id: invalid", + Error::invalid_contract_code_id().to_string() + ); + assert_eq!( + "code id 53: no such code", + Error::unregistered_code_id(53).to_string() + ); + assert_eq!( + "Contract with this address already exists: contract1984", + Error::duplicated_contract_address("contract1984").to_string() + ); +} diff --git a/src/wasm.rs b/src/wasm.rs index 94c3c46a..39edfb36 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -192,7 +192,7 @@ where res.checksum = code_data.checksum.clone(); to_json_binary(&res).map_err(Into::into) } - other => bail!(Error::UnsupportedWasmQuery(other)), + other => bail!(Error::unsupported_wasm_query(other)), } } @@ -279,12 +279,12 @@ impl WasmKeeper { /// Returns code data of the contract with specified code id. fn code_data(&self, code_id: u64) -> AnyResult<&CodeData> { if code_id < 1 { - bail!(Error::InvalidCodeId); + bail!(Error::invalid_contract_code_id()); } Ok(self .code_data .get((code_id - 1) as usize) - .ok_or(Error::UnregisteredCodeId(code_id))?) + .ok_or(Error::unregistered_code_id(code_id))?) } fn contract_namespace(&self, contract: &Addr) -> Vec { @@ -668,7 +668,7 @@ where WasmMsg::ClearAdmin { contract_addr } => { self.update_admin(api, storage, sender, &contract_addr, None) } - msg => bail!(Error::UnsupportedWasmMsg(msg)), + msg => bail!(Error::unsupported_wasm_message(msg)), } } From 350db532c728bcd3b7ea64d17e13eecbd3b27425 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 18 Dec 2023 11:33:54 +0100 Subject: [PATCH 028/250] Fixed clippy warnings. --- src/wasm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm.rs b/src/wasm.rs index 39edfb36..46a500c1 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -284,7 +284,7 @@ impl WasmKeeper { Ok(self .code_data .get((code_id - 1) as usize) - .ok_or(Error::unregistered_code_id(code_id))?) + .ok_or_else(|| Error::unregistered_code_id(code_id))?) } fn contract_namespace(&self, contract: &Addr) -> Vec { From 5e022433412c916d2b69839c8375d890e2f51b01 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 18 Dec 2023 11:55:28 +0100 Subject: [PATCH 029/250] Minor fixes. --- src/wasm.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wasm.rs b/src/wasm.rs index 46a500c1..5ea2e962 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -192,7 +192,7 @@ where res.checksum = code_data.checksum.clone(); to_json_binary(&res).map_err(Into::into) } - other => bail!(Error::unsupported_wasm_query(other)), + _ => unimplemented!("{}", Error::unsupported_wasm_query(request)), } } @@ -553,9 +553,9 @@ where router: &dyn CosmosRouter, block: &BlockInfo, sender: Addr, - wasm_msg: WasmMsg, + msg: WasmMsg, ) -> AnyResult { - match wasm_msg { + match msg { WasmMsg::Execute { contract_addr, msg, @@ -668,7 +668,7 @@ where WasmMsg::ClearAdmin { contract_addr } => { self.update_admin(api, storage, sender, &contract_addr, None) } - msg => bail!(Error::unsupported_wasm_message(msg)), + _ => unimplemented!("{}", Error::unsupported_wasm_message(msg)), } } From 02b11823383961394a6fc149fbbd7b3475b380cf Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 18 Dec 2023 17:42:10 +0100 Subject: [PATCH 030/250] Refactored custom message type contraints. --- src/app.rs | 19 ++++----- src/app_builder.rs | 5 +-- src/module.rs | 7 ++-- src/stargate.rs | 8 ++-- src/test_helpers/mod.rs | 5 ++- src/test_helpers/reflect.rs | 12 +++--- src/tests/test_app.rs | 43 +++++++++++--------- src/tests/test_custom_handler.rs | 14 +++---- src/wasm.rs | 10 ++--- tests/test_app_builder/mod.rs | 7 ++-- tests/test_app_builder/test_with_stargate.rs | 6 +-- 11 files changed, 67 insertions(+), 69 deletions(-) diff --git a/src/app.rs b/src/app.rs index 29c97188..77d1f026 100644 --- a/src/app.rs +++ b/src/app.rs @@ -12,11 +12,10 @@ use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; use crate::{AppBuilder, GovFailingModule, IbcFailingModule}; use cosmwasm_std::testing::{MockApi, MockStorage}; use cosmwasm_std::{ - from_json, to_json_binary, Addr, Api, Binary, BlockInfo, ContractResult, CosmosMsg, + from_json, to_json_binary, Addr, Api, Binary, BlockInfo, ContractResult, CosmosMsg, CustomMsg, CustomQuery, Empty, Querier, QuerierResult, QuerierWrapper, QueryRequest, Record, Storage, SystemError, SystemResult, }; -use schemars::JsonSchema; use serde::{de::DeserializeOwned, Serialize}; use std::fmt::Debug; use std::marker::PhantomData; @@ -107,7 +106,7 @@ impl BasicApp { /// Outside of `App` implementation to make type elision better. pub fn custom_app(init_fn: F) -> BasicApp where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: Debug + CustomQuery + DeserializeOwned + 'static, F: FnOnce( &mut Router< @@ -130,7 +129,7 @@ where impl Querier for App where - CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, @@ -154,7 +153,7 @@ impl for App where - CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, @@ -250,7 +249,7 @@ where IbcT: Ibc, GovT: Gov, StargateT: Stargate, - CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, { /// Registers contract code (like uploading wasm bytecode on a chain), @@ -340,7 +339,7 @@ where impl App where - CustomT::ExecT: Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, @@ -476,7 +475,7 @@ pub struct Router { impl Router where - CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, CustomT: Module, WasmT: Wasm, @@ -576,7 +575,7 @@ pub trait CosmosRouter { impl CosmosRouter for Router where - CustomT::ExecT: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, CustomT: Module, WasmT: Wasm, @@ -739,7 +738,7 @@ impl<'a, ExecC, QueryC> RouterQuerier<'a, ExecC, QueryC> { impl<'a, ExecC, QueryC> Querier for RouterQuerier<'a, ExecC, QueryC> where - ExecC: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { diff --git a/src/app_builder.rs b/src/app_builder.rs index eb5b7821..e8b3d9db 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -6,8 +6,7 @@ use crate::{ WasmKeeper, }; use cosmwasm_std::testing::{mock_env, MockApi, MockStorage}; -use cosmwasm_std::{Api, BlockInfo, CustomQuery, Empty, Storage}; -use schemars::JsonSchema; +use cosmwasm_std::{Api, BlockInfo, CustomMsg, CustomQuery, Empty, Storage}; use serde::de::DeserializeOwned; use std::fmt::Debug; @@ -123,7 +122,7 @@ impl StargateFailing, > where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: Debug + CustomQuery + DeserializeOwned + 'static, { /// Creates builder with default components designed to work with custom exec and query diff --git a/src/module.rs b/src/module.rs index aac82ba4..cc73a4d6 100644 --- a/src/module.rs +++ b/src/module.rs @@ -1,8 +1,7 @@ use crate::app::CosmosRouter; use crate::error::{bail, AnyResult}; use crate::AppResponse; -use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomQuery, Querier, Storage}; -use schemars::JsonSchema; +use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomMsg, CustomQuery, Querier, Storage}; use serde::de::DeserializeOwned; use std::fmt::Debug; use std::marker::PhantomData; @@ -33,7 +32,7 @@ pub trait Module { msg: Self::ExecT, ) -> AnyResult where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static; /// Runs any [QueryT](Self::QueryT) message, @@ -61,7 +60,7 @@ pub trait Module { msg: Self::SudoT, ) -> AnyResult where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static; } /// # Always failing module diff --git a/src/stargate.rs b/src/stargate.rs index b8127c2d..a91dc89d 100644 --- a/src/stargate.rs +++ b/src/stargate.rs @@ -1,10 +1,8 @@ use crate::error::AnyResult; use crate::{AppResponse, CosmosRouter}; use anyhow::bail; -use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomQuery, Querier, Storage}; -use schemars::JsonSchema; +use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomMsg, CustomQuery, Querier, Storage}; use serde::de::DeserializeOwned; -use std::fmt::Debug; /// Stargate interface. /// @@ -27,7 +25,7 @@ pub trait Stargate { value: Binary, ) -> AnyResult where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { let _ = (api, storage, router, block); @@ -83,7 +81,7 @@ impl Stargate for StargateAccepting { value: Binary, ) -> AnyResult where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { let _ = (api, storage, router, block, sender, type_url, value); diff --git a/src/test_helpers/mod.rs b/src/test_helpers/mod.rs index 16d23082..d6ee1adc 100644 --- a/src/test_helpers/mod.rs +++ b/src/test_helpers/mod.rs @@ -1,5 +1,6 @@ #![cfg(test)] +use cosmwasm_std::CustomMsg; use cw_storage_plus::Item; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -17,10 +18,12 @@ pub mod stargate; /// Custom message for testing purposes. #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename = "snake_case")] -pub enum CustomMsg { +pub enum CustomHelperMsg { SetName { name: String }, SetAge { age: u32 }, } +impl CustomMsg for CustomHelperMsg {} + /// Persisted counter for testing purposes. pub const COUNT: Item = Item::new("count"); diff --git a/src/test_helpers/reflect.rs b/src/test_helpers/reflect.rs index c7b37407..41b4396e 100644 --- a/src/test_helpers/reflect.rs +++ b/src/test_helpers/reflect.rs @@ -1,4 +1,4 @@ -use crate::test_helpers::{payout, CustomMsg, COUNT}; +use crate::test_helpers::{payout, CustomHelperMsg, COUNT}; use crate::{Contract, ContractWrapper}; use cosmwasm_std::{ to_json_binary, Binary, Deps, DepsMut, Empty, Env, Event, MessageInfo, Reply, Response, @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Message { - pub messages: Vec>, + pub messages: Vec>, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -25,7 +25,7 @@ fn instantiate( _env: Env, _info: MessageInfo, _msg: Empty, -) -> Result, StdError> { +) -> Result, StdError> { COUNT.save(deps.storage, &0)?; Ok(Response::default()) } @@ -35,7 +35,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)) @@ -55,7 +55,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") @@ -64,7 +64,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/src/tests/test_app.rs b/src/tests/test_app.rs index f6d41f18..46f33db2 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -1,7 +1,7 @@ use crate::custom_handler::CachingCustomHandler; use crate::error::{bail, AnyResult}; use crate::test_helpers::echo::EXECUTE_REPLY_BASE_ID; -use crate::test_helpers::{caller, echo, error, hackatom, payout, reflect, CustomMsg}; +use crate::test_helpers::{caller, echo, error, hackatom, payout, reflect, CustomHelperMsg}; use crate::transactions::{transactional, StorageTransaction}; use crate::wasm::ContractData; use crate::AppBuilder; @@ -12,8 +12,9 @@ use crate::{ use cosmwasm_std::testing::{mock_env, MockQuerier}; use cosmwasm_std::{ coin, coins, from_json, to_json_binary, Addr, AllBalanceResponse, Api, Attribute, BankMsg, - BankQuery, Binary, BlockInfo, Coin, CosmosMsg, CustomQuery, Empty, Event, OverflowError, - OverflowOperation, Querier, Reply, StdError, StdResult, Storage, SubMsg, WasmMsg, + BankQuery, Binary, BlockInfo, Coin, CosmosMsg, CustomMsg, CustomQuery, Empty, Event, + OverflowError, OverflowOperation, Querier, Reply, StdError, StdResult, Storage, SubMsg, + WasmMsg, }; use cw_storage_plus::Item; use cw_utils::parse_instantiate_response_data; @@ -28,7 +29,7 @@ fn get_balance( addr: &Addr, ) -> Vec where - CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, @@ -46,7 +47,7 @@ fn query_router( rcpt: &Addr, ) -> Vec where - CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema, + CustomT::ExecT: CustomMsg, CustomT::QueryT: CustomQuery + DeserializeOwned, WasmT: Wasm, BankT: Bank, @@ -72,7 +73,7 @@ fn query_app( rcpt: &Addr, ) -> Vec where - CustomT::ExecT: Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, @@ -324,7 +325,7 @@ fn reflect_success() { 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) @@ -430,7 +431,7 @@ fn reflect_error() { 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) @@ -581,7 +582,7 @@ fn reflect_sub_message_reply_works() { 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) @@ -855,17 +856,19 @@ mod custom_handler { const PITY: Item = Item::new("pity"); #[derive(Clone, 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; @@ -879,7 +882,7 @@ mod custom_handler { msg: Self::ExecT, ) -> AnyResult where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { let lottery = LOTTERY.load(storage)?; @@ -912,7 +915,7 @@ mod custom_handler { _msg: Self::SudoT, ) -> AnyResult where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { bail!("sudo not implemented for CustomHandler") @@ -955,7 +958,7 @@ mod custom_handler { 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 @@ -969,7 +972,7 @@ mod custom_handler { 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(), }); @@ -1183,7 +1186,7 @@ mod reply_data_overwrite { 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) @@ -1621,7 +1624,7 @@ mod custom_messages { #[test] fn triggering_custom_msg() { - let custom_handler = CachingCustomHandler::::new(); + let custom_handler = CachingCustomHandler::::new(); let custom_handler_state = custom_handler.state(); let mut app = AppBuilder::new_custom() @@ -1641,7 +1644,7 @@ mod custom_messages { 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() @@ -1652,7 +1655,7 @@ mod custom_messages { 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()); @@ -1669,7 +1672,7 @@ mod protobuf_wrapped_data { let owner = Addr::unchecked("owner"); let init_funds = vec![coin(20, "btc")]; - let mut app = custom_app::(|router, _, storage| { + let mut app = custom_app::(|router, _, storage| { router .bank .init_balance(storage, &owner, init_funds) diff --git a/src/tests/test_custom_handler.rs b/src/tests/test_custom_handler.rs index 7ded4f72..36168264 100644 --- a/src/tests/test_custom_handler.rs +++ b/src/tests/test_custom_handler.rs @@ -1,5 +1,5 @@ use crate::custom_handler::CachingCustomHandler; -use crate::test_helpers::CustomMsg; +use crate::test_helpers::CustomHelperMsg; use crate::{App, Module}; use cosmwasm_std::testing::MockStorage; use cosmwasm_std::{Addr, Empty}; @@ -14,7 +14,7 @@ fn custom_handler_works() { let mut storage = MockStorage::default(); // create custom handler - let custom_handler = CachingCustomHandler::::new(); + let custom_handler = CachingCustomHandler::::new(); // run execute function let _ = custom_handler.execute( @@ -23,7 +23,7 @@ fn custom_handler_works() { app.router(), &app.block_info(), Addr::unchecked("sender"), - CustomMsg::SetAge { age: 32 }, + CustomHelperMsg::SetAge { age: 32 }, ); // run query function @@ -32,7 +32,7 @@ fn custom_handler_works() { &storage, &(*app.wrap()), &app.block_info(), - CustomMsg::SetName { + CustomHelperMsg::SetName { name: "John".to_string(), }, ); @@ -43,13 +43,13 @@ fn custom_handler_works() { // there should be one exec message assert_eq!( custom_handler_state.execs().to_owned(), - vec![CustomMsg::SetAge { age: 32 }] + vec![CustomHelperMsg::SetAge { age: 32 }] ); // there should be one query message assert_eq!( custom_handler_state.queries().to_owned(), - vec![CustomMsg::SetName { + vec![CustomHelperMsg::SetName { name: "John".to_string() }] ); @@ -67,7 +67,7 @@ fn custom_handler_has_no_sudo() { let mut storage = MockStorage::default(); // create custom handler - let custom_handler = CachingCustomHandler::::new(); + let custom_handler = CachingCustomHandler::::new(); // run sudo function assert_eq!( diff --git a/src/wasm.rs b/src/wasm.rs index 5ea2e962..388014fe 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -9,9 +9,9 @@ use crate::transactions::transactional; use cosmwasm_std::testing::mock_wasmd_attr; use cosmwasm_std::{ to_json_binary, Addr, Api, Attribute, BankMsg, Binary, BlockInfo, Coin, ContractInfo, - ContractInfoResponse, CustomQuery, Deps, DepsMut, Env, Event, HexBinary, MessageInfo, Order, - Querier, QuerierWrapper, Record, Reply, ReplyOn, Response, StdResult, Storage, SubMsg, - SubMsgResponse, SubMsgResult, TransactionInfo, WasmMsg, WasmQuery, + ContractInfoResponse, CustomMsg, CustomQuery, Deps, DepsMut, Env, Event, HexBinary, + MessageInfo, Order, Querier, QuerierWrapper, Record, Reply, ReplyOn, Response, StdResult, + Storage, SubMsg, SubMsgResponse, SubMsgResult, TransactionInfo, WasmMsg, WasmQuery, }; use cw_storage_plus::Map; use prost::Message; @@ -154,7 +154,7 @@ impl Default for WasmKeeper { impl Wasm for WasmKeeper where - ExecC: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { fn query( @@ -359,7 +359,7 @@ impl WasmKeeper { impl WasmKeeper where - ExecC: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { /// Creates a wasm keeper with default settings. diff --git a/tests/test_app_builder/mod.rs b/tests/test_app_builder/mod.rs index 476df228..d2dcc5c2 100644 --- a/tests/test_app_builder/mod.rs +++ b/tests/test_app_builder/mod.rs @@ -1,7 +1,6 @@ -use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomQuery, Querier, Storage}; +use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomMsg, CustomQuery, Querier, Storage}; use cw_multi_test::error::{bail, AnyResult}; use cw_multi_test::{AppResponse, CosmosRouter, Module}; -use schemars::JsonSchema; use serde::de::DeserializeOwned; use std::fmt::Debug; use std::marker::PhantomData; @@ -52,7 +51,7 @@ where _msg: Self::ExecT, ) -> AnyResult where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { bail!(self.1); @@ -67,7 +66,7 @@ where _msg: Self::SudoT, ) -> AnyResult where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { bail!(self.3); diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index 624e701f..65771bd2 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -1,6 +1,6 @@ use anyhow::bail; use cosmwasm_std::{ - to_json_vec, Addr, Api, Binary, BlockInfo, CosmosMsg, CustomQuery, Empty, Querier, + to_json_vec, Addr, Api, Binary, BlockInfo, CosmosMsg, CustomMsg, CustomQuery, Empty, Querier, QueryRequest, Storage, }; use cw_multi_test::error::AnyResult; @@ -8,9 +8,7 @@ use cw_multi_test::{ no_init, AppBuilder, AppResponse, CosmosRouter, Executor, Stargate, StargateAccepting, StargateFailing, }; -use schemars::JsonSchema; use serde::de::DeserializeOwned; -use std::fmt::Debug; const EXECUTE_MSG: &str = "stargate execute called"; const QUERY_MSG: &str = "stargate query called"; @@ -30,7 +28,7 @@ impl Stargate for MyStargateKeeper { value: Binary, ) -> AnyResult where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { assert_eq!("test", type_url); From 32869e70091ff2551909766cf1f107b8453a9804 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 18 Dec 2023 17:52:35 +0100 Subject: [PATCH 031/250] Refactored custom message type contraints in contract trait. --- src/contracts.rs | 21 ++++++++++----------- src/executor.rs | 7 +++---- src/test_helpers/caller.rs | 6 ++---- src/test_helpers/echo.rs | 6 +++--- src/test_helpers/error.rs | 6 ++---- src/test_helpers/hackatom.rs | 6 +++--- src/test_helpers/payout.rs | 7 +++---- src/wasm.rs | 2 +- 8 files changed, 27 insertions(+), 34 deletions(-) diff --git a/src/contracts.rs b/src/contracts.rs index 954f49c7..6d7afb21 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -2,10 +2,9 @@ use crate::error::{anyhow, bail, AnyError, AnyResult}; use cosmwasm_std::{ - from_json, Binary, CosmosMsg, CustomQuery, Deps, DepsMut, Empty, Env, MessageInfo, + from_json, Binary, CosmosMsg, CustomMsg, CustomQuery, Deps, DepsMut, Empty, Env, MessageInfo, QuerierWrapper, Reply, Response, SubMsg, }; -use schemars::JsonSchema; use serde::de::DeserializeOwned; use std::error::Error; use std::fmt::{Debug, Display}; @@ -17,7 +16,7 @@ use std::ops::Deref; /// making it a fundamental trait for testing contracts. pub trait Contract where - T: Clone + Debug + PartialEq + JsonSchema, + T: CustomMsg, Q: CustomQuery, { /// Evaluates contract's `execute` entry-point. @@ -92,7 +91,7 @@ pub struct ContractWrapper< E4: Display + Debug + Send + Sync + 'static, E5: Display + Debug + Send + Sync + 'static, E6: Display + Debug + Send + Sync + 'static, - C: Clone + Debug + PartialEq + JsonSchema, + C: CustomMsg, Q: CustomQuery + DeserializeOwned + 'static, { execute_fn: ContractClosure, @@ -111,7 +110,7 @@ where E1: Display + Debug + Send + Sync + 'static, E2: Display + Debug + Send + Sync + 'static, E3: Display + Debug + Send + Sync + 'static, - C: Clone + Debug + PartialEq + JsonSchema + 'static, + C: CustomMsg + 'static, Q: CustomQuery + DeserializeOwned + 'static, { /// Creates a new contract wrapper with default settings. @@ -162,7 +161,7 @@ where E4: Display + Debug + Send + Sync + 'static, E5: Display + Debug + Send + Sync + 'static, E6: Display + Debug + Send + Sync + 'static, - C: Clone + Debug + PartialEq + JsonSchema + 'static, + C: CustomMsg + 'static, Q: CustomQuery + DeserializeOwned + 'static, { /// Populates [ContractWrapper] with contract's `sudo` entry-point and custom message type. @@ -282,7 +281,7 @@ fn customize_fn(raw_fn: ContractFn) -> ContractC where T: DeserializeOwned + 'static, E: Display + Debug + Send + Sync + 'static, - C: Clone + Debug + PartialEq + JsonSchema + 'static, + C: CustomMsg + 'static, Q: CustomQuery + DeserializeOwned + 'static, { let customized = move |mut deps: DepsMut, @@ -337,7 +336,7 @@ fn customize_permissioned_fn( where T: DeserializeOwned + 'static, E: Display + Debug + Send + Sync + 'static, - C: Clone + Debug + PartialEq + JsonSchema + 'static, + C: CustomMsg + 'static, Q: CustomQuery + DeserializeOwned + 'static, { let customized = move |deps: DepsMut, env: Env, msg: T| -> Result, E> { @@ -348,7 +347,7 @@ where fn customize_response(resp: Response) -> Response where - C: Clone + Debug + PartialEq + JsonSchema, + C: CustomMsg, { let mut customized_resp = Response::::new() .add_submessages(resp.messages.into_iter().map(customize_msg::)) @@ -360,7 +359,7 @@ where fn customize_msg(msg: SubMsg) -> SubMsg where - C: Clone + Debug + PartialEq + JsonSchema, + C: CustomMsg, { SubMsg { msg: match msg.msg { @@ -393,7 +392,7 @@ where E4: Display + Debug + Send + Sync + 'static, E5: Display + Debug + Send + Sync + 'static, E6: Display + Debug + Send + Sync + 'static, - C: Clone + Debug + PartialEq + JsonSchema, + C: CustomMsg, Q: CustomQuery + DeserializeOwned, { fn execute( diff --git a/src/executor.rs b/src/executor.rs index d5932ca8..0e80f171 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -1,10 +1,9 @@ use crate::error::AnyResult; use cosmwasm_std::{ - to_json_binary, Addr, Attribute, BankMsg, Binary, Coin, CosmosMsg, Event, SubMsgResponse, - WasmMsg, + to_json_binary, Addr, Attribute, BankMsg, Binary, Coin, CosmosMsg, CustomMsg, Event, + SubMsgResponse, WasmMsg, }; use cw_utils::{parse_execute_response_data, parse_instantiate_response_data}; -use schemars::JsonSchema; use serde::Serialize; use std::fmt::Debug; @@ -71,7 +70,7 @@ impl From for AppResponse { /// flow and ensuring that contract _calls_ are processed correctly. pub trait Executor where - C: Clone + Debug + PartialEq + JsonSchema + 'static, + C: CustomMsg + 'static, { /// Processes (executes) an arbitrary `CosmosMsg`. /// This will create a cache before the execution, diff --git a/src/test_helpers/caller.rs b/src/test_helpers/caller.rs index c283cda5..1d50a62a 100644 --- a/src/test_helpers/caller.rs +++ b/src/test_helpers/caller.rs @@ -1,9 +1,7 @@ use crate::{Contract, ContractWrapper}; use cosmwasm_std::{ - Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError, SubMsg, WasmMsg, + Binary, CustomMsg, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError, SubMsg, WasmMsg, }; -use schemars::JsonSchema; -use std::fmt::Debug; fn instantiate( _deps: DepsMut, @@ -33,7 +31,7 @@ fn query(_deps: Deps, _env: Env, _msg: Empty) -> Result { pub fn contract() -> Box> where - C: Clone + Debug + PartialEq + JsonSchema + 'static, + C: CustomMsg + 'static, { let contract = ContractWrapper::new_with_empty(execute, instantiate, query); Box::new(contract) diff --git a/src/test_helpers/echo.rs b/src/test_helpers/echo.rs index 02ab2696..0b73a394 100644 --- a/src/test_helpers/echo.rs +++ b/src/test_helpers/echo.rs @@ -5,8 +5,8 @@ use crate::{Contract, ContractWrapper}; use cosmwasm_std::{ - to_json_binary, Attribute, Binary, Deps, DepsMut, Empty, Env, Event, MessageInfo, Reply, - Response, StdError, SubMsg, SubMsgResponse, SubMsgResult, + to_json_binary, Attribute, Binary, CustomMsg, Deps, DepsMut, Empty, Env, Event, MessageInfo, + Reply, Response, StdError, SubMsg, SubMsgResponse, SubMsgResult, }; use cw_utils::{parse_execute_response_data, parse_instantiate_response_data}; use derivative::Derivative; @@ -130,7 +130,7 @@ pub fn contract() -> Box> { pub fn custom_contract() -> Box> where - C: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + C: CustomMsg + DeserializeOwned + 'static, { let contract = ContractWrapper::new(execute::, instantiate::, query).with_reply(reply::); diff --git a/src/test_helpers/error.rs b/src/test_helpers/error.rs index 033853de..1654440a 100644 --- a/src/test_helpers/error.rs +++ b/src/test_helpers/error.rs @@ -1,7 +1,5 @@ use crate::{Contract, ContractWrapper}; -use cosmwasm_std::{Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError}; -use schemars::JsonSchema; -use std::fmt::Debug; +use cosmwasm_std::{Binary, CustomMsg, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError}; fn instantiate_err( _deps: DepsMut, @@ -36,7 +34,7 @@ fn query(_deps: Deps, _env: Env, _msg: Empty) -> Result { pub fn contract(instantiable: bool) -> Box> where - C: Clone + Debug + PartialEq + JsonSchema + 'static, + C: CustomMsg + 'static, { let contract = if instantiable { ContractWrapper::new_with_empty(execute, instantiate_ok, query) diff --git a/src/test_helpers/hackatom.rs b/src/test_helpers/hackatom.rs index 394c7351..34d4f1ee 100644 --- a/src/test_helpers/hackatom.rs +++ b/src/test_helpers/hackatom.rs @@ -2,10 +2,10 @@ use crate::{Contract, ContractWrapper}; use cosmwasm_std::{ - to_json_binary, BankMsg, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError, + to_json_binary, BankMsg, Binary, CustomMsg, Deps, DepsMut, Empty, Env, MessageInfo, Response, + StdError, }; use cw_storage_plus::Item; -use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::fmt::Debug; @@ -77,7 +77,7 @@ pub fn contract() -> Box> { #[allow(dead_code)] pub fn custom_contract() -> Box> where - C: Clone + Debug + PartialEq + JsonSchema + 'static, + C: CustomMsg + 'static, { let contract = ContractWrapper::new_with_empty(execute, instantiate, query).with_migrate_empty(migrate); diff --git a/src/test_helpers/payout.rs b/src/test_helpers/payout.rs index a1d13ea2..159f6cea 100644 --- a/src/test_helpers/payout.rs +++ b/src/test_helpers/payout.rs @@ -1,11 +1,10 @@ use crate::test_helpers::COUNT; use crate::{Contract, ContractWrapper}; use cosmwasm_std::{ - to_json_binary, BankMsg, Binary, Coin, Deps, DepsMut, Empty, Env, MessageInfo, Response, - StdError, + to_json_binary, BankMsg, Binary, Coin, CustomMsg, Deps, DepsMut, Empty, Env, MessageInfo, + Response, StdError, }; use cw_storage_plus::Item; -use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::fmt::Debug; @@ -76,7 +75,7 @@ fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result { pub fn contract() -> Box> where - C: Clone + Debug + PartialEq + JsonSchema + 'static, + C: CustomMsg + 'static, { let contract = ContractWrapper::new_with_empty(execute, instantiate, query).with_sudo_empty(sudo); diff --git a/src/wasm.rs b/src/wasm.rs index 388014fe..9e313c90 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -341,7 +341,7 @@ impl WasmKeeper { fn verify_response(response: Response) -> AnyResult> where - T: Clone + Debug + PartialEq + JsonSchema, + T: CustomMsg, { Self::verify_attributes(&response.attributes)?; From 62bc44c7ca836733f0a59374632cc17feedeb816 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 19 Dec 2023 11:29:18 +0100 Subject: [PATCH 032/250] Added App::store_with_id function. --- src/app.rs | 23 +++- src/error.rs | 9 ++ src/wasm.rs | 141 ++++++++++++++++------- tests/test_app_builder/test_with_wasm.rs | 9 +- 4 files changed, 136 insertions(+), 46 deletions(-) diff --git a/src/app.rs b/src/app.rs index 77d1f026..d4432fe2 100644 --- a/src/app.rs +++ b/src/app.rs @@ -256,10 +256,10 @@ where /// so it can later be used to instantiate a contract. pub fn store_code(&mut self, code: Box>) -> u64 { self.init_modules(|router, _, _| { - router - .wasm - .store_code(Addr::unchecked("code-creator"), code) + let creator = Addr::unchecked("creator"); + router.wasm.store_code(creator, None, code) }) + .unwrap() } /// Registers contract code (like [store_code](Self::store_code)), @@ -269,7 +269,22 @@ where creator: Addr, code: Box>, ) -> u64 { - self.init_modules(|router, _, _| router.wasm.store_code(creator, code)) + self.init_modules(|router, _, _| router.wasm.store_code(creator, None, code)) + .unwrap() + } + + /// Registers contract code (like [store_code](Self::store_code)), + /// but takes the code identifier as an additional argument. + pub fn store_code_with_id( + &mut self, + code_id: u64, + code: Box>, + ) -> u64 { + self.init_modules(|router, _, _| { + let creator = Addr::unchecked("creator"); + router.wasm.store_code(creator, code_id.into(), code) + }) + .unwrap() } /// Duplicates the contract code identified by `code_id` and returns diff --git a/src/error.rs b/src/error.rs index 013e0aed..0c3e8f59 100644 --- a/src/error.rs +++ b/src/error.rs @@ -39,6 +39,10 @@ pub enum Error { #[error("code id {0}: no such code")] UnregisteredCodeId(u64), + /// Error variant for reporting duplicated contract code identifier. + #[error("duplicated code id {0}")] + DuplicatedCodeId(u64), + /// Error variant for reporting duplicated contract addresses. #[error("Contract with this address already exists: {0}")] DuplicatedContractAddress(String), @@ -85,6 +89,11 @@ impl Error { Self::UnregisteredCodeId(code_id) } + /// Creates an instance of the [Error](Self) for duplicated contract code identifier. + pub fn duplicated_code_id(code_id: u64) -> Self { + Self::DuplicatedCodeId(code_id) + } + /// Creates an instance of the [Error](Self) for duplicated contract addresses. pub fn duplicated_contract_address(address: impl Into) -> Self { Self::DuplicatedContractAddress(address.into()) diff --git a/src/wasm.rs b/src/wasm.rs index 9e313c90..7bf1ba02 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -19,6 +19,7 @@ use schemars::JsonSchema; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use std::borrow::Borrow; +use std::collections::BTreeMap; use std::fmt::Debug; //TODO Make `CONTRACTS` private in version 1.0 when the function AddressGenerator::next_address will be removed. @@ -71,8 +72,8 @@ struct CodeData { creator: Addr, /// Checksum of the contract's code base. checksum: HexBinary, - /// Identifier of the code base where the contract code is stored in memory. - code_base_id: usize, + /// Identifier of the _source_ code of the contract stored in wasm keeper. + source_id: usize, } /// Acts as the interface for interacting with WebAssembly (Wasm) modules. @@ -112,7 +113,12 @@ pub trait Wasm { ) -> AnyResult; /// Stores the contract's code and returns an identifier of the stored contract's code. - fn store_code(&mut self, creator: Addr, code: Box>) -> u64; + fn store_code( + &mut self, + creator: Addr, + opt_code_id: Option, + code: Box>, + ) -> AnyResult; /// Duplicates the contract's code with specified identifier /// and returns an identifier of the copy of the contract's code. @@ -130,7 +136,7 @@ pub struct WasmKeeper { /// Contract codes that stand for wasm code in real-life blockchain. code_base: Vec>>, /// Code data with code base identifier and additional attributes. - code_data: Vec, + code_data: BTreeMap, /// Contract's address generator. address_generator: Box, /// Contract's code checksum generator. @@ -144,7 +150,7 @@ impl Default for WasmKeeper { fn default() -> Self { Self { code_base: Vec::default(), - code_data: Vec::default(), + code_data: BTreeMap::default(), address_generator: Box::new(SimpleAddressGenerator), checksum_generator: Box::new(SimpleChecksumGenerator), _p: std::marker::PhantomData, @@ -230,29 +236,46 @@ where /// Stores the contract's code in the in-memory lookup table. /// Returns an identifier of the stored contract code. - fn store_code(&mut self, creator: Addr, code: Box>) -> u64 { - let code_base_id = self.code_base.len(); - self.code_base.push(code); - let code_id = (self.code_data.len() + 1) as u64; + fn store_code( + &mut self, + creator: Addr, + opt_code_id: Option, + code: Box>, + ) -> AnyResult { + // prepare the next identifier for the contract 'source' code + let source_id = self.code_base.len(); + // prepare the next contract code identifier + let code_id = self.next_code_id(opt_code_id)?; + // calculate the checksum of the contract 'source' code based on code_id let checksum = self.checksum_generator.checksum(&creator, code_id); - self.code_data.push(CodeData { - creator, - checksum, - code_base_id, - }); - code_id + // store the 'source' code of the contract + self.code_base.push(code); + // store the additional code attributes like creator address and checksum + self.code_data.insert( + code_id, + CodeData { + creator, + checksum, + source_id, + }, + ); + Ok(code_id) } /// Duplicates the contract's code with specified identifier. /// Returns an identifier of the copy of the contract's code. fn duplicate_code(&mut self, code_id: u64) -> AnyResult { let code_data = self.code_data(code_id)?; - self.code_data.push(CodeData { - creator: code_data.creator.clone(), - checksum: code_data.checksum.clone(), - code_base_id: code_data.code_base_id, - }); - Ok(code_id + 1) + let new_code_id = self.next_code_id(None)?; + self.code_data.insert( + new_code_id, + CodeData { + creator: code_data.creator.clone(), + checksum: code_data.checksum.clone(), + source_id: code_data.source_id, + }, + ); + Ok(new_code_id) } /// Returns `ContractData` for the contract with specified address. @@ -273,7 +296,7 @@ impl WasmKeeper { /// Returns a handler to code of the contract with specified code id. pub fn contract_code(&self, code_id: u64) -> AnyResult<&dyn Contract> { let code_data = self.code_data(code_id)?; - Ok(self.code_base[code_data.code_base_id].borrow()) + Ok(self.code_base[code_data.source_id].borrow()) } /// Returns code data of the contract with specified code id. @@ -283,7 +306,7 @@ impl WasmKeeper { } Ok(self .code_data - .get((code_id - 1) as usize) + .get(&code_id) .ok_or_else(|| Error::unregistered_code_id(code_id))?) } @@ -355,6 +378,25 @@ impl WasmKeeper { Ok(response) } + + /// Returns the next code identifier. + fn next_code_id(&self, requested_code_id: Option) -> AnyResult { + if let Some(code_id) = requested_code_id { + if self.code_data.contains_key(&code_id) { + bail!(Error::duplicated_code_id(code_id)); + } else { + Ok(code_id) + } + } else { + Ok(self + .code_data + .keys() + .last() + .unwrap_or(&0u64) + .checked_add(1) + .ok_or(Error::InvalidCodeId)?) + } + } } impl WasmKeeper @@ -1154,17 +1196,14 @@ where } } -// TODO: replace with code in utils - #[derive(Clone, PartialEq, Message)] struct InstantiateResponse { #[prost(string, tag = "1")] - pub address: ::prost::alloc::string::String, + pub address: String, #[prost(bytes, tag = "2")] - pub data: ::prost::alloc::vec::Vec, + pub data: Vec, } -// TODO: encode helpers in utils fn instantiate_response(data: Option, contact_address: &Addr) -> Binary { let data = data.unwrap_or_default().to_vec(); let init_data = InstantiateResponse { @@ -1180,7 +1219,7 @@ fn instantiate_response(data: Option, contact_address: &Addr) -> Binary #[derive(Clone, PartialEq, Message)] struct ExecuteResponse { #[prost(bytes, tag = "1")] - pub data: ::prost::alloc::vec::Vec, + pub data: Vec, } // empty return if no data present in original @@ -1246,7 +1285,9 @@ mod test { let mut wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), error::contract(false)); + let code_id = wasm_keeper + .store_code(Addr::unchecked("creator"), None, error::contract(false)) + .unwrap(); transactional(&mut wasm_storage, |cache, _| { // cannot register contract with unregistered codeId @@ -1340,7 +1381,9 @@ mod test { let mut wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); + let code_id = wasm_keeper + .store_code(Addr::unchecked("buzz"), None, payout::contract()) + .unwrap(); assert_eq!(1, code_id); let creator = "foobar"; @@ -1383,7 +1426,9 @@ mod test { let wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); + let code_id = wasm_keeper + .store_code(Addr::unchecked("creator"), None, payout::contract()) + .unwrap(); let querier: MockQuerier = MockQuerier::new(&[]); let query = WasmQuery::CodeInfo { code_id }; let code_info = wasm_keeper @@ -1402,8 +1447,12 @@ mod test { let wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id_payout = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); - let code_id_caller = wasm_keeper.store_code(Addr::unchecked("creator"), caller::contract()); + let code_id_payout = wasm_keeper + .store_code(Addr::unchecked("creator"), None, payout::contract()) + .unwrap(); + let code_id_caller = wasm_keeper + .store_code(Addr::unchecked("creator"), None, caller::contract()) + .unwrap(); let querier: MockQuerier = MockQuerier::new(&[]); let query_payout = WasmQuery::CodeInfo { code_id: code_id_payout, @@ -1447,7 +1496,9 @@ mod test { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); + let code_id = wasm_keeper + .store_code(Addr::unchecked("buzz"), None, payout::contract()) + .unwrap(); let mut wasm_storage = MockStorage::new(); @@ -1500,7 +1551,9 @@ mod test { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); + let code_id = wasm_keeper + .store_code(Addr::unchecked("buzz"), None, payout::contract()) + .unwrap(); let mut wasm_storage = MockStorage::new(); let mut cache = StorageTransaction::new(&wasm_storage); @@ -1613,7 +1666,9 @@ mod test { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); + let code_id = wasm_keeper + .store_code(Addr::unchecked("buzz"), None, payout::contract()) + .unwrap(); let mut wasm_storage = MockStorage::new(); @@ -1783,7 +1838,9 @@ mod test { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), caller::contract()); + let code_id = wasm_keeper + .store_code(Addr::unchecked("creator"), None, caller::contract()) + .unwrap(); let mut wasm_storage = MockStorage::new(); @@ -1897,7 +1954,9 @@ mod test { fn uses_simple_address_generator_by_default() { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); + let code_id = wasm_keeper + .store_code(Addr::unchecked("creator"), None, payout::contract()) + .unwrap(); let mut wasm_storage = MockStorage::new(); @@ -1978,7 +2037,9 @@ mod test { address: expected_addr.clone(), predictable_address: expected_predictable_addr.clone(), }); - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); + let code_id = wasm_keeper + .store_code(Addr::unchecked("creator"), None, payout::contract()) + .unwrap(); let mut wasm_storage = MockStorage::new(); diff --git a/tests/test_app_builder/test_with_wasm.rs b/tests/test_app_builder/test_with_wasm.rs index 13f4b05f..e8a26a4b 100644 --- a/tests/test_app_builder/test_with_wasm.rs +++ b/tests/test_app_builder/test_with_wasm.rs @@ -60,8 +60,13 @@ impl Wasm for MyWasmKeeper { bail!(self.3); } - fn store_code(&mut self, _creator: Addr, _code: Box>) -> u64 { - CODE_ID + fn store_code( + &mut self, + _creator: Addr, + _code_id: Option, + _code: Box>, + ) -> AnyResult { + Ok(CODE_ID) } fn duplicate_code(&mut self, _code_id: u64) -> AnyResult { From 3a55cbec3d90f8e6aa5d20bcbc154873b41eeb59 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 19 Dec 2023 17:12:44 +0100 Subject: [PATCH 033/250] Added lacking bank queries. --- src/bank.rs | 55 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/src/bank.rs b/src/bank.rs index 63a6f2ad..d6846c61 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -7,6 +7,8 @@ use cosmwasm_std::{ coin, to_json_binary, Addr, AllBalanceResponse, Api, BalanceResponse, BankMsg, BankQuery, Binary, BlockInfo, Coin, Event, Querier, Storage, }; +#[cfg(feature = "cosmwasm_1_3")] +use cosmwasm_std::{AllDenomMetadataResponse, DenomMetadataResponse}; #[cfg(feature = "cosmwasm_1_1")] use cosmwasm_std::{Order, StdResult, SupplyResponse, Uint128}; use cw_storage_plus::Map; @@ -193,25 +195,7 @@ impl Module for BankKeeper { self.burn(&mut bank_storage, sender, amount)?; Ok(AppResponse::default()) } - _ => unimplemented!("bank message: {msg:?}"), - } - } - - fn sudo( - &self, - api: &dyn Api, - storage: &mut dyn Storage, - _router: &dyn CosmosRouter, - _block: &BlockInfo, - msg: BankSudo, - ) -> AnyResult { - let mut bank_storage = prefixed(storage, NAMESPACE_BANK); - match msg { - BankSudo::Mint { to_address, amount } => { - let to_address = api.addr_validate(&to_address)?; - self.mint(&mut bank_storage, to_address, amount)?; - Ok(AppResponse::default()) - } + other => unimplemented!("bank message: {other:?}"), } } @@ -244,11 +228,38 @@ impl Module for BankKeeper { #[cfg(feature = "cosmwasm_1_1")] BankQuery::Supply { denom } => { let amount = self.get_supply(&bank_storage, denom)?; - let mut res = SupplyResponse::default(); - res.amount = amount; + let res = SupplyResponse::new(amount); + Ok(to_json_binary(&res)?) + } + #[cfg(feature = "cosmwasm_1_3")] + BankQuery::DenomMetadata { denom: _ } => { + let res = DenomMetadataResponse::new(Default::default()); Ok(to_json_binary(&res)?) } - _ => unimplemented!("bank query: {request:?}",), + #[cfg(feature = "cosmwasm_1_3")] + BankQuery::AllDenomMetadata { pagination: _ } => { + let res = AllDenomMetadataResponse::new(Default::default(), None); + Ok(to_json_binary(&res)?) + } + other => bail!("bank query: {other:?}"), + } + } + + fn sudo( + &self, + api: &dyn Api, + storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + msg: BankSudo, + ) -> AnyResult { + let mut bank_storage = prefixed(storage, NAMESPACE_BANK); + match msg { + BankSudo::Mint { to_address, amount } => { + let to_address = api.addr_validate(&to_address)?; + self.mint(&mut bank_storage, to_address, amount)?; + Ok(AppResponse::default()) + } } } } From 182632786b8a196761b7691d0ecbff829885151d Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 8 Jan 2024 11:25:19 +0100 Subject: [PATCH 034/250] Updated dependencies. --- Cargo.lock | 62 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 6 +++--- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29661721..06cb1e8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" dependencies = [ "backtrace", ] @@ -204,9 +204,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -565,15 +565,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.151" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "miniz_oxide" @@ -586,9 +586,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] @@ -617,9 +617,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] @@ -644,14 +644,14 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -733,15 +733,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" dependencies = [ "serde_derive", ] @@ -757,13 +757,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -779,9 +779,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", @@ -857,9 +857,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.41" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -868,22 +868,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.51" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.51" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8e3391f3..9e290a0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ cosmwasm_1_3 = ["cosmwasm_1_2", "cosmwasm-std/cosmwasm_1_3"] cosmwasm_1_4 = ["cosmwasm_1_3", "cosmwasm-std/cosmwasm_1_4"] [dependencies] -anyhow = "1.0.75" +anyhow = "1.0.79" bech32 = "0.9.1" cosmwasm-std = { version = "1.5.0", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "1.2.0" @@ -26,9 +26,9 @@ derivative = "2.2.0" itertools = "0.12.0" prost = "0.12.3" schemars = "0.8.16" -serde = "1.0.193" +serde = "1.0.195" sha2 = "0.10.8" -thiserror = "1.0.50" +thiserror = "1.0.56" [dev-dependencies] hex = "0.4.3" From ce9cb2521fe1974ea1c2ea56b9d2e764d839e088 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 8 Jan 2024 12:55:38 +0100 Subject: [PATCH 035/250] Added storage for denomination metadata. --- src/bank.rs | 108 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 98 insertions(+), 10 deletions(-) diff --git a/src/bank.rs b/src/bank.rs index d6846c61..5796e21b 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -8,7 +8,7 @@ use cosmwasm_std::{ Binary, BlockInfo, Coin, Event, Querier, Storage, }; #[cfg(feature = "cosmwasm_1_3")] -use cosmwasm_std::{AllDenomMetadataResponse, DenomMetadataResponse}; +use cosmwasm_std::{AllDenomMetadataResponse, DenomMetadata, DenomMetadataResponse}; #[cfg(feature = "cosmwasm_1_1")] use cosmwasm_std::{Order, StdResult, SupplyResponse, Uint128}; use cw_storage_plus::Map; @@ -19,6 +19,10 @@ use schemars::JsonSchema; /// Collection of bank balances. const BALANCES: Map<&Addr, NativeBalance> = Map::new("balances"); +/// Collection of metadata for denomination. +#[cfg(feature = "cosmwasm_1_3")] +const DENOM_METADATA: Map = Map::new("metadata"); + /// Default namespace for bank module. pub const NAMESPACE_BANK: &[u8] = b"bank"; @@ -55,7 +59,7 @@ impl BankKeeper { Self::default() } - /// _Admin_ function for adjusting bank accounts in genesis. + /// Administration function for adjusting bank accounts in genesis. pub fn init_balance( &self, storage: &mut dyn Storage, @@ -66,7 +70,7 @@ impl BankKeeper { self.set_balance(&mut bank_storage, account, amount) } - /// _Admin_ function for adjusting bank accounts. + /// Administration function for adjusting bank accounts. fn set_balance( &self, bank_storage: &mut dyn Storage, @@ -80,8 +84,22 @@ impl BankKeeper { .map_err(Into::into) } - fn get_balance(&self, bank_storage: &dyn Storage, account: &Addr) -> AnyResult> { - let val = BALANCES.may_load(bank_storage, account)?; + /// Administration function for adjusting denomination metadata. + #[cfg(feature = "cosmwasm_1_3")] + pub fn set_denom_metadata( + &self, + bank_storage: &mut dyn Storage, + denom: String, + metadata: DenomMetadata, + ) -> AnyResult<()> { + DENOM_METADATA + .save(bank_storage, denom, &metadata) + .map_err(Into::into) + } + + /// Returns balance for specified address. + fn get_balance(&self, bank_storage: &dyn Storage, addr: &Addr) -> AnyResult> { + let val = BALANCES.may_load(bank_storage, addr)?; Ok(val.unwrap_or_default().into_vec()) } @@ -156,8 +174,7 @@ fn coins_to_string(coins: &[Coin]) -> String { .map(|c| format!("{}{}", c.amount, c.denom)) .join(",") } -///This trait defines the interface for simulating banking operations within the testing environment, -/// essential for creating and testing scenarios involving financial transactions and account management in smart contracts. + impl Bank for BankKeeper {} impl Module for BankKeeper { @@ -232,13 +249,18 @@ impl Module for BankKeeper { Ok(to_json_binary(&res)?) } #[cfg(feature = "cosmwasm_1_3")] - BankQuery::DenomMetadata { denom: _ } => { - let res = DenomMetadataResponse::new(Default::default()); + BankQuery::DenomMetadata { denom } => { + let meta = DENOM_METADATA.may_load(storage, denom)?.unwrap_or_default(); + let res = DenomMetadataResponse::new(meta); Ok(to_json_binary(&res)?) } #[cfg(feature = "cosmwasm_1_3")] BankQuery::AllDenomMetadata { pagination: _ } => { - let res = AllDenomMetadataResponse::new(Default::default(), None); + let mut metadata = vec![]; + for key in DENOM_METADATA.keys(storage, None, None, Order::Ascending) { + metadata.push(DENOM_METADATA.may_load(storage, key?)?.unwrap_or_default()); + } + let res = AllDenomMetadataResponse::new(metadata, None); Ok(to_json_binary(&res)?) } other => bail!("bank query: {other:?}"), @@ -488,6 +510,72 @@ mod test { assert!(matches!(err.downcast().unwrap(), StdError::Overflow { .. })); } + #[test] + #[cfg(feature = "cosmwasm_1_3")] + fn set_get_denom_metadata_should_work() { + let api = MockApi::default(); + let mut store = MockStorage::new(); + let block = mock_env().block; + let querier: MockQuerier = MockQuerier::new(&[]); + let bank = BankKeeper::new(); + // set metadata for Ether + let denom_eth_name = "eth".to_string(); + bank.set_denom_metadata( + &mut store, + denom_eth_name.clone(), + DenomMetadata { + name: denom_eth_name.clone(), + ..Default::default() + }, + ) + .unwrap(); + // query metadata + let req = BankQuery::DenomMetadata { + denom: denom_eth_name.clone(), + }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: DenomMetadataResponse = from_json(raw).unwrap(); + assert_eq!(res.metadata.name, denom_eth_name); + } + + #[test] + #[cfg(feature = "cosmwasm_1_3")] + fn set_get_all_denom_metadata_should_work() { + let api = MockApi::default(); + let mut store = MockStorage::new(); + let block = mock_env().block; + let querier: MockQuerier = MockQuerier::new(&[]); + let bank = BankKeeper::new(); + // set metadata for Bitcoin + let denom_btc_name = "btc".to_string(); + bank.set_denom_metadata( + &mut store, + denom_btc_name.clone(), + DenomMetadata { + name: denom_btc_name.clone(), + ..Default::default() + }, + ) + .unwrap(); + // set metadata for Ether + let denom_eth_name = "eth".to_string(); + bank.set_denom_metadata( + &mut store, + denom_eth_name.clone(), + DenomMetadata { + name: denom_eth_name.clone(), + ..Default::default() + }, + ) + .unwrap(); + // query metadata + let req = BankQuery::AllDenomMetadata { pagination: None }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: AllDenomMetadataResponse = from_json(raw).unwrap(); + assert_eq!(res.metadata[0].name, denom_btc_name); + assert_eq!(res.metadata[1].name, denom_eth_name); + } + #[test] fn fail_on_zero_values() { let api = MockApi::default(); From d485eb05a1f4aeb01aed6fdcb02af87cc24159cd Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 8 Jan 2024 14:45:08 +0100 Subject: [PATCH 036/250] Refactoring. --- src/bank.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bank.rs b/src/bank.rs index 5796e21b..860f12ac 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -230,7 +230,7 @@ impl Module for BankKeeper { let address = api.addr_validate(&address)?; let amount = self.get_balance(&bank_storage, &address)?; let res = AllBalanceResponse { amount }; - Ok(to_json_binary(&res)?) + to_json_binary(&res).map_err(Into::into) } BankQuery::Balance { address, denom } => { let address = api.addr_validate(&address)?; @@ -240,19 +240,19 @@ impl Module for BankKeeper { .find(|c| c.denom == denom) .unwrap_or_else(|| coin(0, denom)); let res = BalanceResponse { amount }; - Ok(to_json_binary(&res)?) + to_json_binary(&res).map_err(Into::into) } #[cfg(feature = "cosmwasm_1_1")] BankQuery::Supply { denom } => { let amount = self.get_supply(&bank_storage, denom)?; let res = SupplyResponse::new(amount); - Ok(to_json_binary(&res)?) + to_json_binary(&res).map_err(Into::into) } #[cfg(feature = "cosmwasm_1_3")] BankQuery::DenomMetadata { denom } => { let meta = DENOM_METADATA.may_load(storage, denom)?.unwrap_or_default(); let res = DenomMetadataResponse::new(meta); - Ok(to_json_binary(&res)?) + to_json_binary(&res).map_err(Into::into) } #[cfg(feature = "cosmwasm_1_3")] BankQuery::AllDenomMetadata { pagination: _ } => { @@ -261,9 +261,9 @@ impl Module for BankKeeper { metadata.push(DENOM_METADATA.may_load(storage, key?)?.unwrap_or_default()); } let res = AllDenomMetadataResponse::new(metadata, None); - Ok(to_json_binary(&res)?) + to_json_binary(&res).map_err(Into::into) } - other => bail!("bank query: {other:?}"), + other => unimplemented!("bank query: {other:?}"), } } From 8c6a1ced2bf995ac51ca304a16f4f20ecec439bd Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 26 Jan 2024 12:21:15 +0100 Subject: [PATCH 037/250] Removed wrong dependency. --- Cargo.lock | 70 ++++++++++++++++-------------------------------------- Cargo.toml | 1 - src/lib.rs | 4 ++-- 3 files changed, 22 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 06cb1e8f..32d8219d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,9 +60,9 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.21.5" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64ct" @@ -135,9 +135,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-crypto" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8bb3c77c3b7ce472056968c745eb501c440fbc07be5004eba02782c35bfbbe3" +checksum = "8ed6aa9f904de106fa16443ad14ec2abe75e94ba003bb61c681c0e43d4c58d2a" dependencies = [ "digest 0.10.7", "ecdsa", @@ -149,18 +149,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea73e9162e6efde00018d55ed0061e93a108b5d6ec4548b4f8ce3c706249687" +checksum = "40abec852f3d4abec6d44ead9a58b78325021a1ead1e7229c3471414e57b2e49" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0df41ea55f2946b6b43579659eec048cc2f66e8c8e2e3652fc5e5e476f673856" +checksum = "b166215fbfe93dc5575bae062aa57ae7bb41121cffe53bac33b033257949d2a9" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -171,9 +171,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43609e92ce1b9368aa951b334dd354a2d0dd4d484931a5f83ae10e12a26c8ba9" +checksum = "8bf12f8e20bb29d1db66b7ca590bc2f670b548d21e9be92499bc0f9022a994a8" dependencies = [ "proc-macro2", "quote", @@ -182,9 +182,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d6864742e3a7662d024b51a94ea81c9af21db6faea2f9a6d2232bb97c6e53e" +checksum = "ad011ae7447188e26e4a7dbca2fcd0fc186aa21ae5c86df0503ea44c78f9e469" dependencies = [ "base64", "bech32", @@ -255,7 +255,6 @@ dependencies = [ "cosmwasm-std", "cw-storage-plus", "cw-utils", - "cw1-whitelist", "derivative", "hex", "hex-literal", @@ -294,35 +293,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "cw1" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1605722190afd93bfea6384b88224d1cfe50ebf70d2e10641535da79fa70e83" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "schemars", - "serde", -] - -[[package]] -name = "cw1-whitelist" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bb3e9dc87f4ff26547f4e27e0ba3c82034372f21b2f55527fb52b542637d8d" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus", - "cw-utils", - "cw1", - "cw2", - "schemars", - "serde", - "thiserror", -] - [[package]] name = "cw2" version = "1.1.2" @@ -469,9 +439,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -551,9 +521,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "k256" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f01b677d82ef7a676aa37e099defd83a28e15687112cafdd112d60236b6115b" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" dependencies = [ "cfg-if", "ecdsa", @@ -617,9 +587,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.76" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -748,9 +718,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16a62a1fad1e1828b24acac8f2b468971dade7b8c3c2e672bcadefefb1f8c137" +checksum = "9e9213a07d53faa0b8dd81e767a54a8188a242fdb9be99ab75ec576a774bfdd7" dependencies = [ "serde", ] diff --git a/Cargo.toml b/Cargo.toml index 9e290a0d..d47938c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,4 +34,3 @@ thiserror = "1.0.56" hex = "0.4.3" hex-literal = "0.4.1" once_cell = "1.19.0" -cw1-whitelist = "1.1.2" diff --git a/src/lib.rs b/src/lib.rs index ea0bdcb6..32121e25 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,7 +80,7 @@ //! for some examples or how to do so (and useful mocks for some test cases). //! Here is an example of wrapping a CosmWasm contract into a [Contract] trait to be added to an [App]: //! -//! ``` +//! ```ignore //! use cosmwasm_std::Empty; //! use cw1_whitelist::contract::{execute, instantiate, query}; //! use cw_multi_test::{App, Contract, ContractWrapper}; @@ -99,7 +99,7 @@ //! There is only one root [Storage](cosmwasm_std::Storage), stored inside [App]. //! This is wrapped into a transaction, and then passed down to other functions to work with. //! The code that modifies the Storage is divided into _modules_ much like the CosmosSDK. -//! Currently the message processing logic is divided into one _module_ for every [CosmosMsg](cosmwasm_std) variant. +//! Currently, the message processing logic is divided into one _module_ for every [CosmosMsg](cosmwasm_std) variant. //! [Bank] handles [BankMsg](cosmwasm_std::BankMsg) and [BankQuery](cosmwasm_std::BankQuery), //! [Wasm] handles [WasmMsg](cosmwasm_std::WasmMsg) and [WasmQuery](cosmwasm_std::WasmQuery), etc. //! From abd988e050088b0a62b68e070576010a320e8b09 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 26 Jan 2024 13:33:38 +0100 Subject: [PATCH 038/250] Transformed startgate trait to module. --- src/app.rs | 36 ++--- src/app_builder.rs | 16 +-- src/lib.rs | 4 +- src/staking.rs | 10 +- src/stargate.rs | 127 +++++------------- src/tests/test_stargate.rs | 10 +- src/wasm.rs | 6 +- .../test_with_distribution.rs | 6 +- tests/test_app_builder/test_with_stargate.rs | 66 +++------ 9 files changed, 93 insertions(+), 188 deletions(-) diff --git a/src/app.rs b/src/app.rs index 77d1f026..ad035b39 100644 --- a/src/app.rs +++ b/src/app.rs @@ -6,7 +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::{Stargate, StargateFailing}; +use crate::stargate::{Stargate, StargateFailingModule, StargateMsg, StargateQuery}; use crate::transactions::transactional; use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; use crate::{AppBuilder, GovFailingModule, IbcFailingModule}; @@ -39,7 +39,7 @@ pub type BasicApp = App< DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailing, + StargateFailingModule, >; /// # Blockchain application simulator @@ -56,7 +56,7 @@ pub struct App< Distr = DistributionKeeper, Ibc = IbcFailingModule, Gov = GovFailingModule, - Stargate = StargateFailing, + Stargate = StargateFailingModule, > { pub(crate) router: Router, pub(crate) api: Api, @@ -92,7 +92,7 @@ impl BasicApp { DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailing, + StargateFailingModule, >, &dyn Api, &mut dyn Storage, @@ -103,7 +103,7 @@ impl BasicApp { } /// Creates new default `App` implementation working with customized exec and query messages. -/// Outside of `App` implementation to make type elision better. +/// Outside the `App` implementation to make type elision better. pub fn custom_app(init_fn: F) -> BasicApp where ExecC: CustomMsg + DeserializeOwned + 'static, @@ -117,7 +117,7 @@ where DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailing, + StargateFailingModule, >, &dyn Api, &mut dyn Storage, @@ -376,7 +376,7 @@ where } /// Simple helper so we get access to all the QuerierWrapper helpers, - /// eg. wrap().query_wasm_smart, query_all_balances, ... + /// e.g. wrap().query_wasm_smart, query_all_balances, ... pub fn wrap(&self) -> QuerierWrapper { QuerierWrapper::new(self) } @@ -535,7 +535,7 @@ impl From for SudoMsg { /// A trait representing the Cosmos based chain's router. /// /// This trait is designed for routing messages within the Cosmos ecosystem. -/// It is key to ensuring that transactions and contract calls are directed to the +/// It is key to ensure that transactions and contract calls are directed to the /// correct destinations during testing, simulating real-world blockchain operations. pub trait CosmosRouter { /// Type of the executed custom message. @@ -607,14 +607,19 @@ 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, type_url, value), + CosmosMsg::Stargate { type_url, value } => self.stargate.execute( + api, + storage, + self, + block, + sender, + StargateMsg { type_url, value }, + ), _ => bail!("Cannot execute {:?}", msg), } } - /// this is used by `RouterQuerier` to actual implement the `Querier` interface. + /// 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 fn query( @@ -631,9 +636,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, path, data), + 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 e8b3d9db..46de71a3 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -2,8 +2,8 @@ use crate::{ App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingModule, Gov, GovFailingModule, - Ibc, IbcFailingModule, Module, Router, StakeKeeper, Staking, Stargate, StargateFailing, Wasm, - WasmKeeper, + Ibc, IbcFailingModule, Module, Router, StakeKeeper, Staking, Stargate, StargateFailingModule, + Wasm, WasmKeeper, }; use cosmwasm_std::testing::{mock_env, MockApi, MockStorage}; use cosmwasm_std::{Api, BlockInfo, CustomMsg, CustomQuery, Empty, Storage}; @@ -38,7 +38,7 @@ pub type BasicAppBuilder = AppBuilder< DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailing, + StargateFailingModule, >; /// Utility to build [App] in stages. @@ -68,7 +68,7 @@ impl Default DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailing, + StargateFailingModule, > { fn default() -> Self { @@ -87,7 +87,7 @@ impl DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailing, + StargateFailingModule, > { /// Creates builder with default components working with empty exec and query messages. @@ -103,7 +103,7 @@ impl distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), - stargate: StargateFailing, + stargate: StargateFailingModule::new(), } } } @@ -119,7 +119,7 @@ impl DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailing, + StargateFailingModule, > where ExecC: CustomMsg + DeserializeOwned + 'static, @@ -139,7 +139,7 @@ where distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), - stargate: StargateFailing, + stargate: StargateFailingModule::new(), } } } diff --git a/src/lib.rs b/src/lib.rs index 32121e25..9a6becda 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -160,5 +160,7 @@ pub use crate::module::{AcceptingModule, FailingModule, Module}; pub use crate::staking::{ Distribution, DistributionKeeper, StakeKeeper, Staking, StakingInfo, StakingSudo, }; -pub use crate::stargate::{Stargate, StargateAccepting, StargateFailing}; +pub use crate::stargate::{ + Stargate, StargateAcceptingModule, StargateFailingModule, StargateMsg, StargateQuery, +}; pub use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; diff --git a/src/staking.rs b/src/staking.rs index 8e11e569..9d8166fa 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -282,7 +282,7 @@ impl StakeKeeper { } /// Updates the staking reward for the given validator and their stakers - /// It saves the validator info and it's stakers, so make sure not to overwrite that. + /// It saves the validator info and stakers, so make sure not to overwrite that. /// Always call this to update rewards before changing anything that influences future rewards. fn update_rewards( api: &dyn Api, @@ -915,7 +915,7 @@ impl DistributionKeeper { Ok(rewards) } - /// Returns the withdraw address for specified delegator. + /// Returns the withdrawal address for specified delegator. pub fn get_withdraw_address(storage: &dyn Storage, delegator: &Addr) -> AnyResult { Ok(match WITHDRAW_ADDRESS.may_load(storage, delegator)? { Some(a) => a, @@ -1036,7 +1036,7 @@ impl Module for DistributionKeeper { #[cfg(test)] mod test { use super::*; - use crate::stargate::StargateFailing; + use crate::stargate::StargateFailingModule; use crate::{ app::MockRouter, BankKeeper, FailingModule, GovFailingModule, IbcFailingModule, Router, WasmKeeper, @@ -1056,7 +1056,7 @@ mod test { DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailing, + StargateFailingModule, >; fn mock_router() -> BasicRouter { @@ -1068,7 +1068,7 @@ mod test { distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), - stargate: StargateFailing, + stargate: StargateFailingModule::new(), } } diff --git a/src/stargate.rs b/src/stargate.rs index a91dc89d..774aa67f 100644 --- a/src/stargate.rs +++ b/src/stargate.rs @@ -1,104 +1,39 @@ -use crate::error::AnyResult; -use crate::{AppResponse, CosmosRouter}; -use anyhow::bail; -use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomMsg, CustomQuery, Querier, Storage}; -use serde::de::DeserializeOwned; +use crate::{AcceptingModule, FailingModule, Module}; +use cosmwasm_std::{Binary, Empty}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; -/// Stargate interface. -/// -/// This trait provides the default behavior for all functions -/// that is equal to [StargateFailing] implementation. -pub trait Stargate { - /// Processes stargate messages. - /// - /// The `CosmosMsg::Stargate` message is unwrapped before processing. - /// The `type_url` and `value` attributes of `CosmosMsg::Stargate` - /// are passed directly to this handler. - fn execute( - &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, - { - let _ = (api, storage, router, block); - bail!( - "Unexpected stargate message: (type_ur = {}, value = {:?}) from {:?}", - type_url, - value, - sender - ) - } +/// Placeholder for stargate message attributes. +#[non_exhaustive] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct StargateMsg { + /// Stargate message type. + pub type_url: String, + /// Stargate message body. + pub value: Binary, +} - /// Processes stargate queries. - /// - /// The `QueryRequest::Stargate` query request is unwrapped before processing. - /// The `path` and `data` attributes of `QueryRequest::Stargate` are passed - /// directly to this handler. - fn query( - &self, - api: &dyn Api, - storage: &dyn Storage, - querier: &dyn Querier, - block: &BlockInfo, - path: String, - data: Binary, - ) -> AnyResult { - let _ = (api, storage, querier, block); - bail!( - "Unexpected stargate query: path = {:?}, data = {:?}", - path, - data - ) - } +/// Placeholder for stargate query attributes. +#[non_exhaustive] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct StargateQuery { + /// Fully qualified service path used for routing, e.g. custom/cosmos_sdk.x.bank.v1.Query/QueryBalance. + pub path: String, + /// Expected protobuf message type (not any), binary encoded. + pub data: Binary, } -/// Always failing stargate mock implementation. -pub struct StargateFailing; +/// Interface to module handling stargate messages and queries. +pub trait Stargate: Module {} -impl Stargate for StargateFailing {} +/// Always accepting stargate module. +pub type StargateAcceptingModule = AcceptingModule; -/// Always accepting stargate mock implementation. -pub struct StargateAccepting; +impl Stargate for StargateAcceptingModule {} -impl Stargate for StargateAccepting { - /// Accepts all stargate messages. Returns default `AppResponse`. - fn execute( - &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, - { - let _ = (api, storage, router, block, sender, type_url, value); - Ok(AppResponse::default()) - } +/// Always accepting stargate module. +pub type StargateFailingModule = FailingModule; - /// Accepts all stargate queries. Returns default `Binary`. - fn query( - &self, - api: &dyn Api, - storage: &dyn Storage, - querier: &dyn Querier, - block: &BlockInfo, - path: String, - data: Binary, - ) -> AnyResult { - let _ = (api, storage, querier, block, path, data); - Ok(Binary::default()) - } -} +impl Stargate for StargateFailingModule {} diff --git a/src/tests/test_stargate.rs b/src/tests/test_stargate.rs index 92fcb69c..1f2c77db 100644 --- a/src/tests/test_stargate.rs +++ b/src/tests/test_stargate.rs @@ -1,9 +1,9 @@ use crate::test_helpers::stargate; -use crate::{no_init, App, AppBuilder, Executor, StargateAccepting}; +use crate::{no_init, App, AppBuilder, Executor, StargateAcceptingModule}; use cosmwasm_std::Empty; #[test] -fn default_stargate() { +fn default_failing_stargate_module_should_work() { let mut app = App::default(); // store the contract @@ -27,13 +27,13 @@ fn default_stargate() { .source() .unwrap() .to_string() - .starts_with("Unexpected stargate message")); + .starts_with("Unexpected exec msg StargateMsg")); } #[test] -fn accepting_stargate() { +fn accepting_stargate_module_should_work() { let mut app = AppBuilder::default() - .with_stargate(StargateAccepting) + .with_stargate(StargateAcceptingModule::new()) .build(no_init); // store the contract diff --git a/src/wasm.rs b/src/wasm.rs index 9e313c90..e7b987da 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1201,7 +1201,7 @@ mod test { use crate::bank::BankKeeper; use crate::module::FailingModule; use crate::staking::{DistributionKeeper, StakeKeeper}; - use crate::stargate::StargateFailing; + use crate::stargate::StargateFailingModule; use crate::test_helpers::{caller, error, payout}; use crate::transactions::StorageTransaction; use crate::{GovFailingModule, IbcFailingModule}; @@ -1220,7 +1220,7 @@ mod test { DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailing, + StargateFailingModule, >; fn wasm_keeper() -> WasmKeeper { @@ -1236,7 +1236,7 @@ mod test { distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), - stargate: StargateFailing, + stargate: StargateFailingModule::new(), } } diff --git a/tests/test_app_builder/test_with_distribution.rs b/tests/test_app_builder/test_with_distribution.rs index 9a27f582..23139ec7 100644 --- a/tests/test_app_builder/test_with_distribution.rs +++ b/tests/test_app_builder/test_with_distribution.rs @@ -7,13 +7,11 @@ type MyDistributionKeeper = MyKeeper; impl Distribution for MyDistributionKeeper {} const EXECUTE_MSG: &str = "distribution execute called"; -/// Manages the distribution aspects within tests, simulating scenarios ] -/// like reward distribution or token allocation. This trait is important -/// for contracts that involve distributing assets in a certain way. + #[test] fn building_app_with_custom_distribution_should_work() { // build custom distribution keeper - // distribution keeper has no query or sudo messages + // which has no query or sudo messages let distribution_keeper = MyDistributionKeeper::new(EXECUTE_MSG, NO_MESSAGE, NO_MESSAGE); // build the application with custom distribution keeper diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index 65771bd2..c068abb7 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -1,61 +1,21 @@ -use anyhow::bail; -use cosmwasm_std::{ - to_json_vec, Addr, Api, Binary, BlockInfo, CosmosMsg, CustomMsg, CustomQuery, Empty, Querier, - QueryRequest, Storage, -}; -use cw_multi_test::error::AnyResult; +use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; +use cosmwasm_std::{to_json_vec, Addr, CosmosMsg, Empty, QueryRequest}; use cw_multi_test::{ - no_init, AppBuilder, AppResponse, CosmosRouter, Executor, Stargate, StargateAccepting, - StargateFailing, + no_init, AppBuilder, Executor, Stargate, StargateAcceptingModule, StargateFailingModule, + StargateMsg, StargateQuery, }; -use serde::de::DeserializeOwned; - -const EXECUTE_MSG: &str = "stargate execute called"; -const QUERY_MSG: &str = "stargate query called"; -struct MyStargateKeeper; +type MyStargateKeeper = MyKeeper; -impl Stargate for MyStargateKeeper { - /// Custom processing of stargate messages. - fn execute( - &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, - { - assert_eq!("test", type_url); - assert_eq!(Binary::default(), value); - bail!(EXECUTE_MSG); - } +impl Stargate for MyStargateKeeper {} - /// Custom stargate queries. - fn query( - &self, - _api: &dyn Api, - _storage: &dyn Storage, - _querier: &dyn Querier, - _block: &BlockInfo, - path: String, - data: Binary, - ) -> AnyResult { - assert_eq!("test", path); - assert_eq!(Binary::default(), data); - bail!(QUERY_MSG); - } -} +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 - let stargate_keeper = MyStargateKeeper; + let stargate_keeper = MyStargateKeeper::new(EXECUTE_MSG, QUERY_MSG, NO_MESSAGE); // build the application with custom stargate keeper let app_builder = AppBuilder::default(); @@ -94,7 +54,9 @@ fn building_app_with_custom_stargate_should_work() { #[test] fn building_app_with_accepting_stargate_should_work() { let app_builder = AppBuilder::default(); - let mut app = app_builder.with_stargate(StargateAccepting).build(no_init); + let mut app = app_builder + .with_stargate(StargateAcceptingModule::new()) + .build(no_init); app.execute( Addr::unchecked("sender"), @@ -117,7 +79,9 @@ fn building_app_with_accepting_stargate_should_work() { #[test] fn building_app_with_failing_stargate_should_work() { let app_builder = AppBuilder::default(); - let mut app = app_builder.with_stargate(StargateFailing).build(no_init); + let mut app = app_builder + .with_stargate(StargateFailingModule::new()) + .build(no_init); app.execute( Addr::unchecked("sender"), From 29055e86531f8ab315cc72ca22beb639f4c57f7b Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 26 Jan 2024 18:15:52 +0100 Subject: [PATCH 039/250] Improved simple address generator. --- src/addresses.rs | 22 ++++++++++++---------- src/tests/test_app.rs | 2 +- src/wasm.rs | 28 ++++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/addresses.rs b/src/addresses.rs index bf918313..dd416180 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -98,30 +98,32 @@ pub trait AddressGenerator { /// /// let my_address_generator = MyAddressGenerator{}; /// - /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 100, 0, &[0], &creator, &[0]).unwrap(); - /// assert_eq!(addr.to_string(),"contract00"); + /// let salt = [0xc0,0xff,0xee]; + /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 100, 0, &[0], &creator, &salt).unwrap(); + /// assert_eq!(addr.to_string(),"contract0c0ffee"); /// - /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 100, 1, &[1], &creator, &[0]).unwrap(); - /// assert_eq!(addr.to_string(),"contract00"); + /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 100, 1, &[1], &creator, &salt).unwrap(); + /// assert_eq!(addr.to_string(),"contract1c0ffee"); /// - /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 200, 0, &[2], &creator, &[1]).unwrap(); - /// assert_eq!(addr.to_string(),"contract01"); + /// let salt = [0xbe,0xef]; + /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 200, 0, &[2], &creator, &salt).unwrap(); + /// assert_eq!(addr.to_string(),"contract0beef"); /// - /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 200, 1, &[3], &creator, &[1]).unwrap(); - /// assert_eq!(addr.to_string(),"contract01"); + /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 200, 1, &[3], &creator, &salt).unwrap(); + /// assert_eq!(addr.to_string(),"contract1beef"); /// ``` fn predictable_contract_address( &self, _api: &dyn Api, _storage: &mut dyn Storage, _code_id: u64, - _instance_id: u64, + instance_id: u64, _checksum: &[u8], _creator: &CanonicalAddr, salt: &[u8], ) -> AnyResult { Ok(Addr::unchecked(format!( - "contract{}", + "contract{instance_id}{}", HexBinary::from(salt).to_hex() ))) } diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 46f33db2..4504cdb9 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -1585,7 +1585,7 @@ mod contract_instantiation { // assert contract's address is exactly the predicted one, // in default address generator, this is like `contract` + salt in hex - assert_eq!(parsed.contract_address, "contract010203040506"); + assert_eq!(parsed.contract_address, "contract0010203040506"); } } diff --git a/src/wasm.rs b/src/wasm.rs index e7b987da..ab48227a 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1898,6 +1898,7 @@ mod test { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); + assert_eq!(1, code_id); let mut wasm_storage = MockStorage::new(); @@ -1928,12 +1929,35 @@ mod test { Addr::unchecked("admin"), "label".to_owned(), 1000, - Binary::from(HexBinary::from_hex("01C0FFEE").unwrap()), + Binary::from(HexBinary::from_hex("C0FFEE").unwrap()), + ) + .unwrap(); + + assert_eq!( + contract_addr, "contract1c0ffee", + "default address generator returned incorrect address" + ); + + // this part + + let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); + assert_eq!(2, code_id); + + let contract_addr = wasm_keeper + .register_contract( + &api, + &mut wasm_storage, + code_id, + Addr::unchecked("foobar"), + Addr::unchecked("admin"), + "label".to_owned(), + 1000, + Binary::from(HexBinary::from_hex("C0FFEE").unwrap()), ) .unwrap(); assert_eq!( - contract_addr, "contract01c0ffee", + contract_addr, "contract2c0ffee", "default address generator returned incorrect address" ); } From 212b70eb9cf4193981c900d721d4504cddb1f79a Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 29 Jan 2024 15:43:03 +0100 Subject: [PATCH 040/250] Added tests. --- Cargo.lock | 12 ++-- Cargo.toml | 4 +- tests/test_app/test_instantiate2.rs | 101 ++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 32d8219d..4173657e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -709,9 +709,9 @@ checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.195" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] @@ -727,9 +727,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", @@ -749,9 +749,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" dependencies = [ "itoa", "ryu", diff --git a/Cargo.toml b/Cargo.toml index d47938c1..22f97897 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,14 +19,14 @@ cosmwasm_1_4 = ["cosmwasm_1_3", "cosmwasm-std/cosmwasm_1_4"] [dependencies] anyhow = "1.0.79" bech32 = "0.9.1" -cosmwasm-std = { version = "1.5.0", features = ["iterator", "staking", "stargate"] } +cosmwasm-std = { version = "1.5.2", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "1.2.0" cw-utils = "1.0.3" derivative = "2.2.0" itertools = "0.12.0" prost = "0.12.3" schemars = "0.8.16" -serde = "1.0.195" +serde = "1.0.196" sha2 = "0.10.8" thiserror = "1.0.56" diff --git a/tests/test_app/test_instantiate2.rs b/tests/test_app/test_instantiate2.rs index 13cc8d34..cec92ad6 100644 --- a/tests/test_app/test_instantiate2.rs +++ b/tests/test_app/test_instantiate2.rs @@ -70,3 +70,104 @@ fn instantiate2_works() { // check if the predictable contract's address matches the result from instantiate2_address function assert_eq!(parsed.contract_address, contract_human_addr.to_string()); } + +#[test] +fn instantiate2_should_work_for_multiple_salts() { + // prepare the application with custom Api and custom address generator + let mut app = AppBuilder::default() + .with_api(MockApiBech32::new("juno")) + .with_wasm(WasmKeeper::default().with_address_generator(MockAddressGenerator)) + .build(no_init); + + // prepare addresses for sender and creator + let sender = app.api().addr_make("sender"); + let creator = app.api().addr_make("creator"); + + // store the contract's code + let code_id = app.store_code_with_creator(creator, counter::contract()); + + let mut f = |salt: &str| { + // instantiate the contract with predictable address and provided salt, sender is the same + let msg = WasmMsg::Instantiate2 { + admin: None, + code_id, + msg: to_json_binary(&Empty {}).unwrap(), + funds: vec![], + label: "label".into(), + salt: salt.as_bytes().into(), + }; + let res = app.execute(sender.clone(), msg.into()).unwrap(); + let parsed = parse_instantiate_response_data(res.data.unwrap().as_slice()).unwrap(); + parsed.contract_address + }; + + // make sure, addresses generated for different salts are different + assert_ne!(f("bad kids 1"), f("bad kids 2")) +} + +#[test] +fn instantiate2_fails_for_duplicated_addresses() { + // prepare the application with custom Api and custom address generator + let mut app = AppBuilder::default() + .with_api(MockApiBech32::new("osmo")) + .with_wasm(WasmKeeper::default().with_address_generator(MockAddressGenerator)) + .build(no_init); + + // prepare addresses for sender and creator + let sender = app.api().addr_make("sender"); + let creator = app.api().addr_make("creator"); + + // store the contract's code + let code_id = app.store_code_with_creator(creator, counter::contract()); + + // prepare the salt for predictable address + let salt = "bad kids".as_bytes(); + + // instantiate the contract with predictable address + let init_msg = to_json_binary(&Empty {}).unwrap(); + let msg = WasmMsg::Instantiate2 { + admin: None, + code_id, + msg: init_msg, + funds: vec![], + label: "label".into(), + salt: salt.into(), + }; + let res = app.execute(sender.clone(), msg.clone().into()).unwrap(); + + // check the instantiate result + let parsed = parse_instantiate_response_data(res.data.unwrap().as_slice()).unwrap(); + assert!(parsed.data.is_none()); + + // check the resulting predictable contract's address + assert_eq!( + parsed.contract_address, + "osmo1navvz5rjlvn43xjqxlpl7dunk6hglmhuh7c6a53eq6qamfam3dusg94p04" + ); + + // creating a new instance of the same contract with the same sender and salt + // should fail because the generated contract address is the same + app.execute(sender.clone(), msg.into()).unwrap_err(); + + // ---------------------------------------------------------------------- + // Below is an additional check, proving that the predictable address + // from contract instantiation is exactly the same when used with the + // cosmwasm_std::instantiate2_address twice (same sender and salt). + // ---------------------------------------------------------------------- + + // get the code info of the contract + let code_info_response = app.wrap().query_wasm_code_info(code_id).unwrap(); + + // retrieve the contract's code checksum + let checksum = code_info_response.checksum.as_slice(); + + // canonicalize the sender address (which is now in human Bech32 format) + let sender_addr = app.api().addr_canonicalize(sender.as_str()).unwrap(); + + // get the contract address using cosmwasm_std::instantiate2_address function twice + let contract_addr_1 = instantiate2_address(checksum, &sender_addr, salt).unwrap(); + let contract_addr_2 = instantiate2_address(checksum, &sender_addr, salt).unwrap(); + + // contract addresses should be the same + assert_eq!(contract_addr_1, contract_addr_2); +} From 25061418035781d73a2c77f4df982d0162f8e16f Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 29 Jan 2024 16:29:30 +0100 Subject: [PATCH 041/250] Based address generation on creator address and salt. --- src/addresses.rs | 39 +++++++++++++++++++++------------------ src/tests/test_app.rs | 13 +++++++++++-- src/wasm.rs | 24 +++++++++++++++++------- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/addresses.rs b/src/addresses.rs index dd416180..50c5fb67 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -81,7 +81,8 @@ pub trait AddressGenerator { /// Address generated by this function is returned as a result of processing /// `WasmMsg::Instantiate2` message. /// - /// The default implementation generates a contract address based on provided salt only. + /// The default implementation generates a contract address based on provided + /// creator address and salt. /// /// # Example /// @@ -91,39 +92,41 @@ pub trait AddressGenerator { /// # use cw_multi_test::{AddressGenerator, SimpleAddressGenerator}; /// # let api = MockApi::default(); /// # let mut storage = MockStorage::default(); - /// # let creator = api.addr_canonicalize("creator").unwrap(); /// struct MyAddressGenerator; /// /// impl AddressGenerator for MyAddressGenerator {} /// /// let my_address_generator = MyAddressGenerator{}; /// - /// let salt = [0xc0,0xff,0xee]; - /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 100, 0, &[0], &creator, &salt).unwrap(); - /// assert_eq!(addr.to_string(),"contract0c0ffee"); - /// - /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 100, 1, &[1], &creator, &salt).unwrap(); - /// assert_eq!(addr.to_string(),"contract1c0ffee"); - /// - /// let salt = [0xbe,0xef]; - /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 200, 0, &[2], &creator, &salt).unwrap(); - /// assert_eq!(addr.to_string(),"contract0beef"); - /// - /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 200, 1, &[3], &creator, &salt).unwrap(); - /// assert_eq!(addr.to_string(),"contract1beef"); + /// let creator1 = api.addr_canonicalize("creator1").unwrap(); + /// let creator2 = api.addr_canonicalize("creator2").unwrap(); + /// let salt1 = [0xc0,0xff,0xee]; + /// let salt2 = [0xbe,0xef]; + /// + /// let addr11 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, &[1], &creator1, &salt1).unwrap(); + /// let addr12 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, &[1], &creator1, &salt2).unwrap(); + /// let addr21 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, &[1], &creator2, &salt1).unwrap(); + /// let addr22 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, &[1], &creator2, &salt2).unwrap(); + /// + /// assert_ne!(addr11, addr12); + /// assert_ne!(addr11, addr21); + /// assert_ne!(addr11, addr22); + /// assert_ne!(addr12, addr21); + /// assert_ne!(addr12, addr22); + /// assert_ne!(addr21, addr22); /// ``` fn predictable_contract_address( &self, _api: &dyn Api, _storage: &mut dyn Storage, _code_id: u64, - instance_id: u64, + _instance_id: u64, _checksum: &[u8], - _creator: &CanonicalAddr, + creator: &CanonicalAddr, salt: &[u8], ) -> AnyResult { Ok(Addr::unchecked(format!( - "contract{instance_id}{}", + "contract{creator}{}", HexBinary::from(salt).to_hex() ))) } diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 4504cdb9..58ae2924 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -1555,6 +1555,7 @@ mod response_validation { } mod contract_instantiation { + #[test] #[cfg(feature = "cosmwasm_1_2")] fn instantiate2_works() { @@ -1569,13 +1570,14 @@ mod contract_instantiation { // initialize the contract let init_msg = to_json_binary(&Empty {}).unwrap(); + let salt = cosmwasm_std::HexBinary::from_hex("010203040506").unwrap(); let msg = WasmMsg::Instantiate2 { admin: None, code_id, msg: init_msg, funds: vec![], label: "label".into(), - salt: [1, 2, 3, 4, 5, 6].as_slice().into(), + salt: salt.clone().into(), }; let res = app.execute(sender, msg.into()).unwrap(); @@ -1585,7 +1587,14 @@ mod contract_instantiation { // assert contract's address is exactly the predicted one, // in default address generator, this is like `contract` + salt in hex - assert_eq!(parsed.contract_address, "contract0010203040506"); + assert_eq!( + parsed.contract_address, + format!( + "contract{}{}", + app.api().addr_canonicalize("sender").unwrap(), + salt.to_hex() + ), + ); } } diff --git a/src/wasm.rs b/src/wasm.rs index ab48227a..dac40c86 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1920,6 +1920,8 @@ mod test { "default address generator returned incorrect address" ); + let salt = HexBinary::from_hex("c0ffee").unwrap(); + let contract_addr = wasm_keeper .register_contract( &api, @@ -1929,17 +1931,20 @@ mod test { Addr::unchecked("admin"), "label".to_owned(), 1000, - Binary::from(HexBinary::from_hex("C0FFEE").unwrap()), + Binary::from(salt.clone()), ) .unwrap(); assert_eq!( - contract_addr, "contract1c0ffee", + contract_addr, + format!( + "contract{}{}", + api.addr_canonicalize("foobar").unwrap(), + salt.to_hex() + ), "default address generator returned incorrect address" ); - // this part - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); assert_eq!(2, code_id); @@ -1948,16 +1953,21 @@ mod test { &api, &mut wasm_storage, code_id, - Addr::unchecked("foobar"), + Addr::unchecked("boobaz"), Addr::unchecked("admin"), "label".to_owned(), 1000, - Binary::from(HexBinary::from_hex("C0FFEE").unwrap()), + Binary::from(salt.clone()), ) .unwrap(); assert_eq!( - contract_addr, "contract2c0ffee", + contract_addr, + format!( + "contract{}{}", + api.addr_canonicalize("boobaz").unwrap(), + salt.to_hex() + ), "default address generator returned incorrect address" ); } From 4b597769dd7aaf9d8a240bf5dba65490436d31d3 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 7 Feb 2024 11:05:38 +0100 Subject: [PATCH 042/250] Upgraded dependencies. --- Cargo.lock | 74 ++++++++++++++++++------------------------------------ Cargo.toml | 11 ++++---- 2 files changed, 31 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4173657e..0c000bf1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "bnum" -version = "0.8.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab9008b6bb9fc80b5277f2fe481c09e828743d9151203e804583eb4c9e15b31d" +checksum = "56953345e39537a3e18bdaeba4cb0c58a78c1f61f361dc0fa7c5c7340ae87c5f" [[package]] name = "byteorder" @@ -135,12 +135,11 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-crypto" -version = "1.5.2" +version = "2.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ed6aa9f904de106fa16443ad14ec2abe75e94ba003bb61c681c0e43d4c58d2a" +checksum = "07faab121b507bf68d49ff847d517823947d9aece93fcb951ac1d33a8b3a7910" dependencies = [ "digest 0.10.7", - "ecdsa", "ed25519-zebra", "k256", "rand_core 0.6.4", @@ -149,18 +148,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.5.2" +version = "2.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40abec852f3d4abec6d44ead9a58b78325021a1ead1e7229c3471414e57b2e49" +checksum = "29db670d3578a661b7c8ac6591c5cd422363d6d0517744211bc31131c602355a" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "1.5.2" +version = "2.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b166215fbfe93dc5575bae062aa57ae7bb41121cffe53bac33b033257949d2a9" +checksum = "df0cf9c873ae321836f0781f8f9e135862d6ccc9fd563bfaebec42990fa7315c" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -171,9 +170,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.5.2" +version = "2.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf12f8e20bb29d1db66b7ca590bc2f670b548d21e9be92499bc0f9022a994a8" +checksum = "c8c5a8183b78c6749908ee1f4582cb11d6dbab15cca9ccf894722c13e63b73fd" dependencies = [ "proc-macro2", "quote", @@ -182,9 +181,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.5.2" +version = "2.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad011ae7447188e26e4a7dbca2fcd0fc186aa21ae5c86df0503ea44c78f9e469" +checksum = "db0be28064aea18722a60ea00722647b6d9bddda7945c72e71a52e2e7d91c100" dependencies = [ "base64", "bech32", @@ -258,7 +257,7 @@ dependencies = [ "derivative", "hex", "hex-literal", - "itertools 0.12.0", + "itertools 0.12.1", "once_cell", "prost", "schemars", @@ -269,9 +268,9 @@ dependencies = [ [[package]] name = "cw-storage-plus" -version = "1.2.0" +version = "2.0.0-beta.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5ff29294ee99373e2cd5fd21786a3c0ced99a52fec2ca347d565489c61b723c" +checksum = "ac155bf43ea6106a6d32023e68a465928dc2ffabd0ec53c5f6ec7959a55923d9" dependencies = [ "cosmwasm-std", "schemars", @@ -280,30 +279,13 @@ dependencies = [ [[package]] name = "cw-utils" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c4a657e5caacc3a0d00ee96ca8618745d050b8f757c709babafb81208d4239c" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw2", - "schemars", - "semver", - "serde", - "thiserror", -] - -[[package]] -name = "cw2" -version = "1.1.2" +version = "2.0.0-beta.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c120b24fbbf5c3bedebb97f2cc85fbfa1c3287e09223428e7e597b5293c1fa" +checksum = "5c41e47f5e786edbd80119a4132d6ecfe9f666c48541c74fd743ca29407fa41d" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus", "schemars", - "semver", "serde", "thiserror", ] @@ -506,9 +488,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] @@ -535,9 +517,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.152" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "memchr" @@ -547,9 +529,9 @@ checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] @@ -701,12 +683,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "semver" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" - [[package]] name = "serde" version = "1.0.196" @@ -718,9 +694,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.5.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e9213a07d53faa0b8dd81e767a54a8188a242fdb9be99ab75ec576a774bfdd7" +checksum = "f05da0d153dd4595bdffd5099dc0e9ce425b205ee648eb93437ff7302af8c9a5" dependencies = [ "serde", ] diff --git a/Cargo.toml b/Cargo.toml index 22f97897..d40f0fd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,21 +9,22 @@ repository = "https://github.com/CosmWasm/cw-multi-test" homepage = "https://cosmwasm.com" [features] -default = [] +default = ["cosmwasm_2_0"] backtrace = ["anyhow/backtrace"] cosmwasm_1_1 = ["cosmwasm-std/cosmwasm_1_1"] cosmwasm_1_2 = ["cosmwasm_1_1", "cosmwasm-std/cosmwasm_1_2"] cosmwasm_1_3 = ["cosmwasm_1_2", "cosmwasm-std/cosmwasm_1_3"] cosmwasm_1_4 = ["cosmwasm_1_3", "cosmwasm-std/cosmwasm_1_4"] +cosmwasm_2_0 = ["cosmwasm_1_4", "cosmwasm-std/cosmwasm_2_0"] [dependencies] anyhow = "1.0.79" bech32 = "0.9.1" -cosmwasm-std = { version = "1.5.2", features = ["iterator", "staking", "stargate"] } -cw-storage-plus = "1.2.0" -cw-utils = "1.0.3" +cosmwasm-std = { version = "2.0.0-rc.0", features = ["iterator", "staking", "stargate"] } +cw-storage-plus = "2.0.0-beta.0" +cw-utils = "2.0.0-beta.0" derivative = "2.2.0" -itertools = "0.12.0" +itertools = "0.12.1" prost = "0.12.3" schemars = "0.8.16" serde = "1.0.196" From e13b29ae351c0be064547e471585d96ea276d1ce Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 7 Feb 2024 15:46:32 +0100 Subject: [PATCH 043/250] cosmwasm-std 2.0 local fixes. --- Cargo.lock | 10 ---------- Cargo.toml | 7 ++++--- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c000bf1..338b85e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,8 +136,6 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-crypto" version = "2.0.0-rc.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07faab121b507bf68d49ff847d517823947d9aece93fcb951ac1d33a8b3a7910" dependencies = [ "digest 0.10.7", "ed25519-zebra", @@ -149,8 +147,6 @@ dependencies = [ [[package]] name = "cosmwasm-derive" version = "2.0.0-rc.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29db670d3578a661b7c8ac6591c5cd422363d6d0517744211bc31131c602355a" dependencies = [ "syn 1.0.109", ] @@ -182,8 +178,6 @@ dependencies = [ [[package]] name = "cosmwasm-std" version = "2.0.0-rc.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db0be28064aea18722a60ea00722647b6d9bddda7945c72e71a52e2e7d91c100" dependencies = [ "base64", "bech32", @@ -269,8 +263,6 @@ dependencies = [ [[package]] name = "cw-storage-plus" version = "2.0.0-beta.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac155bf43ea6106a6d32023e68a465928dc2ffabd0ec53c5f6ec7959a55923d9" dependencies = [ "cosmwasm-std", "schemars", @@ -280,8 +272,6 @@ dependencies = [ [[package]] name = "cw-utils" version = "2.0.0-beta.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c41e47f5e786edbd80119a4132d6ecfe9f666c48541c74fd743ca29407fa41d" dependencies = [ "cosmwasm-schema", "cosmwasm-std", diff --git a/Cargo.toml b/Cargo.toml index d40f0fd0..d5449c41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,9 +20,10 @@ cosmwasm_2_0 = ["cosmwasm_1_4", "cosmwasm-std/cosmwasm_2_0"] [dependencies] anyhow = "1.0.79" bech32 = "0.9.1" -cosmwasm-std = { version = "2.0.0-rc.0", features = ["iterator", "staking", "stargate"] } -cw-storage-plus = "2.0.0-beta.0" -cw-utils = "2.0.0-beta.0" +# cosmwasm-std = { version = "2.0.0-rc.0", features = ["iterator", "staking", "stargate"] } +cosmwasm-std = { path = "../cosmwasm/packages/std", features = ["iterator", "staking", "stargate"] } +cw-storage-plus = { path = "../cw-storage-plus"} +cw-utils = { path = "../cw-utils"} derivative = "2.2.0" itertools = "0.12.1" prost = "0.12.3" From 1cbb5768f5848cf25445c5125cd0c1f76ad3f4af Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 7 Feb 2024 16:00:10 +0100 Subject: [PATCH 044/250] Stargate and Bank fixes. --- src/app.rs | 21 +++++++++++++++------ src/bank.rs | 4 ++-- src/contracts.rs | 2 +- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/app.rs b/src/app.rs index ad035b39..cbaeab20 100644 --- a/src/app.rs +++ b/src/app.rs @@ -607,13 +607,16 @@ 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( + CosmosMsg::Any(msg) => self.stargate.execute( api, storage, self, block, sender, - StargateMsg { type_url, value }, + StargateMsg { + type_url: msg.type_url, + value: msg.value, + }, ), _ => bail!("Cannot execute {:?}", msg), } @@ -636,10 +639,16 @@ 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 }) - } + QueryRequest::Grpc(grpc) => self.stargate.query( + api, + storage, + &querier, + block, + StargateQuery { + path: grpc.path, + data: grpc.data, + }, + ), _ => unimplemented!(), } } diff --git a/src/bank.rs b/src/bank.rs index 860f12ac..cefc0e24 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -229,7 +229,7 @@ impl Module for BankKeeper { BankQuery::AllBalances { address } => { let address = api.addr_validate(&address)?; let amount = self.get_balance(&bank_storage, &address)?; - let res = AllBalanceResponse { amount }; + let res = AllBalanceResponse::new(amount); to_json_binary(&res).map_err(Into::into) } BankQuery::Balance { address, denom } => { @@ -239,7 +239,7 @@ impl Module for BankKeeper { .into_iter() .find(|c| c.denom == denom) .unwrap_or_else(|| coin(0, denom)); - let res = BalanceResponse { amount }; + let res = BalanceResponse::new(amount); to_json_binary(&res).map_err(Into::into) } #[cfg(feature = "cosmwasm_1_1")] diff --git a/src/contracts.rs b/src/contracts.rs index 6d7afb21..869c64af 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -369,7 +369,7 @@ where CosmosMsg::Distribution(distribution) => CosmosMsg::Distribution(distribution), CosmosMsg::Custom(_) => unreachable!(), CosmosMsg::Ibc(ibc) => CosmosMsg::Ibc(ibc), - CosmosMsg::Stargate { type_url, value } => CosmosMsg::Stargate { type_url, value }, + CosmosMsg::Any(any) => CosmosMsg::Any(any), _ => panic!("unknown message variant {:?}", msg), }, id: msg.id, From 322d8890a99fec1cc4b611b75cdd1b19d980b5e7 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 7 Feb 2024 16:31:18 +0100 Subject: [PATCH 045/250] Fixed uint128 mul and checksum. --- src/checksums.rs | 9 ++--- src/staking.rs | 99 +++++++++++++++++++++++------------------------- src/wasm.rs | 32 +++++++++------- 3 files changed, 69 insertions(+), 71 deletions(-) diff --git a/src/checksums.rs b/src/checksums.rs index 994ee79e..d5a38536 100644 --- a/src/checksums.rs +++ b/src/checksums.rs @@ -1,7 +1,6 @@ //! # Implementation of the interface to custom checksum generator -use cosmwasm_std::{Addr, HexBinary}; -use sha2::{Digest, Sha256}; +use cosmwasm_std::{Addr, Checksum}; /// Provides a custom interface for generating checksums for contract code. /// This is crucial for ensuring code integrity and is particularly useful @@ -14,7 +13,7 @@ pub trait ChecksumGenerator { /// and code identifier. Returns a hexadecimal binary representation /// of the calculated checksum. There are no assumptions about /// the length of the calculated checksum. - fn checksum(&self, creator: &Addr, code_id: u64) -> HexBinary; + fn checksum(&self, creator: &Addr, code_id: u64) -> Checksum; } /// Default checksum generator implementation. @@ -23,7 +22,7 @@ pub struct SimpleChecksumGenerator; impl ChecksumGenerator for SimpleChecksumGenerator { /// Calculates the checksum based on code identifier. The resulting /// checksum is 32-byte length SHA2 digest. - fn checksum(&self, _creator: &Addr, code_id: u64) -> HexBinary { - HexBinary::from(Sha256::digest(format!("contract code {}", code_id)).to_vec()) + fn checksum(&self, _creator: &Addr, code_id: u64) -> Checksum { + Checksum::generate(format!("contract code {}", code_id).as_bytes()) } } diff --git a/src/staking.rs b/src/staking.rs index 9d8166fa..41d2adb4 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -256,7 +256,7 @@ impl StakeKeeper { Ok(Coin { denom: staking_info.bonded_denom, - amount: Uint128::new(1) * delegator_rewards, // multiplying by 1 to convert Decimal to Uint128 + amount: Uint128::new(1).mul_floor(delegator_rewards), // multiplying by 1 to convert Decimal to Uint128 }) } @@ -362,7 +362,7 @@ impl StakeKeeper { Ok(shares.map(|shares| { Coin { denom: staking_info.bonded_denom, - amount: Uint128::new(1) * shares.stake, // multiplying by 1 to convert Decimal to Uint128 + amount: Uint128::new(1).mul_floor(shares.stake), // multiplying by 1 to convert Decimal to Uint128 } })) } @@ -482,7 +482,7 @@ impl StakeKeeper { .unwrap(); let remaining_percentage = Decimal::one() - percentage; - validator_info.stake = validator_info.stake * remaining_percentage; + validator_info.stake = validator_info.stake.mul_floor(remaining_percentage); // if the stake is completely gone, we clear all stakers and reinitialize the validator if validator_info.stake.is_zero() { @@ -515,7 +515,7 @@ impl StakeKeeper { .iter_mut() .filter(|ub| &ub.validator == validator) .for_each(|ub| { - ub.amount = ub.amount * remaining_percentage; + ub.amount = ub.amount.mul_floor(remaining_percentage); }); UNBONDING_QUEUE.save(staking_storage, &unbonding_queue)?; @@ -783,36 +783,33 @@ impl Module for StakeKeeper { ) -> AnyResult { let staking_storage = prefixed_read(storage, NAMESPACE_STAKING); match request { - StakingQuery::BondedDenom {} => Ok(to_json_binary(&BondedDenomResponse { - denom: Self::get_staking_info(&staking_storage)?.bonded_denom, - })?), + StakingQuery::BondedDenom {} => Ok(to_json_binary(&BondedDenomResponse::new( + Self::get_staking_info(&staking_storage)?.bonded_denom, + ))?), StakingQuery::AllDelegations { delegator } => { let delegator = api.addr_validate(&delegator)?; let validators = self.get_validators(&staking_storage)?; - let res: AnyResult> = validators - .into_iter() - .filter_map(|validator| { - let delegator = delegator.clone(); - let amount = self - .get_stake( - &staking_storage, - &delegator, - &Addr::unchecked(&validator.address), - ) - .transpose()?; - - Some(amount.map(|amount| Delegation { - delegator, - validator: validator.address, - amount, - })) - }) - .collect(); - - Ok(to_json_binary(&AllDelegationsResponse { - delegations: res?, - })?) + let res: AnyResult> = + validators + .into_iter() + .filter_map(|validator| { + let delegator = delegator.clone(); + let amount = self + .get_stake( + &staking_storage, + &delegator, + &Addr::unchecked(&validator.address), + ) + .transpose()?; + + Some(amount.map(|amount| { + Delegation::new(delegator, validator.address, amount) + })) + }) + .collect(); + + Ok(to_json_binary(&AllDelegationsResponse::new(res?))?) } StakingQuery::Delegation { delegator, @@ -840,38 +837,36 @@ impl Module for StakeKeeper { let staking_info = Self::get_staking_info(&staking_storage)?; let amount = coin( - (shares.stake * Uint128::new(1)).u128(), + Uint128::new(1).mul_floor(shares.stake).u128(), staking_info.bonded_denom, ); let full_delegation_response = if amount.amount.is_zero() { // no delegation - DelegationResponse { delegation: None } + DelegationResponse::new(None) } else { - DelegationResponse { - delegation: Some(FullDelegation { - delegator, - validator, - amount: amount.clone(), - can_redelegate: amount, // TODO: not implemented right now - accumulated_rewards: if reward.amount.is_zero() { - vec![] - } else { - vec![reward] - }, - }), - } + DelegationResponse::new(Some(FullDelegation::new( + delegator, + validator, + amount.clone(), + amount, // TODO: not implemented right now + if reward.amount.is_zero() { + vec![] + } else { + vec![reward] + }, + ))) }; let res = to_json_binary(&full_delegation_response)?; Ok(res) } - StakingQuery::AllValidators {} => Ok(to_json_binary(&AllValidatorsResponse { - validators: self.get_validators(&staking_storage)?, - })?), - StakingQuery::Validator { address } => Ok(to_json_binary(&ValidatorResponse { - validator: self.get_validator(&staking_storage, &Addr::unchecked(address))?, - })?), + StakingQuery::AllValidators {} => Ok(to_json_binary(&AllValidatorsResponse::new( + self.get_validators(&staking_storage)?, + ))?), + StakingQuery::Validator { address } => Ok(to_json_binary(&ValidatorResponse::new( + self.get_validator(&staking_storage, &Addr::unchecked(address))?, + ))?), q => bail!("Unsupported staking sudo message: {:?}", q), } } @@ -906,7 +901,7 @@ impl DistributionKeeper { // load updated rewards for delegator let mut shares = STAKES.load(&staking_storage, (delegator, validator))?; - let rewards = Uint128::new(1) * shares.rewards; // convert to Uint128 + let rewards = Uint128::new(1).mul_floor(shares.rewards); // convert to Uint128 // remove rewards from delegator shares.rewards = Decimal::zero(); diff --git a/src/wasm.rs b/src/wasm.rs index dac40c86..5e2509a5 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -8,10 +8,10 @@ use crate::prefixed_storage::{prefixed, prefixed_read, PrefixedStorage, Readonly use crate::transactions::transactional; use cosmwasm_std::testing::mock_wasmd_attr; use cosmwasm_std::{ - to_json_binary, Addr, Api, Attribute, BankMsg, Binary, BlockInfo, Coin, ContractInfo, - ContractInfoResponse, CustomMsg, CustomQuery, Deps, DepsMut, Env, Event, HexBinary, - MessageInfo, Order, Querier, QuerierWrapper, Record, Reply, ReplyOn, Response, StdResult, - Storage, SubMsg, SubMsgResponse, SubMsgResult, TransactionInfo, WasmMsg, WasmQuery, + to_json_binary, Addr, Api, Attribute, BankMsg, Binary, BlockInfo, Checksum, Coin, ContractInfo, + ContractInfoResponse, CustomMsg, CustomQuery, Deps, DepsMut, Env, Event, MessageInfo, Order, + Querier, QuerierWrapper, Record, Reply, ReplyOn, Response, StdResult, Storage, SubMsg, + SubMsgResponse, SubMsgResult, TransactionInfo, WasmMsg, WasmQuery, }; use cw_storage_plus::Map; use prost::Message; @@ -70,7 +70,7 @@ struct CodeData { /// Address of an account that initially stored the contract code. creator: Addr, /// Checksum of the contract's code base. - checksum: HexBinary, + checksum: Checksum, /// Identifier of the code base where the contract code is stored in memory. code_base_id: usize, } @@ -177,19 +177,23 @@ where WasmQuery::ContractInfo { contract_addr } => { let addr = api.addr_validate(&contract_addr)?; let contract = self.contract_data(storage, &addr)?; - let mut res = ContractInfoResponse::default(); - res.code_id = contract.code_id; - res.creator = contract.creator.to_string(); - res.admin = contract.admin.map(|x| x.into()); + let res = ContractInfoResponse::new( + contract.code_id, + contract.creator, + contract.admin.map(|x| x.into()), + false, + None, + ); to_json_binary(&res).map_err(Into::into) } #[cfg(feature = "cosmwasm_1_2")] WasmQuery::CodeInfo { code_id } => { let code_data = self.code_data(code_id)?; - let mut res = cosmwasm_std::CodeInfoResponse::default(); - res.code_id = code_id; - res.creator = code_data.creator.to_string(); - res.checksum = code_data.checksum.clone(); + let res = cosmwasm_std::CodeInfoResponse::new( + code_id, + code_data.creator.clone(), + code_data.checksum.clone(), + ); to_json_binary(&res).map_err(Into::into) } _ => unimplemented!("{}", Error::unsupported_wasm_query(request)), @@ -234,7 +238,7 @@ where let code_base_id = self.code_base.len(); self.code_base.push(code); let code_id = (self.code_data.len() + 1) as u64; - let checksum = self.checksum_generator.checksum(&creator, code_id); + let checksum: Checksum = self.checksum_generator.checksum(&creator, code_id).into(); self.code_data.push(CodeData { creator, checksum, From 6062bbbd7ca9c52a69fc72c1ba19a1fa14ab7b73 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 7 Feb 2024 16:33:53 +0100 Subject: [PATCH 046/250] Added default-empty payload. --- src/contracts.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/contracts.rs b/src/contracts.rs index 869c64af..0a0acc49 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -362,6 +362,8 @@ where C: CustomMsg, { SubMsg { + id: msg.id, + payload: Binary::default(), msg: match msg.msg { CosmosMsg::Wasm(wasm) => CosmosMsg::Wasm(wasm), CosmosMsg::Bank(bank) => CosmosMsg::Bank(bank), @@ -372,7 +374,6 @@ where CosmosMsg::Any(any) => CosmosMsg::Any(any), _ => panic!("unknown message variant {:?}", msg), }, - id: msg.id, gas_limit: msg.gas_limit, reply_on: msg.reply_on, } From 36beee3294a4946c88f9063f31ece893fb73c7d8 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 7 Feb 2024 17:27:23 +0100 Subject: [PATCH 047/250] Test code fixes. --- src/executor.rs | 2 +- src/staking.rs | 144 +++++++++---------- src/test_helpers/echo.rs | 3 +- src/test_helpers/gov.rs | 2 +- src/test_helpers/stargate.rs | 6 +- src/tests/test_app.rs | 27 ++-- src/wasm.rs | 44 +++--- tests/test_app_builder/test_with_gov.rs | 2 +- tests/test_app_builder/test_with_staking.rs | 2 +- tests/test_app_builder/test_with_stargate.rs | 26 ++-- tests/test_wasm/test_with_checksum_gen.rs | 9 +- 11 files changed, 136 insertions(+), 131 deletions(-) diff --git a/src/executor.rs b/src/executor.rs index 0e80f171..9892ef74 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -58,7 +58,7 @@ impl AppResponse { impl From for AppResponse { fn from(reply: SubMsgResponse) -> Self { AppResponse { - data: reply.data, + data: None, events: reply.events, } } diff --git a/src/staking.rs b/src/staking.rs index 41d2adb4..cbcc45aa 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1091,12 +1091,12 @@ mod test { .unwrap(); // add validator - let valoper1 = Validator { - address: "testvaloper1".to_string(), - commission: validator_commission, - max_commission: Decimal::percent(100), - max_change_rate: Decimal::percent(1), - }; + let valoper1 = Validator::new( + "testvaloper1".to_string(), + validator_commission, + Decimal::percent(100), + Decimal::percent(1), + ); router .staking .add_validator(&api, &mut store, &block, valoper1) @@ -1113,12 +1113,12 @@ mod test { let block = mock_env().block; // add validator - let valoper1 = Validator { - address: "testvaloper1".to_string(), - commission: Decimal::percent(10), - max_commission: Decimal::percent(20), - max_change_rate: Decimal::percent(1), - }; + let valoper1 = Validator::new( + "testvaloper1".to_string(), + Decimal::percent(10), + Decimal::percent(20), + Decimal::percent(1), + ); stake .add_validator(&api, &mut store, &block, valoper1.clone()) .unwrap(); @@ -1135,12 +1135,12 @@ mod test { assert_eq!(val, valoper1); // try to add with same address - let valoper1_fake = Validator { - address: "testvaloper1".to_string(), - commission: Decimal::percent(1), - max_commission: Decimal::percent(10), - max_change_rate: Decimal::percent(100), - }; + let valoper1_fake = Validator::new( + "testvaloper1".to_string(), + Decimal::percent(1), + Decimal::percent(10), + Decimal::percent(100), + ); stake .add_validator(&api, &mut store, &block, valoper1_fake) .unwrap_err(); @@ -1169,12 +1169,12 @@ mod test { let validator = api.addr_validate("testvaloper1").unwrap(); // add validator - let valoper1 = Validator { - address: "testvaloper1".to_string(), - commission: Decimal::percent(10), - max_commission: Decimal::percent(20), - max_change_rate: Decimal::percent(1), - }; + let valoper1 = Validator::new( + "testvaloper1".to_string(), + Decimal::percent(10), + Decimal::percent(20), + Decimal::percent(1), + ); stake .add_validator(&api, &mut store, &block, valoper1) .unwrap(); @@ -1575,12 +1575,12 @@ mod test { &test_env.api, &mut test_env.store, &test_env.block, - Validator { - address: validator2.to_string(), - commission: Decimal::zero(), - max_commission: Decimal::percent(20), - max_change_rate: Decimal::percent(1), - }, + Validator::new( + validator2.to_string(), + Decimal::zero(), + Decimal::percent(20), + Decimal::percent(1), + ), ) .unwrap(); @@ -1652,11 +1652,11 @@ mod test { .unwrap(); assert_eq!( delegations.delegations, - [Delegation { - delegator: delegator1.clone(), - validator: validator2.to_string(), - amount: coin(100, "TOKEN"), - }] + [Delegation::new( + delegator1.clone(), + validator2.to_string(), + coin(100, "TOKEN"), + )] ); // undelegate all tokens @@ -1816,12 +1816,12 @@ mod test { &test_env.api, &mut test_env.store, &test_env.block, - Validator { - address: validator2.to_string(), - commission: Decimal::zero(), - max_commission: Decimal::percent(20), - max_change_rate: Decimal::percent(1), - }, + Validator::new( + validator2.to_string(), + Decimal::zero(), + Decimal::percent(20), + Decimal::percent(1), + ), ) .unwrap(); @@ -2011,12 +2011,12 @@ mod test { // add another validator let validator2 = test_env.api.addr_validate("testvaloper2").unwrap(); - let valoper2 = Validator { - address: "testvaloper2".to_string(), - commission: Decimal::percent(0), - max_commission: Decimal::percent(1), - max_change_rate: Decimal::percent(1), - }; + let valoper2 = Validator::new( + "testvaloper2".to_string(), + Decimal::percent(0), + Decimal::percent(1), + Decimal::percent(1), + ); test_env .router .staking @@ -2116,16 +2116,16 @@ mod test { assert_eq!( response1.delegations, vec![ - Delegation { - delegator: delegator1.clone(), - validator: validator1.to_string(), - amount: coin(50, "TOKEN"), - }, - Delegation { - delegator: delegator1.clone(), - validator: validator2.to_string(), - amount: coin(160, "TOKEN"), - }, + Delegation::new( + delegator1.clone(), + validator1.to_string(), + coin(50, "TOKEN"), + ), + Delegation::new( + delegator1.clone(), + validator2.to_string(), + coin(160, "TOKEN"), + ), ] ); let response2: DelegationResponse = query_stake( @@ -2138,13 +2138,13 @@ mod test { .unwrap(); assert_eq!( response2.delegation.unwrap(), - FullDelegation { - delegator: delegator2.clone(), - validator: validator1.to_string(), - amount: coin(100, "TOKEN"), - accumulated_rewards: vec![], - can_redelegate: coin(100, "TOKEN"), - }, + FullDelegation::new( + delegator2.clone(), + validator1.to_string(), + coin(100, "TOKEN"), + coin(100, "TOKEN"), + vec![], + ), ); } @@ -2218,11 +2218,11 @@ mod test { .unwrap(); assert_eq!( response1.delegations, - vec![Delegation { - delegator: delegator1.clone(), - validator: validator.to_string(), - amount: coin(50, "TOKEN"), - }] + vec![Delegation::new( + delegator1.clone(), + validator.to_string(), + coin(50, "TOKEN"), + )] ); let response2: DelegationResponse = query_stake( &test_env, @@ -2462,11 +2462,7 @@ mod test { .unwrap(); assert_eq!( response1.delegations[0], - Delegation { - delegator: delegator.clone(), - validator: validator.to_string(), - amount: coin(111, "TOKEN"), - } + Delegation::new(delegator.clone(), validator.to_string(), coin(111, "TOKEN"),) ); // wait until unbonding is complete and check if amount was slashed diff --git a/src/test_helpers/echo.rs b/src/test_helpers/echo.rs index 0b73a394..adb3c214 100644 --- a/src/test_helpers/echo.rs +++ b/src/test_helpers/echo.rs @@ -87,7 +87,7 @@ fn query(_deps: Deps, _env: Env, msg: Empty) -> Result { to_json_binary(&msg) } -#[allow(clippy::unnecessary_wraps)] +#[allow(clippy::unnecessary_wraps, deprecated)] fn reply(_deps: DepsMut, _env: Env, msg: Reply) -> Result, StdError> where ExecC: Debug + PartialEq + Clone + JsonSchema + 'static, @@ -98,6 +98,7 @@ where result: SubMsgResult::Ok(SubMsgResponse { data: Some(data), .. }), + .. } = msg { // We parse out the WasmMsg::Execute wrapper... diff --git a/src/test_helpers/gov.rs b/src/test_helpers/gov.rs index bc5a413b..0c885c3a 100644 --- a/src/test_helpers/gov.rs +++ b/src/test_helpers/gov.rs @@ -10,7 +10,7 @@ fn instantiate(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> St fn execute(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { let msg: CosmosMsg = GovMsg::Vote { proposal_id: 1, - vote: cosmwasm_std::VoteOption::No, + option: cosmwasm_std::VoteOption::No, } .into(); let resp = Response::new().add_message(msg); diff --git a/src/test_helpers/stargate.rs b/src/test_helpers/stargate.rs index ca090e75..c624c2c3 100644 --- a/src/test_helpers/stargate.rs +++ b/src/test_helpers/stargate.rs @@ -1,6 +1,6 @@ use crate::{Contract, ContractWrapper}; use cosmwasm_std::{ - Binary, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdResult, + AnyMsg, Binary, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdResult, }; fn instantiate(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { @@ -8,10 +8,10 @@ fn instantiate(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> St } fn execute(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { - Ok(Response::new().add_message(CosmosMsg::Stargate { + Ok(Response::new().add_message(CosmosMsg::Any(AnyMsg { type_url: "/this.is.a.stargate.test.helper".to_string(), value: Default::default(), - })) + }))) } fn query(_deps: Deps, _env: Env, _msg: Empty) -> StdResult { diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 58ae2924..11154bcb 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -505,7 +505,7 @@ fn reflect_error() { .execute_contract(random.clone(), reflect_addr.clone(), &msgs, &[]) .unwrap_err(); assert_eq!( - StdError::overflow(OverflowError::new(OverflowOperation::Sub, 0, 3)), + StdError::overflow(OverflowError::new(OverflowOperation::Sub)), err.downcast().unwrap() ); @@ -772,7 +772,7 @@ fn sent_wasm_migration_works() { .wrap() .query_wasm_smart(&contract, &hackatom::QueryMsg::Beneficiary {}) .unwrap(); - assert_eq!(state.beneficiary, beneficiary); + assert_eq!(state.beneficiary, beneficiary.to_string()); // migrate fails if not admin let random = Addr::unchecked("random"); @@ -795,7 +795,7 @@ fn sent_wasm_migration_works() { .wrap() .query_wasm_smart(&contract, &hackatom::QueryMsg::Beneficiary {}) .unwrap(); - assert_eq!(state.beneficiary, random); + assert_eq!(state.beneficiary, random.to_string()); } #[test] @@ -1608,8 +1608,8 @@ mod wasm_queries { let code_id = app.store_code_with_creator(Addr::unchecked("creator"), echo::contract()); let code_info_response = app.wrap().query_wasm_code_info(code_id).unwrap(); assert_eq!(code_id, code_info_response.code_id); - assert_eq!("creator", code_info_response.creator); - assert!(!code_info_response.checksum.is_empty()); + assert_eq!("creator", code_info_response.creator.to_string()); + assert_eq!(code_info_response.checksum.to_string(), ""); } #[test] @@ -1836,7 +1836,7 @@ mod errors { // we should be able to retrieve the original error by downcasting let source: &StdError = err.downcast_ref().unwrap(); - if let StdError::GenericErr { msg } = source { + if let StdError::GenericErr { msg, .. } = source { assert_eq!(msg, "Init failed"); } else { panic!("wrong StdError variant"); @@ -1867,7 +1867,7 @@ mod errors { // we should be able to retrieve the original error by downcasting let source: &StdError = err.downcast_ref().unwrap(); - if let StdError::GenericErr { msg } = source { + if let StdError::GenericErr { msg, .. } = source { assert_eq!(msg, "Handle failed"); } else { panic!("wrong StdError variant"); @@ -1905,9 +1905,9 @@ mod errors { .execute_contract(Addr::unchecked("random"), caller_addr, &msg, &[]) .unwrap_err(); - // we can downcast to get the original error + // we can get the original error by downcasting let source: &StdError = err.downcast_ref().unwrap(); - if let StdError::GenericErr { msg } = source { + if let StdError::GenericErr { msg, .. } = source { assert_eq!(msg, "Handle failed"); } else { panic!("wrong StdError variant"); @@ -1956,9 +1956,9 @@ mod errors { // uncomment to have the test fail and see how the error stringifies // panic!("{:?}", err); - // we can downcast to get the original error + // we can get the original error by downcasting let source: &StdError = err.downcast_ref().unwrap(); - if let StdError::GenericErr { msg } = source { + if let StdError::GenericErr { msg, .. } = source { assert_eq!(msg, "Handle failed"); } else { panic!("wrong StdError variant"); @@ -1992,6 +1992,9 @@ mod api { fn api_addr_humanize_should_work() { let app = App::default(); let canonical = app.api().addr_canonicalize("creator").unwrap(); - assert_eq!(app.api().addr_humanize(&canonical).unwrap(), "creator"); + assert_eq!( + app.api().addr_humanize(&canonical).unwrap().to_string(), + "creator" + ); } } diff --git a/src/wasm.rs b/src/wasm.rs index 5e2509a5..711640d2 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -180,7 +180,7 @@ where let res = ContractInfoResponse::new( contract.code_id, contract.creator, - contract.admin.map(|x| x.into()), + contract.admin, false, None, ); @@ -192,7 +192,7 @@ where let res = cosmwasm_std::CodeInfoResponse::new( code_id, code_data.creator.clone(), - code_data.checksum.clone(), + code_data.checksum, ); to_json_binary(&res).map_err(Into::into) } @@ -238,7 +238,7 @@ where let code_base_id = self.code_base.len(); self.code_base.push(code); let code_id = (self.code_data.len() + 1) as u64; - let checksum: Checksum = self.checksum_generator.checksum(&creator, code_id).into(); + let checksum: Checksum = self.checksum_generator.checksum(&creator, code_id); self.code_data.push(CodeData { creator, checksum, @@ -253,7 +253,7 @@ where let code_data = self.code_data(code_id)?; self.code_data.push(CodeData { creator: code_data.creator.clone(), - checksum: code_data.checksum.clone(), + checksum: code_data.checksum, code_base_id: code_data.code_base_id, }); Ok(code_id + 1) @@ -756,6 +756,7 @@ where /// /// The `data` on `AppResponse` is data returned from `reply` call, not from execution of /// sub-message itself. In case if `reply` is not called, no `data` is set. + #[allow(deprecated)] fn execute_submsg( &self, api: &dyn Api, @@ -779,9 +780,12 @@ where if matches!(reply_on, ReplyOn::Always | ReplyOn::Success) { let reply = Reply { id, + payload: Default::default(), + gas_used: 0, result: SubMsgResult::Ok(SubMsgResponse { events: r.events.clone(), - data: r.data, + data: None, + msg_responses: vec![], }), }; // do reply and combine it with the original response @@ -800,6 +804,8 @@ where if matches!(reply_on, ReplyOn::Always | ReplyOn::Error) { let reply = Reply { id, + payload: Default::default(), + gas_used: 0, result: SubMsgResult::Err(format!("{:?}", e)), }; self.reply(api, router, storage, block, contract, reply) @@ -1347,16 +1353,16 @@ mod test { let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); assert_eq!(1, code_id); - let creator = "foobar"; - let admin = "admin"; + let creator = Addr::unchecked("foobar"); + let admin = Addr::unchecked("admin"); let contract_addr = wasm_keeper .register_contract( &api, &mut wasm_storage, code_id, - Addr::unchecked(creator), - Addr::unchecked(admin), + creator.clone(), + admin.clone(), "label".to_owned(), 1000, None, @@ -1373,10 +1379,7 @@ mod test { .unwrap(); let actual: ContractInfoResponse = from_json(contract_info).unwrap(); - let mut expected = ContractInfoResponse::default(); - expected.code_id = code_id; - expected.creator = creator.into(); - expected.admin = Some(admin.into()); + let expected = ContractInfoResponse::new(code_id, creator, admin.into(), false, None); assert_eq!(expected, actual); } @@ -1395,8 +1398,8 @@ mod test { .unwrap(); let actual: cosmwasm_std::CodeInfoResponse = from_json(code_info).unwrap(); assert_eq!(code_id, actual.code_id); - assert_eq!("creator", actual.creator); - assert!(!actual.checksum.is_empty()); + assert_eq!("creator", actual.creator.to_string()); + assert_eq!(actual.checksum.to_string(), ""); } #[test] @@ -1779,7 +1782,7 @@ mod test { ) .unwrap(); let res: ContractInfoResponse = from_json(data).unwrap(); - assert_eq!(res.admin, admin.as_ref().map(Addr::to_string)); + assert_eq!(res.admin, admin); } #[test] @@ -1920,7 +1923,8 @@ mod test { .unwrap(); assert_eq!( - contract_addr, "contract0", + contract_addr.to_string(), + "contract0", "default address generator returned incorrect address" ); @@ -1940,7 +1944,7 @@ mod test { .unwrap(); assert_eq!( - contract_addr, + contract_addr.to_string(), format!( "contract{}{}", api.addr_canonicalize("foobar").unwrap(), @@ -1966,7 +1970,7 @@ mod test { .unwrap(); assert_eq!( - contract_addr, + contract_addr.to_string(), format!( "contract{}{}", api.addr_canonicalize("boobaz").unwrap(), @@ -2068,7 +2072,7 @@ mod test { }; let mut storage = MockStorage::default(); let contract_addr = addr_gen.next_address(&mut storage); - assert_eq!(contract_addr, "contract0"); + assert_eq!(contract_addr.to_string(), "contract0"); let _: WasmKeeper = WasmKeeper::new_with_custom_address_generator(addr_gen); } diff --git a/tests/test_app_builder/test_with_gov.rs b/tests/test_app_builder/test_with_gov.rs index 7f47095a..76faf582 100644 --- a/tests/test_app_builder/test_with_gov.rs +++ b/tests/test_app_builder/test_with_gov.rs @@ -24,7 +24,7 @@ fn building_app_with_custom_gov_should_work() { Addr::unchecked("sender"), GovMsg::Vote { proposal_id: 1, - vote: VoteOption::Yes, + option: VoteOption::Yes, } .into(), ) diff --git a/tests/test_app_builder/test_with_staking.rs b/tests/test_app_builder/test_with_staking.rs index 798b42d5..9dc8c38f 100644 --- a/tests/test_app_builder/test_with_staking.rs +++ b/tests/test_app_builder/test_with_staking.rs @@ -43,7 +43,7 @@ fn building_app_with_custom_staking_should_work() { Addr::unchecked("sender"), StakingMsg::Delegate { validator: validator.clone().into(), - amount: Coin::new(1, "eth"), + amount: Coin::new(1_u32, "eth"), } .into(), ) diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index c068abb7..d5216c5b 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -1,5 +1,5 @@ use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; -use cosmwasm_std::{to_json_vec, Addr, CosmosMsg, Empty, QueryRequest}; +use cosmwasm_std::{to_json_vec, Addr, AnyMsg, CosmosMsg, Empty, GrpcQuery, QueryRequest}; use cw_multi_test::{ no_init, AppBuilder, Executor, Stargate, StargateAcceptingModule, StargateFailingModule, StargateMsg, StargateQuery, @@ -26,10 +26,10 @@ fn building_app_with_custom_stargate_should_work() { assert_eq!( app.execute( Addr::unchecked("sender"), - CosmosMsg::Stargate { + CosmosMsg::Any(AnyMsg { type_url: "test".to_string(), value: Default::default() - }, + }), ) .unwrap_err() .to_string(), @@ -38,10 +38,10 @@ fn building_app_with_custom_stargate_should_work() { // executing stargate query should return // an error defined in custom stargate keeper - let query: QueryRequest = QueryRequest::Stargate { + let query: QueryRequest = QueryRequest::Grpc(GrpcQuery { path: "test".to_string(), data: Default::default(), - }; + }); assert_eq!( app.wrap() .raw_query(to_json_vec(&query).unwrap().as_slice()) @@ -60,19 +60,19 @@ fn building_app_with_accepting_stargate_should_work() { app.execute( Addr::unchecked("sender"), - CosmosMsg::Stargate { + CosmosMsg::Any(AnyMsg { type_url: "test".to_string(), value: Default::default(), - }, + }), ) .unwrap(); let _ = app .wrap() - .query::(&QueryRequest::Stargate { + .query::(&QueryRequest::Grpc(GrpcQuery { path: "test".to_string(), data: Default::default(), - }) + })) .is_ok(); } @@ -85,18 +85,18 @@ fn building_app_with_failing_stargate_should_work() { app.execute( Addr::unchecked("sender"), - CosmosMsg::Stargate { + CosmosMsg::Any(AnyMsg { type_url: "test".to_string(), value: Default::default(), - }, + }), ) .unwrap_err(); let _ = app .wrap() - .query::(&QueryRequest::Stargate { + .query::(&QueryRequest::Grpc(GrpcQuery { path: "test".to_string(), data: Default::default(), - }) + })) .unwrap_err(); } diff --git a/tests/test_wasm/test_with_checksum_gen.rs b/tests/test_wasm/test_with_checksum_gen.rs index 89b7d600..3540d304 100644 --- a/tests/test_wasm/test_with_checksum_gen.rs +++ b/tests/test_wasm/test_with_checksum_gen.rs @@ -1,7 +1,7 @@ #![cfg(feature = "cosmwasm_1_2")] use crate::test_contracts; -use cosmwasm_std::{Addr, HexBinary}; +use cosmwasm_std::{Addr, Checksum}; use cw_multi_test::{no_init, App, AppBuilder, ChecksumGenerator, WasmKeeper}; #[test] @@ -28,9 +28,10 @@ fn default_checksum_generator_should_work() { struct MyChecksumGenerator; impl ChecksumGenerator for MyChecksumGenerator { - fn checksum(&self, _creator: &Addr, _code_id: u64) -> HexBinary { - HexBinary::from_hex("c0ffee01c0ffee02c0ffee03c0ffee04c0ffee05c0ffee06c0ffee07c0ffee08") - .unwrap() + fn checksum(&self, _creator: &Addr, _code_id: u64) -> Checksum { + Checksum::generate( + "c0ffee01c0ffee02c0ffee03c0ffee04c0ffee05c0ffee06c0ffee07c0ffee08".as_bytes(), + ) } } From b3c6a43a435f93002970df4eb662d38ed424843d Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 8 Feb 2024 10:29:11 +0100 Subject: [PATCH 048/250] Fixed some tests. --- src/addresses.rs | 64 ++++++++------- src/wasm.rs | 108 +++++++++++--------------- tests/test_wasm/test_with_addr_gen.rs | 6 -- 3 files changed, 77 insertions(+), 101 deletions(-) diff --git a/src/addresses.rs b/src/addresses.rs index 50c5fb67..bd5c8b10 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -1,9 +1,9 @@ //! # Implementation of address generators use crate::error::AnyResult; -use crate::prefixed_storage::prefixed_read; -use crate::wasm::{CONTRACTS, NAMESPACE_WASM}; -use cosmwasm_std::{Addr, Api, CanonicalAddr, HexBinary, Order, Storage}; +use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage}; +use sha2::digest::Update; +use sha2::{Digest, Sha256}; /// Common address generator interface. /// @@ -12,27 +12,6 @@ use cosmwasm_std::{Addr, Api, CanonicalAddr, HexBinary, Order, Storage}; /// or [predictable_contract_address](AddressGenerator::predictable_contract_address) is used, /// but users should not make any assumptions about the value of the generated address. pub trait AddressGenerator { - #[deprecated( - since = "0.18.0", - note = "use `contract_address` or `predictable_contract_address` instead; will be removed in version 1.0.0" - )] - /// Generates a _non-predictable_ contract address based on the number of contract's instances. - /// This is a simplified version of simulating contract addresses that is deprecated in favour of - /// [contract_address](Self::contract_address) and - /// [predictable_contract_address](Self::predictable_contract_address) functions. - fn next_address(&self, storage: &mut dyn Storage) -> Addr { - //TODO After removing this function in version 1.0, make `CONTRACTS` and `NAMESPACE_WASM` private in `wasm.rs`. - let count = CONTRACTS - .range_raw( - &prefixed_read(storage, NAMESPACE_WASM), - None, - None, - Order::Ascending, - ) - .count(); - Addr::unchecked(format!("contract{}", count)) - } - /// Generates a _non-predictable_ contract address, just like the real-life chain /// returns contract address after its instantiation. /// Address generated by this function is returned as a result of processing @@ -68,12 +47,13 @@ pub trait AddressGenerator { /// ``` fn contract_address( &self, - _api: &dyn Api, + api: &dyn Api, _storage: &mut dyn Storage, - _code_id: u64, + code_id: u64, instance_id: u64, ) -> AnyResult { - Ok(Addr::unchecked(format!("contract{instance_id}"))) + let canonical_addr = instantiate_address(code_id, instance_id); + Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) } /// Generates a _predictable_ contract address, just like the real-life chain @@ -117,21 +97,39 @@ pub trait AddressGenerator { /// ``` fn predictable_contract_address( &self, - _api: &dyn Api, + api: &dyn Api, _storage: &mut dyn Storage, _code_id: u64, _instance_id: u64, - _checksum: &[u8], + checksum: &[u8], creator: &CanonicalAddr, salt: &[u8], ) -> AnyResult { - Ok(Addr::unchecked(format!( - "contract{creator}{}", - HexBinary::from(salt).to_hex() - ))) + let canonical_addr = instantiate2_address(checksum, creator, salt)?; + Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) } } +/// Returns non-predictable contract address. +/// +/// Address is generated using the same algorithm as [`BuildContractAddressClassic`] +/// implementation in `wasmd`. +/// +/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41 +fn instantiate_address(code_id: u64, instance_id: u64) -> CanonicalAddr { + let mut key = Vec::::new(); + key.extend_from_slice(b"wasm\0"); + key.extend_from_slice(&code_id.to_be_bytes()); + key.extend_from_slice(&instance_id.to_be_bytes()); + let module = Sha256::digest("module".as_bytes()); + Sha256::new() + .chain(module) + .chain(key) + .finalize() + .to_vec() + .into() +} + /// Default contract address generator used in [WasmKeeper](crate::WasmKeeper). pub struct SimpleAddressGenerator; diff --git a/src/wasm.rs b/src/wasm.rs index 711640d2..13b12378 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -21,12 +21,12 @@ use serde::{Deserialize, Serialize}; use std::borrow::Borrow; use std::fmt::Debug; -//TODO Make `CONTRACTS` private in version 1.0 when the function AddressGenerator::next_address will be removed. /// Contract state kept in storage, separate from the contracts themselves (contract code). -pub(crate) const CONTRACTS: Map<&Addr, ContractData> = Map::new("contracts"); +const CONTRACTS: Map<&Addr, ContractData> = Map::new("contracts"); + +/// Wasm module namespace. +const NAMESPACE_WASM: &[u8] = b"wasm"; -//TODO Make `NAMESPACE_WASM` private in version 1.0 when the function AddressGenerator::next_address will be removed. -pub(crate) const NAMESPACE_WASM: &[u8] = b"wasm"; /// See const CONTRACT_ATTR: &str = "_contract_address"; @@ -1217,8 +1217,8 @@ mod test { use crate::{GovFailingModule, IbcFailingModule}; use cosmwasm_std::testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage}; use cosmwasm_std::{ - coin, from_json, to_json_vec, BankMsg, CanonicalAddr, Coin, CosmosMsg, Empty, HexBinary, - StdError, + coin, from_json, to_json_vec, BankMsg, CanonicalAddr, CodeInfoResponse, Coin, CosmosMsg, + Empty, HexBinary, StdError, }; /// Type alias for default build `Router` to make its reference in typical scenario @@ -1390,16 +1390,17 @@ mod test { let wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); + let creator = api.addr_make("creator"); + let code_id = wasm_keeper.store_code(creator.clone(), payout::contract()); let querier: MockQuerier = MockQuerier::new(&[]); let query = WasmQuery::CodeInfo { code_id }; let code_info = wasm_keeper .query(&api, &wasm_storage, &querier, &block, query) .unwrap(); - let actual: cosmwasm_std::CodeInfoResponse = from_json(code_info).unwrap(); + let actual: CodeInfoResponse = from_json(code_info).unwrap(); assert_eq!(code_id, actual.code_id); - assert_eq!("creator", actual.creator.to_string()); - assert_eq!(actual.checksum.to_string(), ""); + assert_eq!(creator.to_string(), actual.creator.to_string()); + assert_eq!(32, actual.checksum.as_slice().len()); } #[test] @@ -1424,8 +1425,8 @@ mod test { let code_info_caller = wasm_keeper .query(&api, &wasm_storage, &querier, &block, query_caller) .unwrap(); - let info_payout: cosmwasm_std::CodeInfoResponse = from_json(code_info_payout).unwrap(); - let info_caller: cosmwasm_std::CodeInfoResponse = from_json(code_info_caller).unwrap(); + let info_payout: CodeInfoResponse = from_json(code_info_payout).unwrap(); + let info_caller: CodeInfoResponse = from_json(code_info_caller).unwrap(); assert_eq!(code_id_payout, info_payout.code_id); assert_eq!(code_id_caller, info_caller.code_id); assert_ne!(info_caller.code_id, info_payout.code_id); @@ -1790,20 +1791,21 @@ mod test { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), caller::contract()); + let creator = api.addr_make("creator"); + let code_id = wasm_keeper.store_code(creator.clone(), caller::contract()); let mut wasm_storage = MockStorage::new(); - let admin: Addr = Addr::unchecked("admin"); - let new_admin: Addr = Addr::unchecked("new_admin"); - let normal_user: Addr = Addr::unchecked("normal_user"); + let admin = api.addr_make("admin"); + let new_admin = api.addr_make("new_admin"); + let normal_user = api.addr_make("normal_user"); let contract_addr = wasm_keeper .register_contract( &api, &mut wasm_storage, code_id, - Addr::unchecked("creator"), + creator, admin.clone(), "label".to_owned(), 1000, @@ -1904,18 +1906,20 @@ mod test { fn uses_simple_address_generator_by_default() { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); + let creator = api.addr_make("creator"); + let code_id = wasm_keeper.store_code(creator.clone(), payout::contract()); assert_eq!(1, code_id); let mut wasm_storage = MockStorage::new(); + let admin = api.addr_make("admin"); let contract_addr = wasm_keeper .register_contract( &api, &mut wasm_storage, code_id, - Addr::unchecked("foobar"), - Addr::unchecked("admin"), + creator.clone(), + admin.clone(), "label".to_owned(), 1000, None, @@ -1924,7 +1928,7 @@ mod test { assert_eq!( contract_addr.to_string(), - "contract0", + "cosmwasm1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsgn6fq2", "default address generator returned incorrect address" ); @@ -1935,8 +1939,8 @@ mod test { &api, &mut wasm_storage, code_id, - Addr::unchecked("foobar"), - Addr::unchecked("admin"), + creator, + admin.clone(), "label".to_owned(), 1000, Binary::from(salt.clone()), @@ -1945,24 +1949,22 @@ mod test { assert_eq!( contract_addr.to_string(), - format!( - "contract{}{}", - api.addr_canonicalize("foobar").unwrap(), - salt.to_hex() - ), + "cosmwasm1drhu6t78wacgm5qjzs4hvkv9fd9awa9henw7fh6vmzrhf7k2nkjsg3flns", "default address generator returned incorrect address" ); let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); assert_eq!(2, code_id); + let user = api.addr_make("boobaz"); + let contract_addr = wasm_keeper .register_contract( &api, &mut wasm_storage, code_id, - Addr::unchecked("boobaz"), - Addr::unchecked("admin"), + user, + admin, "label".to_owned(), 1000, Binary::from(salt.clone()), @@ -1971,11 +1973,7 @@ mod test { assert_eq!( contract_addr.to_string(), - format!( - "contract{}{}", - api.addr_canonicalize("boobaz").unwrap(), - salt.to_hex() - ), + "cosmwasm13cfeertf2gny0rzp5jwqzst8crmfgvcd2lq5su0c9z66yxa45qdsdd0uxc", "default address generator returned incorrect address" ); } @@ -2013,24 +2011,26 @@ mod test { #[test] fn can_use_custom_address_generator() { let api = MockApi::default(); - let expected_addr = Addr::unchecked("address"); - let expected_predictable_addr = Addr::unchecked("predictable_address"); + let expected_address = api.addr_make("address"); + let expected_predictable_address = api.addr_make("predictable_address"); let mut wasm_keeper: WasmKeeper = WasmKeeper::new().with_address_generator(TestAddressGenerator { - address: expected_addr.clone(), - predictable_address: expected_predictable_addr.clone(), + address: expected_address.clone(), + predictable_address: expected_predictable_address.clone(), }); - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); + let creator = api.addr_make("creator"); + let code_id = wasm_keeper.store_code(creator.clone(), payout::contract()); let mut wasm_storage = MockStorage::new(); + let admin = api.addr_make("admin"); let contract_addr = wasm_keeper .register_contract( &api, &mut wasm_storage, code_id, - Addr::unchecked("foobar"), - Addr::unchecked("admin"), + creator.clone(), + admin.clone(), "label".to_owned(), 1000, None, @@ -2038,7 +2038,7 @@ mod test { .unwrap(); assert_eq!( - contract_addr, expected_addr, + contract_addr, expected_address, "custom address generator returned incorrect address" ); @@ -2047,8 +2047,8 @@ mod test { &api, &mut wasm_storage, code_id, - Addr::unchecked("foobar"), - Addr::unchecked("admin"), + creator, + admin, "label".to_owned(), 1000, Binary::from(HexBinary::from_hex("23A74B8C").unwrap()), @@ -2056,24 +2056,8 @@ mod test { .unwrap(); assert_eq!( - contract_addr, expected_predictable_addr, + contract_addr, expected_predictable_address, "custom address generator returned incorrect address" ); } - - #[test] - #[allow(deprecated)] - fn remove_this_test_in_version_1_0() { - //TODO Remove this test in version 1.0.0 of multitest, now provided only for code coverage. - - let addr_gen = TestAddressGenerator { - address: Addr::unchecked("a"), - predictable_address: Addr::unchecked("b"), - }; - let mut storage = MockStorage::default(); - let contract_addr = addr_gen.next_address(&mut storage); - assert_eq!(contract_addr.to_string(), "contract0"); - - let _: WasmKeeper = WasmKeeper::new_with_custom_address_generator(addr_gen); - } } diff --git a/tests/test_wasm/test_with_addr_gen.rs b/tests/test_wasm/test_with_addr_gen.rs index af0035c4..e288a274 100644 --- a/tests/test_wasm/test_with_addr_gen.rs +++ b/tests/test_wasm/test_with_addr_gen.rs @@ -53,12 +53,6 @@ fn custom_address_generator_should_work() { struct CustomAddressGenerator; impl AddressGenerator for CustomAddressGenerator { - // deprecated since version 0.18.0 - fn next_address(&self, _storage: &mut dyn Storage) -> Addr { - // Panic in case of calling this function - unreachable!("this function should not be called") - } - // use this function instead of next_address fn contract_address( &self, From dced29389d5374d961b93e9dc15d199cf0676ca1 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 8 Feb 2024 10:31:33 +0100 Subject: [PATCH 049/250] Fixed bank tests. --- src/bank.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/bank.rs b/src/bank.rs index cefc0e24..f3a22c13 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -319,8 +319,8 @@ mod test { let querier: MockQuerier = MockQuerier::new(&[]); let router = MockRouter::default(); - let owner = Addr::unchecked("owner"); - let rcpt = Addr::unchecked("receiver"); + let owner = api.addr_make("owner"); + let rcpt = api.addr_make("receiver"); let init_funds = vec![coin(100, "eth"), coin(20, "btc")]; let norm = vec![coin(20, "btc"), coin(100, "eth")]; @@ -419,8 +419,8 @@ mod test { let block = mock_env().block; let router = MockRouter::default(); - let owner = Addr::unchecked("owner"); - let rcpt = Addr::unchecked("receiver"); + let owner = api.addr_make("owner"); + let rcpt = api.addr_make("receiver"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let rcpt_funds = vec![coin(5, "btc")]; @@ -472,8 +472,8 @@ mod test { let block = mock_env().block; let router = MockRouter::default(); - let owner = Addr::unchecked("owner"); - let rcpt = Addr::unchecked("recipient"); + let owner = api.addr_make("owner"); + let rcpt = api.addr_make("recipient"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; // set money @@ -583,8 +583,8 @@ mod test { let block = mock_env().block; let router = MockRouter::default(); - let owner = Addr::unchecked("owner"); - let rcpt = Addr::unchecked("recipient"); + let owner = api.addr_make("owner"); + let rcpt = api.addr_make("recipient"); let init_funds = vec![coin(5000, "atom"), coin(100, "eth")]; // set money From c61c1213b3f762f62b8a0c61df3168f82c1489c2 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 8 Feb 2024 11:01:08 +0100 Subject: [PATCH 050/250] Fixed staking tests. --- src/staking.rs | 120 ++++++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 61 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index cbcc45aa..b2442a4c 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1076,7 +1076,7 @@ mod test { let mut store = MockStorage::new(); let block = mock_env().block; - let validator = api.addr_validate("testvaloper1").unwrap(); + let validator_address = api.addr_make("testvaloper1"); router .staking @@ -1092,7 +1092,7 @@ mod test { // add validator let valoper1 = Validator::new( - "testvaloper1".to_string(), + validator_address.to_string(), validator_commission, Decimal::percent(100), Decimal::percent(1), @@ -1102,7 +1102,7 @@ mod test { .add_validator(&api, &mut store, &block, valoper1) .unwrap(); - (api, store, router, block, validator) + (api, store, router, block, validator_address) } #[test] @@ -1112,49 +1112,45 @@ mod test { let stake = StakeKeeper::default(); let block = mock_env().block; + let validator_address = api.addr_make("test-validator"); + // add validator - let valoper1 = Validator::new( - "testvaloper1".to_string(), + let validator = Validator::new( + validator_address.to_string(), Decimal::percent(10), Decimal::percent(20), Decimal::percent(1), ); stake - .add_validator(&api, &mut store, &block, valoper1.clone()) + .add_validator(&api, &mut store, &block, validator.clone()) .unwrap(); // get it let staking_storage = prefixed_read(&store, NAMESPACE_STAKING); let val = stake - .get_validator( - &staking_storage, - &api.addr_validate("testvaloper1").unwrap(), - ) + .get_validator(&staking_storage, &validator_address) .unwrap() .unwrap(); - assert_eq!(val, valoper1); + assert_eq!(val, validator); // try to add with same address - let valoper1_fake = Validator::new( - "testvaloper1".to_string(), + let validator_fake = Validator::new( + validator_address.to_string(), Decimal::percent(1), Decimal::percent(10), Decimal::percent(100), ); stake - .add_validator(&api, &mut store, &block, valoper1_fake) + .add_validator(&api, &mut store, &block, validator_fake) .unwrap_err(); // should still be original value let staking_storage = prefixed_read(&store, NAMESPACE_STAKING); let val = stake - .get_validator( - &staking_storage, - &api.addr_validate("testvaloper1").unwrap(), - ) + .get_validator(&staking_storage, &validator_address) .unwrap() .unwrap(); - assert_eq!(val, valoper1); + assert_eq!(val, validator); } #[test] @@ -1165,12 +1161,12 @@ mod test { let stake = StakeKeeper::new(); let block = mock_env().block; - let delegator = Addr::unchecked("delegator"); - let validator = api.addr_validate("testvaloper1").unwrap(); + let delegator_address = api.addr_make("delegator"); + let validator_address = api.addr_make("testvaloper1"); // add validator let valoper1 = Validator::new( - "testvaloper1".to_string(), + validator_address.to_string(), Decimal::percent(10), Decimal::percent(20), Decimal::percent(1), @@ -1186,8 +1182,8 @@ mod test { &api, &mut staking_storage, &block, - &delegator, - &validator, + &delegator_address, + &validator_address, coin(100, "TOKEN"), ) .unwrap(); @@ -1200,7 +1196,7 @@ mod test { &router, &block, StakingSudo::Slash { - validator: "testvaloper1".to_string(), + validator: validator_address.to_string(), percentage: Decimal::percent(50), }, ) @@ -1209,7 +1205,7 @@ mod test { // check stake let staking_storage = prefixed(&mut store, NAMESPACE_STAKING); let stake_left = stake - .get_stake(&staking_storage, &delegator, &validator) + .get_stake(&staking_storage, &delegator_address, &validator_address) .unwrap(); assert_eq!( stake_left.unwrap().amount.u128(), @@ -1225,7 +1221,7 @@ mod test { &router, &block, StakingSudo::Slash { - validator: "testvaloper1".to_string(), + validator: validator_address.to_string(), percentage: Decimal::percent(100), }, ) @@ -1234,18 +1230,18 @@ mod test { // check stake let staking_storage = prefixed(&mut store, NAMESPACE_STAKING); let stake_left = stake - .get_stake(&staking_storage, &delegator, &validator) + .get_stake(&staking_storage, &delegator_address, &validator_address) .unwrap(); assert_eq!(stake_left, None, "should have slashed whole stake"); } #[test] fn rewards_work_for_single_delegator() { - let (api, mut store, router, mut block, validator) = + let (api, mut store, router, mut block, validator_address) = setup_test_env(Decimal::percent(10), Decimal::percent(10)); let stake = &router.staking; let distr = &router.distribution; - let delegator = Addr::unchecked("delegator"); + let delegator_address = api.addr_make("delegator"); let mut staking_storage = prefixed(&mut store, NAMESPACE_STAKING); // stake 200 tokens @@ -1254,8 +1250,8 @@ mod test { &api, &mut staking_storage, &block, - &delegator, - &validator, + &delegator_address, + &validator_address, coin(200, "TOKEN"), ) .unwrap(); @@ -1265,7 +1261,7 @@ mod test { // should now have 200 * 10% / 2 - 10% commission = 9 tokens reward let rewards = stake - .get_rewards(&store, &block, &delegator, &validator) + .get_rewards(&store, &block, &delegator_address, &validator_address) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 9, "should have 9 tokens reward"); @@ -1277,16 +1273,16 @@ mod test { &mut store, &router, &block, - delegator.clone(), + delegator_address.clone(), DistributionMsg::WithdrawDelegatorReward { - validator: validator.to_string(), + validator: validator_address.to_string(), }, ) .unwrap(); // should have no rewards left let rewards = stake - .get_rewards(&store, &block, &delegator, &validator) + .get_rewards(&store, &block, &delegator_address, &validator_address) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 0); @@ -1295,7 +1291,7 @@ mod test { block.time = block.time.plus_seconds(60 * 60 * 24 * 365 / 2); // should now have 9 tokens again let rewards = stake - .get_rewards(&store, &block, &delegator, &validator) + .get_rewards(&store, &block, &delegator_address, &validator_address) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 9); @@ -1308,8 +1304,8 @@ mod test { let stake = &router.staking; let distr = &router.distribution; let bank = &router.bank; - let delegator1 = Addr::unchecked("delegator1"); - let delegator2 = Addr::unchecked("delegator2"); + let delegator1 = api.addr_make("delegator1"); + let delegator2 = api.addr_make("delegator2"); let mut staking_storage = prefixed(&mut store, NAMESPACE_STAKING); @@ -1556,8 +1552,8 @@ mod test { let (mut test_env, validator1) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator1 = Addr::unchecked("delegator1"); - let reward_receiver = Addr::unchecked("rewardreceiver"); + let delegator1 = test_env.api.addr_make("delegator1"); + let reward_receiver = test_env.api.addr_make("rewardreceiver"); // fund delegator1 account test_env @@ -1567,7 +1563,7 @@ mod test { .unwrap(); // add second validator - let validator2 = Addr::unchecked("validator2"); + let validator2 = test_env.api.addr_make("validator2"); test_env .router .staking @@ -1694,8 +1690,8 @@ mod test { let (mut test_env, validator) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator = Addr::unchecked("delegator"); - let reward_receiver = Addr::unchecked("rewardreceiver"); + let delegator = test_env.api.addr_make("delegator"); + let reward_receiver = test_env.api.addr_make("rewardreceiver"); test_env .router @@ -1774,7 +1770,7 @@ mod test { let (mut test_env, validator1) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator1 = Addr::unchecked("delegator1"); + let delegator1 = test_env.api.addr_make("delegator1"); // fund delegator1 account test_env @@ -1808,7 +1804,7 @@ mod test { assert_eq!(e.to_string(), "invalid shares amount"); // add second validator - let validator2 = Addr::unchecked("validator2"); + let validator2 = test_env.api.addr_make("validator2"); test_env .router .staking @@ -1890,7 +1886,8 @@ mod test { let (mut test_env, _) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator1 = Addr::unchecked("delegator1"); + let delegator1 = test_env.api.addr_make("delegator1"); + let non_existing_validator = test_env.api.addr_make("nonexistingvaloper"); // fund delegator1 account test_env @@ -1909,7 +1906,7 @@ mod test { &test_env.router, &test_env.block, StakingSudo::Slash { - validator: "nonexistingvaloper".to_string(), + validator: non_existing_validator.to_string(), percentage: Decimal::percent(50), }, ) @@ -1922,8 +1919,8 @@ mod test { let (mut test_env, _) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator = Addr::unchecked("delegator1"); - let validator = "testvaloper2"; + let delegator = test_env.api.addr_make("delegator1"); + let validator = test_env.api.addr_make("testvaloper2"); // init balances test_env @@ -1994,8 +1991,10 @@ mod test { // run all staking queries let (mut test_env, validator1) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator1 = Addr::unchecked("delegator1"); - let delegator2 = Addr::unchecked("delegator2"); + let delegator1 = test_env.api.addr_make("delegator1"); + let delegator2 = test_env.api.addr_make("delegator2"); + let validator2 = test_env.api.addr_make("testvaloper2"); + let not_validator = test_env.api.addr_make("notvaloper"); // init balances test_env @@ -2010,9 +2009,8 @@ mod test { .unwrap(); // add another validator - let validator2 = test_env.api.addr_validate("testvaloper2").unwrap(); let valoper2 = Validator::new( - "testvaloper2".to_string(), + validator2.to_string(), Decimal::percent(0), Decimal::percent(1), Decimal::percent(1), @@ -2046,7 +2044,7 @@ mod test { let response = query_stake::( &test_env, StakingQuery::Validator { - address: "notvaloper".to_string(), + address: not_validator.to_string(), }, ) .unwrap(); @@ -2153,8 +2151,8 @@ mod test { // run all staking queries let (mut test_env, validator) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator1 = Addr::unchecked("delegator1"); - let delegator2 = Addr::unchecked("delegator2"); + let delegator1 = test_env.api.addr_make("delegator1"); + let delegator2 = test_env.api.addr_make("delegator2"); // init balances test_env @@ -2282,7 +2280,7 @@ mod test { fn partial_unbonding_reduces_stake() { let (mut test_env, validator) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator = Addr::unchecked("delegator1"); + let delegator = test_env.api.addr_make("delegator1"); // init balance test_env @@ -2406,7 +2404,7 @@ mod test { // run all staking queries let (mut test_env, validator) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator = Addr::unchecked("delegator"); + let delegator = test_env.api.addr_make("delegator"); // init balance test_env @@ -2446,7 +2444,7 @@ mod test { &test_env.router, &test_env.block, StakingSudo::Slash { - validator: "testvaloper1".to_string(), + validator: validator.to_string(), percentage: Decimal::percent(50), }, ) @@ -2491,7 +2489,7 @@ mod test { fn rewards_initial_wait() { let (mut test_env, validator) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::zero())); - let delegator = Addr::unchecked("delegator"); + let delegator = test_env.api.addr_make("delegator"); // init balance test_env From 035da42aa891ee28eb06ee9f1a2b09dbce77a957 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 8 Feb 2024 11:22:39 +0100 Subject: [PATCH 051/250] Fixed some app errors. --- src/tests/test_app.rs | 120 ++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 69 deletions(-) diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 11154bcb..b526e3dd 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -9,7 +9,7 @@ use crate::{ custom_app, next_block, no_init, App, AppResponse, Bank, CosmosRouter, Distribution, Executor, Module, Router, Staking, Wasm, WasmSudo, }; -use cosmwasm_std::testing::{mock_env, MockQuerier}; +use cosmwasm_std::testing::{mock_env, MockApi, MockQuerier}; use cosmwasm_std::{ coin, coins, from_json, to_json_binary, Addr, AllBalanceResponse, Api, Attribute, BankMsg, BankQuery, Binary, BlockInfo, Coin, CosmosMsg, CustomMsg, CustomQuery, Empty, Event, @@ -105,8 +105,9 @@ fn update_block() { #[test] fn multi_level_bank_cache() { // set personal balance - let owner = Addr::unchecked("owner"); - let rcpt = Addr::unchecked("recipient"); + let api = MockApi::default(); + let owner = api.addr_make("owner"); + let rcpt = api.addr_make("recipient"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let mut app = App::new(|router, _, storage| { @@ -187,8 +188,9 @@ fn duplicate_contract_code() { #[test] fn send_tokens() { - let owner = Addr::unchecked("owner"); - let rcpt = Addr::unchecked("receiver"); + let api = MockApi::default(); + let owner = api.addr_make("owner"); + let rcpt = api.addr_make("receiver"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let rcpt_funds = vec![coin(5, "btc")]; @@ -235,7 +237,8 @@ fn send_tokens() { #[test] fn simple_contract() { // set personal balance - let owner = Addr::unchecked("owner"); + let api = MockApi::default(); + let owner = api.addr_make("owner"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let mut app = App::new(|router, _, storage| { @@ -251,7 +254,7 @@ fn simple_contract() { let msg = payout::InstantiateMessage { payout: coin(5, "eth"), }; - let contract_addr = app + let contract_address = app .instantiate_contract( code_id, owner.clone(), @@ -262,7 +265,7 @@ fn simple_contract() { ) .unwrap(); - let contract_data = app.contract_data(&contract_addr).unwrap(); + let contract_data = app.contract_data(&contract_address).unwrap(); assert_eq!( contract_data, ContractData { @@ -278,17 +281,22 @@ fn simple_contract() { let sender = get_balance(&app, &owner); assert_eq!(sender, vec![coin(20, "btc"), coin(77, "eth")]); // get contract address, has funds - let funds = get_balance(&app, &contract_addr); + let funds = get_balance(&app, &contract_address); assert_eq!(funds, coins(23, "eth")); // create empty account - let random = Addr::unchecked("random"); - let funds = get_balance(&app, &random); + let random_address = app.api().addr_make("random"); + let funds = get_balance(&app, &random_address); assert_eq!(funds, vec![]); // do one payout and see money coming in let res = app - .execute_contract(random.clone(), contract_addr.clone(), &Empty {}, &[]) + .execute_contract( + random_address.clone(), + contract_address.clone(), + &Empty {}, + &[], + ) .unwrap(); assert_eq!(3, res.events.len()); @@ -297,7 +305,7 @@ fn simple_contract() { assert_eq!(payout_exec.ty.as_str(), "execute"); assert_eq!( payout_exec.attributes, - [("_contract_address", &contract_addr)] + [("_contract_address", &contract_address)] ); // next is a custom wasm event @@ -306,16 +314,16 @@ fn simple_contract() { // then the transfer event let expected_transfer = Event::new("transfer") - .add_attribute("recipient", "random") - .add_attribute("sender", &contract_addr) + .add_attribute("recipient", &random_address) + .add_attribute("sender", &contract_address) .add_attribute("amount", "5eth"); assert_eq!(&expected_transfer, &res.events[2]); // random got cash - let funds = get_balance(&app, &random); + let funds = get_balance(&app, &random_address); assert_eq!(funds, coins(5, "eth")); // contract lost it - let funds = get_balance(&app, &contract_addr); + let funds = get_balance(&app, &contract_address); assert_eq!(funds, coins(18, "eth")); } @@ -428,7 +436,8 @@ fn reflect_success() { #[test] fn reflect_error() { // set personal balance - let owner = Addr::unchecked("owner"); + let api = MockApi::default(); + let owner = api.addr_make("owner"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let mut app = custom_app::(|router, _, storage| { @@ -455,18 +464,18 @@ fn reflect_error() { // reflect has 40 eth let funds = get_balance(&app, &reflect_addr); assert_eq!(funds, coins(40, "eth")); - let random = Addr::unchecked("random"); + let random_address = app.api().addr_make("random"); // sending 7 eth works let msg = SubMsg::new(BankMsg::Send { - to_address: random.clone().into(), + to_address: random_address.clone().into(), amount: coins(7, "eth"), }); let msgs = reflect::Message { messages: vec![msg], }; let res = app - .execute_contract(random.clone(), reflect_addr.clone(), &msgs, &[]) + .execute_contract(random_address.clone(), reflect_addr.clone(), &msgs, &[]) .unwrap(); // no wasm events as no attributes assert_eq!(2, res.events.len()); @@ -479,7 +488,7 @@ fn reflect_error() { assert_eq!(transfer.ty.as_str(), "transfer"); // ensure random got paid - let funds = get_balance(&app, &random); + let funds = get_balance(&app, &random_address); assert_eq!(funds, coins(7, "eth")); // reflect count should be updated to 1 @@ -491,18 +500,18 @@ fn reflect_error() { // sending 8 eth, then 3 btc should fail both let msg = SubMsg::new(BankMsg::Send { - to_address: random.clone().into(), + to_address: random_address.clone().into(), amount: coins(8, "eth"), }); let msg2 = SubMsg::new(BankMsg::Send { - to_address: random.clone().into(), + to_address: random_address.clone().into(), amount: coins(3, "btc"), }); let msgs = reflect::Message { messages: vec![msg, msg2], }; let err = app - .execute_contract(random.clone(), reflect_addr.clone(), &msgs, &[]) + .execute_contract(random_address.clone(), reflect_addr.clone(), &msgs, &[]) .unwrap_err(); assert_eq!( StdError::overflow(OverflowError::new(OverflowOperation::Sub)), @@ -510,7 +519,7 @@ fn reflect_error() { ); // first one should have been rolled-back on error (no second payment) - let funds = get_balance(&app, &random); + let funds = get_balance(&app, &random_address); assert_eq!(funds, coins(7, "eth")); // failure should not update reflect count @@ -673,12 +682,12 @@ fn send_update_admin_works() { // update admin succeeds if admin // update admin fails if not (new) admin // check admin set properly - let owner = Addr::unchecked("owner"); - let owner2 = Addr::unchecked("owner2"); - let beneficiary = Addr::unchecked("beneficiary"); - let mut app = App::default(); + let owner = app.api().addr_make("owner"); + let owner2 = app.api().addr_make("owner2"); + let beneficiary = app.api().addr_make("beneficiary"); + // create a hackatom contract with some funds let code_id = app.store_code(hackatom::contract()); @@ -805,8 +814,9 @@ fn sent_funds_properly_visible_on_execution() { // additional 20btc. Then beneficiary balance is checked - expected 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 owner = Addr::unchecked("owner"); - let beneficiary = Addr::unchecked("beneficiary"); + let api = MockApi::default(); + let owner = api.addr_make("owner"); + let beneficiary = api.addr_make("beneficiary"); let init_funds = coins(30, "btc"); let mut app = App::new(|router, _, storage| { @@ -950,9 +960,6 @@ mod custom_handler { // let's call this custom handler #[test] fn dispatches_messages() { - let winner = "winner".to_string(); - let second = "second".to_string(); - // payments. note 54321 - 12321 = 42000 let denom = "tix"; let lottery = coin(54321, denom); @@ -967,16 +974,20 @@ mod custom_handler { .unwrap(); }); + let winner = app.api().addr_make("winner"); + let second = app.api().addr_make("second"); + // query that balances are empty let start = app.wrap().query_balance(&winner, denom).unwrap(); assert_eq!(start, coin(0, denom)); // trigger the custom module let msg = CosmosMsg::Custom(CustomLotteryMsg { - lucky_winner: winner.clone(), - runner_up: second.clone(), + lucky_winner: winner.to_string(), + runner_up: second.to_string(), }); - app.execute(Addr::unchecked("anyone"), msg).unwrap(); + let anyone = app.api().addr_make("anyone"); + app.execute(anyone, msg).unwrap(); // see if coins were properly added let big_win = app.wrap().query_balance(&winner, denom).unwrap(); @@ -1063,7 +1074,7 @@ mod reply_data_overwrite { fn single_submsg() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1152,7 +1163,7 @@ mod reply_data_overwrite { fn single_no_top_level_data() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1969,32 +1980,3 @@ mod errors { assert_eq!(err.chain().count(), 4); } } - -mod api { - use super::*; - - #[test] - fn api_addr_validate_should_work() { - let app = App::default(); - let addr = app.api().addr_validate("creator").unwrap(); - assert_eq!(addr.to_string(), "creator"); - } - - #[test] - #[cfg(not(feature = "cosmwasm_1_5"))] - fn api_addr_canonicalize_should_work() { - let app = App::default(); - let canonical = app.api().addr_canonicalize("creator").unwrap(); - assert_eq!(canonical.to_string(), "0000000000000000000000000000726F0000000000000000000000000000000000000000006572000000000000000000000000000000000000000000610000000000000000000000000000000000000000006374000000000000"); - } - - #[test] - fn api_addr_humanize_should_work() { - let app = App::default(); - let canonical = app.api().addr_canonicalize("creator").unwrap(); - assert_eq!( - app.api().addr_humanize(&canonical).unwrap().to_string(), - "creator" - ); - } -} From 96e2c95338e8060140c5ab98674b451e3cd3e867 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 8 Feb 2024 11:41:41 +0100 Subject: [PATCH 052/250] Fixed some app errors. --- src/tests/test_app.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index b526e3dd..fb166438 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -1574,10 +1574,11 @@ mod contract_instantiation { // prepare application and actors let mut app = App::default(); - let sender = Addr::unchecked("sender"); + let sender = app.api().addr_make("sender"); + let creator = app.api().addr_make("creator"); // store contract's code - let code_id = app.store_code_with_creator(Addr::unchecked("creator"), echo::contract()); + let code_id = app.store_code_with_creator(creator, echo::contract()); // initialize the contract let init_msg = to_json_binary(&Empty {}).unwrap(); @@ -1600,11 +1601,7 @@ mod contract_instantiation { // in default address generator, this is like `contract` + salt in hex assert_eq!( parsed.contract_address, - format!( - "contract{}{}", - app.api().addr_canonicalize("sender").unwrap(), - salt.to_hex() - ), + "cosmwasm167g7x7auj3l00lhdcevusncx565ytz6a6xvmx2f5xuy84re9ddrqczpzkm", ); } } @@ -1616,11 +1613,12 @@ mod wasm_queries { fn query_existing_code_info() { use super::*; let mut app = App::default(); - let code_id = app.store_code_with_creator(Addr::unchecked("creator"), echo::contract()); + let creator = app.api().addr_make("creator"); + let code_id = app.store_code_with_creator(creator.clone(), echo::contract()); let code_info_response = app.wrap().query_wasm_code_info(code_id).unwrap(); assert_eq!(code_id, code_info_response.code_id); - assert_eq!("creator", code_info_response.creator.to_string()); - assert_eq!(code_info_response.checksum.to_string(), ""); + assert_eq!(creator.to_string(), code_info_response.creator.to_string()); + assert_eq!(32, code_info_response.checksum.as_slice().len()); } #[test] @@ -1651,8 +1649,8 @@ mod custom_messages { .with_custom(custom_handler) .build(no_init); - let sender = app.api().addr_validate("sender").unwrap(); - let owner = app.api().addr_validate("owner").unwrap(); + let sender = app.api().addr_make("sender"); + let owner = app.api().addr_make("owner"); let contract_id = app.store_code(echo::custom_contract()); From ade594948c7e2945bd0ddd18fae104b2df286e73 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 8 Feb 2024 15:22:22 +0100 Subject: [PATCH 053/250] Fixed all tests. --- src/addresses.rs | 26 ++++++++--------------- src/wasm.rs | 24 ++++----------------- tests/test_wasm/test_with_checksum_gen.rs | 12 +++++------ 3 files changed, 18 insertions(+), 44 deletions(-) diff --git a/src/addresses.rs b/src/addresses.rs index bd5c8b10..97df8865 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -33,17 +33,8 @@ pub trait AddressGenerator { /// /// let my_address_generator = MyAddressGenerator{}; /// - /// let addr = my_address_generator.contract_address(&api, &mut storage, 100, 0).unwrap(); - /// assert_eq!(addr.to_string(),"contract0"); - /// /// let addr = my_address_generator.contract_address(&api, &mut storage, 100, 1).unwrap(); - /// assert_eq!(addr.to_string(),"contract1"); - /// - /// let addr = my_address_generator.contract_address(&api, &mut storage, 200, 5).unwrap(); - /// assert_eq!(addr.to_string(),"contract5"); - /// - /// let addr = my_address_generator.contract_address(&api, &mut storage, 200, 6).unwrap(); - /// assert_eq!(addr.to_string(),"contract6"); + /// assert_eq!(addr.to_string(),"cosmwasm1vlc0q60lwcr89hkkkgj9u360fccw4a2jz48r3dgv0ulmlhgvjczsjfr2pk"); /// ``` fn contract_address( &self, @@ -67,7 +58,7 @@ pub trait AddressGenerator { /// # Example /// /// ``` - /// # use cosmwasm_std::Api; + /// # use cosmwasm_std::{Api, Checksum}; /// # use cosmwasm_std::testing::{MockApi, MockStorage}; /// # use cw_multi_test::{AddressGenerator, SimpleAddressGenerator}; /// # let api = MockApi::default(); @@ -78,15 +69,16 @@ pub trait AddressGenerator { /// /// let my_address_generator = MyAddressGenerator{}; /// - /// let creator1 = api.addr_canonicalize("creator1").unwrap(); - /// let creator2 = api.addr_canonicalize("creator2").unwrap(); + /// let creator1 = api.addr_canonicalize(&api.addr_make("creator1").to_string()).unwrap(); + /// let creator2 = api.addr_canonicalize(&api.addr_make("creator2").to_string()).unwrap(); /// let salt1 = [0xc0,0xff,0xee]; /// let salt2 = [0xbe,0xef]; + /// let chs = Checksum::generate(&[1]); /// - /// let addr11 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, &[1], &creator1, &salt1).unwrap(); - /// let addr12 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, &[1], &creator1, &salt2).unwrap(); - /// let addr21 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, &[1], &creator2, &salt1).unwrap(); - /// let addr22 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, &[1], &creator2, &salt2).unwrap(); + /// let addr11 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator1, &salt1).unwrap(); + /// let addr12 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator1, &salt2).unwrap(); + /// let addr21 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator2, &salt1).unwrap(); + /// let addr22 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator2, &salt2).unwrap(); /// /// assert_ne!(addr11, addr12); /// assert_ne!(addr11, addr21); diff --git a/src/wasm.rs b/src/wasm.rs index 13b12378..2a765448 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -383,22 +383,6 @@ where Self::default() } - #[deprecated( - since = "0.18.0", - note = "use `WasmKeeper::new().with_address_generator` instead; will be removed in version 1.0.0" - )] - /// Populates an existing [WasmKeeper] with custom contract address generator. - /// - /// See description of [with_address_generator](Self::with_address_generator) function for details. - pub fn new_with_custom_address_generator( - address_generator: impl AddressGenerator + 'static, - ) -> Self { - Self { - address_generator: Box::new(address_generator), - ..Default::default() - } - } - /// Populates an existing [WasmKeeper] with custom contract address generator. /// /// # Example @@ -442,15 +426,15 @@ where /// # Example /// /// ``` - /// use cosmwasm_std::{Addr, HexBinary}; + /// use cosmwasm_std::{Addr, Checksum, HexBinary}; /// use cw_multi_test::{AppBuilder, ChecksumGenerator, no_init, WasmKeeper}; /// /// struct MyChecksumGenerator; /// /// impl ChecksumGenerator for MyChecksumGenerator { - /// fn checksum(&self, creator: &Addr, code_id: u64) -> HexBinary { + /// fn checksum(&self, creator: &Addr, code_id: u64) -> Checksum { /// // here implement your custom checksum generator - /// # HexBinary::default() + /// # Checksum::from_hex("custom_checksum").unwrap() /// } /// } /// @@ -784,7 +768,7 @@ where gas_used: 0, result: SubMsgResult::Ok(SubMsgResponse { events: r.events.clone(), - data: None, + data: r.data, msg_responses: vec![], }), }; diff --git a/tests/test_wasm/test_with_checksum_gen.rs b/tests/test_wasm/test_with_checksum_gen.rs index 3540d304..2b47fdef 100644 --- a/tests/test_wasm/test_with_checksum_gen.rs +++ b/tests/test_wasm/test_with_checksum_gen.rs @@ -29,9 +29,8 @@ struct MyChecksumGenerator; impl ChecksumGenerator for MyChecksumGenerator { fn checksum(&self, _creator: &Addr, _code_id: u64) -> Checksum { - Checksum::generate( - "c0ffee01c0ffee02c0ffee03c0ffee04c0ffee05c0ffee06c0ffee07c0ffee08".as_bytes(), - ) + Checksum::from_hex("c0ffee01c0ffee02c0ffee03c0ffee04c0ffee05c0ffee06c0ffee07c0ffee08") + .unwrap() } } @@ -43,11 +42,10 @@ fn custom_checksum_generator_should_work() { // prepare application with custom wasm keeper let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init); + let creator_addr = app.api().addr_make("creator"); + // store contract's code - let code_id = app.store_code_with_creator( - Addr::unchecked("creator"), - test_contracts::counter::contract(), - ); + let code_id = app.store_code_with_creator(creator_addr, test_contracts::counter::contract()); // get code info let code_info_response = app.wrap().query_wasm_code_info(code_id).unwrap(); From 67fc152c1046c135d991a4b83053e7950de40bb2 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 8 Feb 2024 18:56:41 +0100 Subject: [PATCH 054/250] Bumped version. --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 338b85e3..8aa0081e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -241,7 +241,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "0.20.0" +version = "2.0.0" dependencies = [ "anyhow", "bech32", diff --git a/Cargo.toml b/Cargo.toml index d5449c41..b8da5bde 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "0.20.0" +version = "2.0.0" authors = ["Ethan Frey "] edition = "2021" description = "Testing tools for multi-contract interactions" From 4c912348fb81a19e075a2c3c5e05fc0c82b2d67a Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 8 Feb 2024 19:07:28 +0100 Subject: [PATCH 055/250] Removed features lower than 2.0 --- Cargo.toml | 6 +-- src/bank.rs | 51 ++++++++--------------- src/executor.rs | 1 - src/tests/test_app.rs | 4 -- src/wasm.rs | 5 --- tests/test_app/test_instantiate2.rs | 2 - tests/test_app_builder/test_with_wasm.rs | 1 - tests/test_wasm/test_with_addr_gen.rs | 2 - tests/test_wasm/test_with_checksum_gen.rs | 2 - 9 files changed, 18 insertions(+), 56 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b8da5bde..2bfd3697 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,11 +11,7 @@ homepage = "https://cosmwasm.com" [features] default = ["cosmwasm_2_0"] backtrace = ["anyhow/backtrace"] -cosmwasm_1_1 = ["cosmwasm-std/cosmwasm_1_1"] -cosmwasm_1_2 = ["cosmwasm_1_1", "cosmwasm-std/cosmwasm_1_2"] -cosmwasm_1_3 = ["cosmwasm_1_2", "cosmwasm-std/cosmwasm_1_3"] -cosmwasm_1_4 = ["cosmwasm_1_3", "cosmwasm-std/cosmwasm_1_4"] -cosmwasm_2_0 = ["cosmwasm_1_4", "cosmwasm-std/cosmwasm_2_0"] +cosmwasm_2_0 = ["cosmwasm-std/cosmwasm_2_0"] [dependencies] anyhow = "1.0.79" diff --git a/src/bank.rs b/src/bank.rs index f3a22c13..7da9ebab 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -4,13 +4,10 @@ use crate::executor::AppResponse; use crate::module::Module; use crate::prefixed_storage::{prefixed, prefixed_read}; use cosmwasm_std::{ - coin, to_json_binary, Addr, AllBalanceResponse, Api, BalanceResponse, BankMsg, BankQuery, - Binary, BlockInfo, Coin, Event, Querier, Storage, + coin, to_json_binary, Addr, AllBalanceResponse, AllDenomMetadataResponse, Api, BalanceResponse, + BankMsg, BankQuery, Binary, BlockInfo, Coin, DenomMetadata, DenomMetadataResponse, Event, + Order, Querier, StdResult, Storage, SupplyResponse, Uint128, }; -#[cfg(feature = "cosmwasm_1_3")] -use cosmwasm_std::{AllDenomMetadataResponse, DenomMetadata, DenomMetadataResponse}; -#[cfg(feature = "cosmwasm_1_1")] -use cosmwasm_std::{Order, StdResult, SupplyResponse, Uint128}; use cw_storage_plus::Map; use cw_utils::NativeBalance; use itertools::Itertools; @@ -20,7 +17,6 @@ use schemars::JsonSchema; const BALANCES: Map<&Addr, NativeBalance> = Map::new("balances"); /// Collection of metadata for denomination. -#[cfg(feature = "cosmwasm_1_3")] const DENOM_METADATA: Map = Map::new("metadata"); /// Default namespace for bank module. @@ -85,7 +81,6 @@ impl BankKeeper { } /// Administration function for adjusting denomination metadata. - #[cfg(feature = "cosmwasm_1_3")] pub fn set_denom_metadata( &self, bank_storage: &mut dyn Storage, @@ -103,7 +98,6 @@ impl BankKeeper { Ok(val.unwrap_or_default().into_vec()) } - #[cfg(feature = "cosmwasm_1_1")] fn get_supply(&self, bank_storage: &dyn Storage, denom: String) -> AnyResult { let supply: Uint128 = BALANCES .range(bank_storage, None, None, Order::Ascending) @@ -242,19 +236,16 @@ impl Module for BankKeeper { let res = BalanceResponse::new(amount); to_json_binary(&res).map_err(Into::into) } - #[cfg(feature = "cosmwasm_1_1")] BankQuery::Supply { denom } => { let amount = self.get_supply(&bank_storage, denom)?; let res = SupplyResponse::new(amount); to_json_binary(&res).map_err(Into::into) } - #[cfg(feature = "cosmwasm_1_3")] BankQuery::DenomMetadata { denom } => { let meta = DENOM_METADATA.may_load(storage, denom)?.unwrap_or_default(); let res = DenomMetadataResponse::new(meta); to_json_binary(&res).map_err(Into::into) } - #[cfg(feature = "cosmwasm_1_3")] BankQuery::AllDenomMetadata { pagination: _ } => { let mut metadata = vec![]; for key in DENOM_METADATA.keys(storage, None, None, Order::Ascending) { @@ -374,16 +365,13 @@ mod test { let res: BalanceResponse = from_json(raw).unwrap(); assert_eq!(res.amount, coin(0, "eth")); - #[cfg(feature = "cosmwasm_1_1")] - { - // Query total supply of a denom - let req = BankQuery::Supply { - denom: "eth".into(), - }; - let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); - let res: SupplyResponse = from_json(raw).unwrap(); - assert_eq!(res.amount, coin(100, "eth")); - } + // Query total supply of a denom + let req = BankQuery::Supply { + denom: "eth".into(), + }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: SupplyResponse = from_json(raw).unwrap(); + assert_eq!(res.amount, coin(100, "eth")); // Mint tokens for recipient account let msg = BankSudo::Mint { @@ -400,16 +388,13 @@ mod test { let res: AllBalanceResponse = from_json(raw).unwrap(); assert_eq!(res.amount, norm); - #[cfg(feature = "cosmwasm_1_1")] - { - // Check that the total supply of a denom is updated - let req = BankQuery::Supply { - denom: "eth".into(), - }; - let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); - let res: SupplyResponse = from_json(raw).unwrap(); - assert_eq!(res.amount, coin(200, "eth")); - } + // Check that the total supply of a denom is updated + let req = BankQuery::Supply { + denom: "eth".into(), + }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: SupplyResponse = from_json(raw).unwrap(); + assert_eq!(res.amount, coin(200, "eth")); } #[test] @@ -511,7 +496,6 @@ mod test { } #[test] - #[cfg(feature = "cosmwasm_1_3")] fn set_get_denom_metadata_should_work() { let api = MockApi::default(); let mut store = MockStorage::new(); @@ -539,7 +523,6 @@ mod test { } #[test] - #[cfg(feature = "cosmwasm_1_3")] fn set_get_all_denom_metadata_should_work() { let api = MockApi::default(); let mut store = MockStorage::new(); diff --git a/src/executor.rs b/src/executor.rs index 9892ef74..6aed234a 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -106,7 +106,6 @@ where /// Instantiates a new contract and returns its predictable address. /// This is a helper function around [execute][Self::execute] function /// with `WasmMsg::Instantiate2` message. - #[cfg(feature = "cosmwasm_1_2")] fn instantiate2_contract( &mut self, code_id: u64, diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index fb166438..963ec0ff 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -166,7 +166,6 @@ fn multi_level_bank_cache() { } #[test] -#[cfg(feature = "cosmwasm_1_2")] fn duplicate_contract_code() { // set up the multi-test application let mut app = App::default(); @@ -1568,7 +1567,6 @@ mod response_validation { mod contract_instantiation { #[test] - #[cfg(feature = "cosmwasm_1_2")] fn instantiate2_works() { use super::*; @@ -1609,7 +1607,6 @@ mod contract_instantiation { mod wasm_queries { #[test] - #[cfg(feature = "cosmwasm_1_2")] fn query_existing_code_info() { use super::*; let mut app = App::default(); @@ -1622,7 +1619,6 @@ mod wasm_queries { } #[test] - #[cfg(feature = "cosmwasm_1_2")] fn query_non_existing_code_info() { use super::*; let app = App::default(); diff --git a/src/wasm.rs b/src/wasm.rs index 2a765448..770fd9f7 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -186,7 +186,6 @@ where ); to_json_binary(&res).map_err(Into::into) } - #[cfg(feature = "cosmwasm_1_2")] WasmQuery::CodeInfo { code_id } => { let code_data = self.code_data(code_id)?; let res = cosmwasm_std::CodeInfoResponse::new( @@ -591,7 +590,6 @@ where } => self.process_wasm_msg_instantiate( api, storage, router, block, sender, admin, code_id, msg, funds, label, None, ), - #[cfg(feature = "cosmwasm_1_2")] WasmMsg::Instantiate2 { admin, code_id, @@ -1368,7 +1366,6 @@ mod test { } #[test] - #[cfg(feature = "cosmwasm_1_2")] fn query_code_info() { let api = MockApi::default(); let wasm_storage = MockStorage::new(); @@ -1388,7 +1385,6 @@ mod test { } #[test] - #[cfg(feature = "cosmwasm_1_2")] fn different_contracts_must_have_different_checksum() { let api = MockApi::default(); let wasm_storage = MockStorage::new(); @@ -1419,7 +1415,6 @@ mod test { } #[test] - #[cfg(feature = "cosmwasm_1_2")] fn querying_invalid_code_info_must_fail() { let api = MockApi::default(); let wasm_storage = MockStorage::new(); diff --git a/tests/test_app/test_instantiate2.rs b/tests/test_app/test_instantiate2.rs index cec92ad6..c0e7f191 100644 --- a/tests/test_app/test_instantiate2.rs +++ b/tests/test_app/test_instantiate2.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "cosmwasm_1_2")] - use crate::test_contracts::counter; use cosmwasm_std::{instantiate2_address, to_json_binary, Api, Empty, WasmMsg}; use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; diff --git a/tests/test_app_builder/test_with_wasm.rs b/tests/test_app_builder/test_with_wasm.rs index 13f4b05f..c668c36a 100644 --- a/tests/test_app_builder/test_with_wasm.rs +++ b/tests/test_app_builder/test_with_wasm.rs @@ -140,7 +140,6 @@ fn building_app_with_custom_wasm_should_work() { ); // executing wasm query should return an error defined in custom keeper - #[cfg(feature = "cosmwasm_1_2")] assert_eq!( format!("Generic error: Querier contract error: {}", QUERY_MSG), app.wrap() diff --git a/tests/test_wasm/test_with_addr_gen.rs b/tests/test_wasm/test_with_addr_gen.rs index e288a274..0fb5ae72 100644 --- a/tests/test_wasm/test_with_addr_gen.rs +++ b/tests/test_wasm/test_with_addr_gen.rs @@ -89,7 +89,6 @@ fn custom_address_generator_should_work() { } #[test] -#[cfg(feature = "cosmwasm_1_2")] fn predictable_contract_address_should_work() { // prepare wasm module with custom address generator let wasm_keeper: WasmKeeper = @@ -147,7 +146,6 @@ fn predictable_contract_address_should_work() { } #[test] -#[cfg(feature = "cosmwasm_1_2")] fn creating_contract_with_the_same_predictable_address_should_fail() { // prepare wasm module with custom address generator let wasm_keeper: WasmKeeper = diff --git a/tests/test_wasm/test_with_checksum_gen.rs b/tests/test_wasm/test_with_checksum_gen.rs index 2b47fdef..426112b3 100644 --- a/tests/test_wasm/test_with_checksum_gen.rs +++ b/tests/test_wasm/test_with_checksum_gen.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "cosmwasm_1_2")] - use crate::test_contracts; use cosmwasm_std::{Addr, Checksum}; use cw_multi_test::{no_init, App, AppBuilder, ChecksumGenerator, WasmKeeper}; From a5f7933131fa2ecbfe400824a40df77cd1c388c6 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 8 Feb 2024 19:08:21 +0100 Subject: [PATCH 056/250] Updates. --- src/bank.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bank.rs b/src/bank.rs index 7da9ebab..1843c7e3 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -19,7 +19,7 @@ const BALANCES: Map<&Addr, NativeBalance> = Map::new("balances"); /// Collection of metadata for denomination. const DENOM_METADATA: Map = Map::new("metadata"); -/// Default namespace for bank module. +/// Default storage namespace for bank module. pub const NAMESPACE_BANK: &[u8] = b"bank"; /// A message representing privileged actions in bank module. From 267e3c292f3848195b5920e2041452cad097293f Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 8 Feb 2024 19:20:46 +0100 Subject: [PATCH 057/250] Refactored tests. --- tests/test_app_builder/test_with_distribution.rs | 11 ++++++----- tests/test_module/test_accepting_module.rs | 12 +++++++----- tests/test_module/test_failing_module.rs | 14 ++++++++------ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/tests/test_app_builder/test_with_distribution.rs b/tests/test_app_builder/test_with_distribution.rs index 23139ec7..fe6a6f46 100644 --- a/tests/test_app_builder/test_with_distribution.rs +++ b/tests/test_app_builder/test_with_distribution.rs @@ -1,5 +1,5 @@ use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; -use cosmwasm_std::{Addr, DistributionMsg, Empty}; +use cosmwasm_std::{DistributionMsg, Empty}; use cw_multi_test::{no_init, AppBuilder, Distribution, Executor}; type MyDistributionKeeper = MyKeeper; @@ -20,16 +20,17 @@ fn building_app_with_custom_distribution_should_work() { .with_distribution(distribution_keeper) .build(no_init); - // prepare additional input data - let recipient = Addr::unchecked("recipient"); + // prepare addresses + let recipient_addr = app.api().addr_make("recipient"); + let sender_addr = app.api().addr_make("sender"); // executing distribution message should return an error defined in custom keeper assert_eq!( EXECUTE_MSG, app.execute( - Addr::unchecked("sender"), + sender_addr, DistributionMsg::SetWithdrawAddress { - address: recipient.into(), + address: recipient_addr.into(), } .into(), ) diff --git a/tests/test_module/test_accepting_module.rs b/tests/test_module/test_accepting_module.rs index 1952b412..9f085b5b 100644 --- a/tests/test_module/test_accepting_module.rs +++ b/tests/test_module/test_accepting_module.rs @@ -1,5 +1,5 @@ use cosmwasm_std::testing::MockStorage; -use cosmwasm_std::{Addr, Binary, Empty}; +use cosmwasm_std::{Binary, Empty}; use cw_multi_test::{AcceptingModule, App, AppResponse, Module}; /// Utility function for comparing responses. @@ -11,6 +11,8 @@ fn eq(actual: AppResponse, expected: AppResponse) { /// Utility function for asserting default outputs returned from accepting module. fn assert_results(accepting_module: AcceptingModule) { let app = App::default(); + let sender_addr = app.api().addr_make("sender"); + let empty_msg = Empty {}; let mut storage = MockStorage::default(); eq( AppResponse::default(), @@ -20,8 +22,8 @@ fn assert_results(accepting_module: AcceptingModule) { &mut storage, app.router(), &app.block_info(), - Addr::unchecked("sender"), - Empty {}, + sender_addr, + empty_msg.clone(), ) .unwrap(), ); @@ -33,7 +35,7 @@ fn assert_results(accepting_module: AcceptingModule) { &storage, &(*app.wrap()), &app.block_info(), - Empty {} + empty_msg.clone() ) .unwrap() ); @@ -45,7 +47,7 @@ fn assert_results(accepting_module: AcceptingModule) { &mut storage, app.router(), &app.block_info(), - Empty {}, + empty_msg, ) .unwrap(), ); diff --git a/tests/test_module/test_failing_module.rs b/tests/test_module/test_failing_module.rs index 64c5a2ca..d8f01279 100644 --- a/tests/test_module/test_failing_module.rs +++ b/tests/test_module/test_failing_module.rs @@ -1,21 +1,23 @@ use cosmwasm_std::testing::MockStorage; -use cosmwasm_std::{Addr, Empty}; +use cosmwasm_std::Empty; use cw_multi_test::{App, FailingModule, Module}; /// Utility function for asserting outputs returned from failing module. fn assert_results(failing_module: FailingModule) { let app = App::default(); + let sender_addr = app.api().addr_make("sender"); + let empty_msg = Empty {}; let mut storage = MockStorage::default(); assert_eq!( - r#"Unexpected exec msg Empty from Addr("sender")"#, + format!(r#"Unexpected exec msg Empty from Addr("{}")"#, sender_addr), failing_module .execute( app.api(), &mut storage, app.router(), &app.block_info(), - Addr::unchecked("sender"), - Empty {} + sender_addr, + empty_msg.clone() ) .unwrap_err() .to_string() @@ -28,7 +30,7 @@ fn assert_results(failing_module: FailingModule) { &storage, &(*app.wrap()), &app.block_info(), - Empty {} + empty_msg.clone() ) .unwrap_err() .to_string() @@ -41,7 +43,7 @@ fn assert_results(failing_module: FailingModule) { &mut storage, app.router(), &app.block_info(), - Empty {} + empty_msg ) .unwrap_err() .to_string() From 4e9e9ab68dc79d2f928ee84f81364bb90752cd72 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 8 Feb 2024 19:23:09 +0100 Subject: [PATCH 058/250] Updates. --- src/checksums.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/checksums.rs b/src/checksums.rs index d5a38536..f5c641f6 100644 --- a/src/checksums.rs +++ b/src/checksums.rs @@ -1,4 +1,4 @@ -//! # Implementation of the interface to custom checksum generator +//! # Implementation of checksum generator use cosmwasm_std::{Addr, Checksum}; From cd6c1c22a9f6b834a69adb156cfbf2ac7c64807a Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 09:09:21 +0100 Subject: [PATCH 059/250] Refactoring. --- tests/test_app_builder/test_with_gov.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/test_app_builder/test_with_gov.rs b/tests/test_app_builder/test_with_gov.rs index 76faf582..d086674c 100644 --- a/tests/test_app_builder/test_with_gov.rs +++ b/tests/test_app_builder/test_with_gov.rs @@ -1,5 +1,5 @@ use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; -use cosmwasm_std::{Addr, Empty, GovMsg, VoteOption}; +use cosmwasm_std::{Empty, GovMsg, VoteOption}; use cw_multi_test::{no_init, AppBuilder, Executor, Gov}; type MyGovKeeper = MyKeeper; @@ -10,18 +10,21 @@ const EXECUTE_MSG: &str = "gov execute called"; #[test] fn building_app_with_custom_gov_should_work() { - // build custom gov keeper (no query and sudo handling for gov) + // build custom governance keeper (no query and sudo handling for gov module) let gov_keeper = MyGovKeeper::new(EXECUTE_MSG, NO_MESSAGE, NO_MESSAGE); // build the application with custom gov keeper let app_builder = AppBuilder::default(); let mut app = app_builder.with_gov(gov_keeper).build(no_init); - // executing gov message should return an error defined in custom keeper + // prepare addresses + let sender_addr = app.api().addr_make("sender"); + + // executing governance message should return an error defined in custom keeper assert_eq!( EXECUTE_MSG, app.execute( - Addr::unchecked("sender"), + sender_addr, GovMsg::Vote { proposal_id: 1, option: VoteOption::Yes, From 5882979436efd2b8f85bca5b010c1ce95f8c2a37 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 09:33:26 +0100 Subject: [PATCH 060/250] Refactoring. --- tests/test_app_builder/test_with_api.rs | 14 ++++----- tests/test_app_builder/test_with_bank.rs | 15 ++++++---- tests/test_wasm/test_with_addr_gen.rs | 35 +++++++++++------------ tests/test_wasm/test_with_checksum_gen.rs | 11 +++---- 4 files changed, 38 insertions(+), 37 deletions(-) diff --git a/tests/test_app_builder/test_with_api.rs b/tests/test_app_builder/test_with_api.rs index c96184d4..26be8e25 100644 --- a/tests/test_app_builder/test_with_api.rs +++ b/tests/test_app_builder/test_with_api.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Addr, Api, CanonicalAddr, HexBinary}; +use cosmwasm_std::{Api, CanonicalAddr, HexBinary}; use cw_multi_test::addons::MockApiBech32; use cw_multi_test::{no_init, AppBuilder}; @@ -15,10 +15,7 @@ fn building_app_with_custom_api_should_work() { .build(no_init); // check address validation function - assert_eq!( - app.api().addr_validate(human).unwrap(), - Addr::unchecked(human) - ); + assert_eq!(human, app.api().addr_validate(human).unwrap().as_str()); // check if address can be canonicalized assert_eq!( @@ -28,12 +25,13 @@ fn building_app_with_custom_api_should_work() { // check if address can be humanized assert_eq!( + human, app.api() .addr_humanize(&app.api().addr_canonicalize(human).unwrap()) - .unwrap(), - Addr::unchecked(human) + .unwrap() + .as_str(), ); // check extension function for creating Bech32 encoded addresses - assert_eq!(app.api().addr_make("creator"), Addr::unchecked(human)); + assert_eq!(human, app.api().addr_make("creator").as_str()); } diff --git a/tests/test_app_builder/test_with_bank.rs b/tests/test_app_builder/test_with_bank.rs index fa9f1758..3aba13fd 100644 --- a/tests/test_app_builder/test_with_bank.rs +++ b/tests/test_app_builder/test_with_bank.rs @@ -1,5 +1,5 @@ use crate::test_app_builder::MyKeeper; -use cosmwasm_std::{coins, Addr, BankMsg, BankQuery}; +use cosmwasm_std::{coins, BankMsg, BankQuery}; use cw_multi_test::{no_init, AppBuilder, Bank, BankSudo, Executor}; type MyBankKeeper = MyKeeper; @@ -19,17 +19,20 @@ fn building_app_with_custom_bank_should_work() { let app_builder = AppBuilder::default(); let mut app = app_builder.with_bank(bank_keeper).build(no_init); + // prepare user addresses + let recipient_addr = app.api().addr_make("recipient"); + let sender_addr = app.api().addr_make("sender"); + // prepare additional input data - let recipient = Addr::unchecked("recipient"); let denom = "eth"; // executing bank message should return an error defined in custom keeper assert_eq!( EXECUTE_MSG, app.execute( - Addr::unchecked("sender"), + sender_addr, BankMsg::Send { - to_address: recipient.clone().into(), + to_address: recipient_addr.clone().into(), amount: coins(1, denom), } .into(), @@ -43,7 +46,7 @@ fn building_app_with_custom_bank_should_work() { SUDO_MSG, app.sudo( BankSudo::Mint { - to_address: recipient.clone().into(), + to_address: recipient_addr.clone().into(), amount: vec![], } .into() @@ -56,7 +59,7 @@ fn building_app_with_custom_bank_should_work() { assert_eq!( format!("Generic error: Querier contract error: {}", QUERY_MSG), app.wrap() - .query_balance(recipient, denom) + .query_balance(recipient_addr, denom) .unwrap_err() .to_string() ); diff --git a/tests/test_wasm/test_with_addr_gen.rs b/tests/test_wasm/test_with_addr_gen.rs index 0fb5ae72..24b53bf6 100644 --- a/tests/test_wasm/test_with_addr_gen.rs +++ b/tests/test_wasm/test_with_addr_gen.rs @@ -1,5 +1,4 @@ use cosmwasm_std::{Addr, Api, Empty, Storage}; - use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; use cw_multi_test::error::AnyResult; use cw_multi_test::{no_init, AddressGenerator, AppBuilder, Executor, WasmKeeper}; @@ -12,17 +11,17 @@ fn contract_address_should_work() { let wasm_keeper: WasmKeeper = WasmKeeper::new().with_address_generator(MockAddressGenerator); - // prepare application with custom api + // prepare application with custom API let mut app = AppBuilder::default() .with_api(MockApiBech32::new("purple")) .with_wasm(wasm_keeper) .build(no_init); + // prepare user addresses + let creator_addr = app.api().addr_make("creator"); + // store contract's code - let code_id = app.store_code_with_creator( - Addr::unchecked("creator"), - test_contracts::counter::contract(), - ); + let code_id = app.store_code_with_creator(creator_addr, test_contracts::counter::contract()); let owner = app.api().addr_make("owner"); @@ -50,10 +49,10 @@ fn contract_address_should_work() { #[test] fn custom_address_generator_should_work() { + // prepare custom address generator struct CustomAddressGenerator; impl AddressGenerator for CustomAddressGenerator { - // use this function instead of next_address fn contract_address( &self, _api: &dyn Api, @@ -61,31 +60,31 @@ fn custom_address_generator_should_work() { _code_id: u64, _instance_id: u64, ) -> AnyResult { - Ok(Addr::unchecked("test_address")) + Ok(MockApiBech32::new("osmo").addr_make("test_addr")) } } // prepare wasm module with custom address generator let wasm_keeper = WasmKeeper::new().with_address_generator(CustomAddressGenerator); + // prepare application with custom wasm keeper let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init); + // prepare user addresses + let owner_addr = app.api().addr_make("owner"); + // store contract's code let code_id = app.store_code(test_contracts::counter::contract()); let contract_addr = app - .instantiate_contract( - code_id, - Addr::unchecked("owner"), - &Empty {}, - &[], - "Counter", - None, - ) + .instantiate_contract(code_id, owner_addr, &Empty {}, &[], "Counter", None) .unwrap(); - // make sure that contract address equals to "test_address" generated by custom address generator - assert_eq!(contract_addr.as_str(), "test_address"); + // make sure that contract address equals to value generated by custom address generator + assert_eq!( + contract_addr.as_str(), + MockApiBech32::new("osmo").addr_make("test_addr").as_str() + ); } #[test] diff --git a/tests/test_wasm/test_with_checksum_gen.rs b/tests/test_wasm/test_with_checksum_gen.rs index 426112b3..47685d31 100644 --- a/tests/test_wasm/test_with_checksum_gen.rs +++ b/tests/test_wasm/test_with_checksum_gen.rs @@ -7,16 +7,16 @@ fn default_checksum_generator_should_work() { // prepare default application with default wasm keeper let mut app = App::default(); + // prepare user addresses + let creator_addr = app.api().addr_make("creator"); + // store contract's code - let code_id = app.store_code_with_creator( - Addr::unchecked("creator"), - test_contracts::counter::contract(), - ); + let code_id = app.store_code_with_creator(creator_addr, test_contracts::counter::contract()); // get code info let code_info_response = app.wrap().query_wasm_code_info(code_id).unwrap(); - // this should be default checksum + // this should be a default checksum assert_eq!( code_info_response.checksum.to_hex(), "27095b438f70aed35405149bc5e8dfa1d461f7cd9c25359807ad66dcc1396fc7" @@ -40,6 +40,7 @@ fn custom_checksum_generator_should_work() { // prepare application with custom wasm keeper let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init); + // prepare user addresses let creator_addr = app.api().addr_make("creator"); // store contract's code From 883ef5e34c008dc3f2a42638ef575b0e256063f8 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 10:02:46 +0100 Subject: [PATCH 061/250] Updates. --- src/staking.rs | 26 ++++++----- src/tests/test_app.rs | 46 ++++++++++---------- src/wasm.rs | 20 ++++----- tests/test_app_builder/test_with_ibc.rs | 7 ++- tests/test_app_builder/test_with_staking.rs | 13 +++--- tests/test_app_builder/test_with_stargate.rs | 17 ++++++-- tests/test_app_builder/test_with_storage.rs | 10 +++-- tests/test_app_builder/test_with_wasm.rs | 7 +-- 8 files changed, 84 insertions(+), 62 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index b2442a4c..136c8483 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1852,24 +1852,28 @@ mod test { #[test] fn denom_validation() { - let (mut test_env, validator) = + let (mut test_env, validator_addr) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator1 = Addr::unchecked("delegator1"); + let delegator_addr = test_env.api.addr_make("delegator"); // fund delegator1 account test_env .router .bank - .init_balance(&mut test_env.store, &delegator1, vec![coin(100, "FAKE")]) + .init_balance( + &mut test_env.store, + &delegator_addr, + vec![coin(100, "FAKE")], + ) .unwrap(); - // try to delegate 100 to validator1 + // try to delegate 100 to validator let e = execute_stake( &mut test_env, - delegator1.clone(), + delegator_addr.clone(), StakingMsg::Delegate { - validator: validator.to_string(), + validator: validator_addr.to_string(), amount: coin(100, "FAKE"), }, ) @@ -1886,14 +1890,14 @@ mod test { let (mut test_env, _) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator1 = test_env.api.addr_make("delegator1"); + let delegator = test_env.api.addr_make("delegator"); let non_existing_validator = test_env.api.addr_make("nonexistingvaloper"); // fund delegator1 account test_env .router .bank - .init_balance(&mut test_env.store, &delegator1, vec![coin(100, "FAKE")]) + .init_balance(&mut test_env.store, &delegator, vec![coin(100, "FAKE")]) .unwrap(); // try to delegate 100 to validator1 @@ -1959,12 +1963,12 @@ mod test { let (mut test_env, validator) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator = Addr::unchecked("delegator1"); + let delegator_addr = test_env.api.addr_make("delegator"); // delegate 0 let err = execute_stake( &mut test_env, - delegator.clone(), + delegator_addr.clone(), StakingMsg::Delegate { validator: validator.to_string(), amount: coin(0, "TOKEN"), @@ -1976,7 +1980,7 @@ mod test { // undelegate 0 let err = execute_stake( &mut test_env, - delegator, + delegator_addr, StakingMsg::Undelegate { validator: validator.to_string(), amount: coin(0, "TOKEN"), diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 963ec0ff..f865741d 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -94,33 +94,32 @@ where #[test] fn update_block() { let mut app = App::default(); - let BlockInfo { time, height, .. } = app.block_info(); app.update_block(next_block); - assert_eq!(time.plus_seconds(5), app.block_info().time); assert_eq!(height + 1, app.block_info().height); } #[test] fn multi_level_bank_cache() { - // set personal balance + // prepare user addresses let api = MockApi::default(); - let owner = api.addr_make("owner"); - let rcpt = api.addr_make("recipient"); - let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; + let owner_addr = api.addr_make("owner"); + let recipient_addr = api.addr_make("recipient"); + // set personal balance + let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let mut app = App::new(|router, _, storage| { router .bank - .init_balance(storage, &owner, init_funds) + .init_balance(storage, &owner_addr, init_funds) .unwrap(); }); // cache 1 - send some tokens let mut cache = StorageTransaction::new(app.storage()); let msg = BankMsg::Send { - to_address: rcpt.clone().into(), + to_address: recipient_addr.clone().into(), amount: coins(25, "eth"), }; app.router() @@ -128,31 +127,31 @@ fn multi_level_bank_cache() { app.api(), &mut cache, &app.block_info(), - owner.clone(), + owner_addr.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, &recipient_addr); assert_eq!(coins(25, "eth"), cached_rcpt); - let router_rcpt = query_app(&app, &rcpt); + let router_rcpt = query_app(&app, &recipient_addr); assert_eq!(router_rcpt, vec![]); // now, second level cache transactional(&mut cache, |cache2, read| { let msg = BankMsg::Send { - to_address: rcpt.clone().into(), + to_address: recipient_addr.clone().into(), amount: coins(12, "eth"), }; app.router() - .execute(app.api(), cache2, &app.block_info(), owner, msg.into()) + .execute(app.api(), cache2, &app.block_info(), owner_addr, 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, &recipient_addr); 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, &recipient_addr); assert_eq!(coins(37, "eth"), cached2_rcpt); Ok(()) }) @@ -161,7 +160,7 @@ fn multi_level_bank_cache() { // apply first to router cache.prepare().commit(app.storage_mut()); - let committed = query_app(&app, &rcpt); + let committed = query_app(&app, &recipient_addr); assert_eq!(coins(37, "eth"), committed); } @@ -328,14 +327,17 @@ fn simple_contract() { #[test] fn reflect_success() { + // prepare user addresses + let api = MockApi::default(); + let owner_addr = api.addr_make("owner"); + let random_addr = api.addr_make("random"); + // set personal balance - let owner = Addr::unchecked("owner"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; - let mut app = custom_app::(|router, _, storage| { router .bank - .init_balance(storage, &owner, init_funds) + .init_balance(storage, &owner_addr, init_funds) .unwrap(); }); @@ -348,7 +350,7 @@ fn reflect_success() { let payout_addr = app .instantiate_contract( payout_id, - owner.clone(), + owner_addr.clone(), &msg, &coins(23, "eth"), "Payout", @@ -360,7 +362,7 @@ fn reflect_success() { let reflect_id = app.store_code(reflect::contract()); let reflect_addr = app - .instantiate_contract(reflect_id, owner, &Empty {}, &[], "Reflect", None) + .instantiate_contract(reflect_id, owner_addr, &Empty {}, &[], "Reflect", None) .unwrap(); // reflect account is empty @@ -383,7 +385,7 @@ fn reflect_success() { messages: vec![msg], }; let res = app - .execute_contract(Addr::unchecked("random"), reflect_addr.clone(), &msgs, &[]) + .execute_contract(random_addr, reflect_addr.clone(), &msgs, &[]) .unwrap(); // ensure the attributes were relayed from the sub-message diff --git a/src/wasm.rs b/src/wasm.rs index 770fd9f7..a960b7c6 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1885,8 +1885,8 @@ mod test { fn uses_simple_address_generator_by_default() { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); - let creator = api.addr_make("creator"); - let code_id = wasm_keeper.store_code(creator.clone(), payout::contract()); + let creator_addr = api.addr_make("creator"); + let code_id = wasm_keeper.store_code(creator_addr.clone(), payout::contract()); assert_eq!(1, code_id); let mut wasm_storage = MockStorage::new(); @@ -1897,7 +1897,7 @@ mod test { &api, &mut wasm_storage, code_id, - creator.clone(), + creator_addr.clone(), admin.clone(), "label".to_owned(), 1000, @@ -1906,7 +1906,7 @@ mod test { .unwrap(); assert_eq!( - contract_addr.to_string(), + contract_addr.as_str(), "cosmwasm1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsgn6fq2", "default address generator returned incorrect address" ); @@ -1918,7 +1918,7 @@ mod test { &api, &mut wasm_storage, code_id, - creator, + creator_addr.clone(), admin.clone(), "label".to_owned(), 1000, @@ -1927,22 +1927,22 @@ mod test { .unwrap(); assert_eq!( - contract_addr.to_string(), + contract_addr.as_str(), "cosmwasm1drhu6t78wacgm5qjzs4hvkv9fd9awa9henw7fh6vmzrhf7k2nkjsg3flns", "default address generator returned incorrect address" ); - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); + let code_id = wasm_keeper.store_code(creator_addr, payout::contract()); assert_eq!(2, code_id); - let user = api.addr_make("boobaz"); + let user_addr = api.addr_make("boobaz"); let contract_addr = wasm_keeper .register_contract( &api, &mut wasm_storage, code_id, - user, + user_addr, admin, "label".to_owned(), 1000, @@ -1951,7 +1951,7 @@ mod test { .unwrap(); assert_eq!( - contract_addr.to_string(), + contract_addr.as_str(), "cosmwasm13cfeertf2gny0rzp5jwqzst8crmfgvcd2lq5su0c9z66yxa45qdsdd0uxc", "default address generator returned incorrect address" ); diff --git a/tests/test_app_builder/test_with_ibc.rs b/tests/test_app_builder/test_with_ibc.rs index 431570e0..a39ec0a5 100644 --- a/tests/test_app_builder/test_with_ibc.rs +++ b/tests/test_app_builder/test_with_ibc.rs @@ -1,5 +1,5 @@ use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; -use cosmwasm_std::{Addr, Empty, IbcMsg, IbcQuery, QueryRequest}; +use cosmwasm_std::{Empty, IbcMsg, IbcQuery, QueryRequest}; use cw_multi_test::{no_init, AppBuilder, Executor, Ibc}; type MyIbcKeeper = MyKeeper; @@ -18,11 +18,14 @@ fn building_app_with_custom_ibc_should_work() { let app_builder = AppBuilder::default(); let mut app = app_builder.with_ibc(ibc_keeper).build(no_init); + // prepare user addresses + let sender_addr = app.api().addr_make("sender"); + // executing ibc message should return an error defined in custom keeper assert_eq!( EXECUTE_MSG, app.execute( - Addr::unchecked("sender"), + sender_addr, IbcMsg::CloseChannel { channel_id: "my-channel".to_string() } diff --git a/tests/test_app_builder/test_with_staking.rs b/tests/test_app_builder/test_with_staking.rs index 9dc8c38f..784bab95 100644 --- a/tests/test_app_builder/test_with_staking.rs +++ b/tests/test_app_builder/test_with_staking.rs @@ -1,5 +1,5 @@ use crate::test_app_builder::MyKeeper; -use cosmwasm_std::{Addr, Api, BlockInfo, Coin, CustomQuery, StakingMsg, StakingQuery, Storage}; +use cosmwasm_std::{Api, BlockInfo, Coin, CustomQuery, StakingMsg, StakingQuery, Storage}; use cw_multi_test::error::AnyResult; use cw_multi_test::{ no_init, AppBuilder, AppResponse, CosmosRouter, Executor, Staking, StakingSudo, @@ -33,16 +33,17 @@ fn building_app_with_custom_staking_should_work() { let app_builder = AppBuilder::default(); let mut app = app_builder.with_staking(stake_keeper).build(no_init); - // prepare additional input data - let validator = Addr::unchecked("recipient"); + // prepare addresses + let validator_addr = app.api().addr_make("validator"); + let sender_addr = app.api().addr_make("sender"); // executing staking message should return an error defined in custom keeper assert_eq!( EXECUTE_MSG, app.execute( - Addr::unchecked("sender"), + sender_addr, StakingMsg::Delegate { - validator: validator.clone().into(), + validator: validator_addr.clone().into(), amount: Coin::new(1_u32, "eth"), } .into(), @@ -56,7 +57,7 @@ fn building_app_with_custom_staking_should_work() { SUDO_MSG, app.sudo( StakingSudo::Slash { - validator: validator.into(), + validator: validator_addr.into(), percentage: Default::default(), } .into() diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index d5216c5b..80b0fe60 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -1,5 +1,5 @@ use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; -use cosmwasm_std::{to_json_vec, Addr, AnyMsg, CosmosMsg, Empty, GrpcQuery, QueryRequest}; +use cosmwasm_std::{to_json_vec, AnyMsg, CosmosMsg, Empty, GrpcQuery, QueryRequest}; use cw_multi_test::{ no_init, AppBuilder, Executor, Stargate, StargateAcceptingModule, StargateFailingModule, StargateMsg, StargateQuery, @@ -21,11 +21,14 @@ fn building_app_with_custom_stargate_should_work() { let app_builder = AppBuilder::default(); let mut app = app_builder.with_stargate(stargate_keeper).build(no_init); + // prepare user addresses + let sender_addr = app.api().addr_make("sender"); + // executing stargate message should return // an error defined in custom stargate keeper assert_eq!( app.execute( - Addr::unchecked("sender"), + sender_addr, CosmosMsg::Any(AnyMsg { type_url: "test".to_string(), value: Default::default() @@ -58,8 +61,11 @@ fn building_app_with_accepting_stargate_should_work() { .with_stargate(StargateAcceptingModule::new()) .build(no_init); + // prepare user addresses + let sender_addr = app.api().addr_make("sender"); + app.execute( - Addr::unchecked("sender"), + sender_addr, CosmosMsg::Any(AnyMsg { type_url: "test".to_string(), value: Default::default(), @@ -83,8 +89,11 @@ fn building_app_with_failing_stargate_should_work() { .with_stargate(StargateFailingModule::new()) .build(no_init); + // prepare user addresses + let sender_addr = app.api().addr_make("sender"); + app.execute( - Addr::unchecked("sender"), + sender_addr, CosmosMsg::Any(AnyMsg { type_url: "test".to_string(), value: Default::default(), diff --git a/tests/test_app_builder/test_with_storage.rs b/tests/test_app_builder/test_with_storage.rs index b6106d7f..72f8998f 100644 --- a/tests/test_app_builder/test_with_storage.rs +++ b/tests/test_app_builder/test_with_storage.rs @@ -1,5 +1,5 @@ use crate::{test_contracts, CounterQueryMsg, CounterResponseMsg}; -use cosmwasm_std::{to_json_binary, Addr, Empty, Order, Record, Storage, WasmMsg}; +use cosmwasm_std::{to_json_binary, Empty, Order, Record, Storage, WasmMsg}; use cw_multi_test::{no_init, AppBuilder, Executor}; use std::collections::BTreeMap; use std::iter; @@ -34,7 +34,6 @@ impl Storage for MyStorage { #[test] fn building_app_with_custom_storage_should_work() { // prepare additional test input data - let owner = Addr::unchecked("owner"); let msg = to_json_binary(&Empty {}).unwrap(); let admin = None; let funds = vec![]; @@ -46,6 +45,9 @@ fn building_app_with_custom_storage_should_work() { .with_storage(MyStorage::default()) .build(no_init); + // prepare user addresses + let owner_addr = app.api().addr_make("owner"); + // store a contract code let code_id = app.store_code(test_contracts::counter::contract()); @@ -53,7 +55,7 @@ fn building_app_with_custom_storage_should_work() { let contract_addr = app .instantiate_contract( code_id, - owner.clone(), + owner_addr.clone(), &WasmMsg::Instantiate { admin: admin.clone(), code_id, @@ -69,7 +71,7 @@ fn building_app_with_custom_storage_should_work() { // execute contract, this increments a counter app.execute_contract( - owner, + owner_addr, contract_addr.clone(), &WasmMsg::Execute { contract_addr: contract_addr.clone().into(), diff --git a/tests/test_app_builder/test_with_wasm.rs b/tests/test_app_builder/test_with_wasm.rs index c668c36a..31e772e8 100644 --- a/tests/test_app_builder/test_with_wasm.rs +++ b/tests/test_app_builder/test_with_wasm.rs @@ -86,8 +86,9 @@ fn building_app_with_custom_wasm_should_work() { let app_builder = AppBuilder::default(); let mut app = app_builder.with_wasm(wasm_keeper).build(no_init); - // prepare additional input data - let contract_addr = Addr::unchecked("contract"); + // prepare addresses + let contract_addr = app.api().addr_make("contract"); + let sender_addr = app.api().addr_make("sender"); // calling store_code should return value defined in custom keeper assert_eq!(CODE_ID, app.store_code(test_contracts::counter::contract())); @@ -111,7 +112,7 @@ fn building_app_with_custom_wasm_should_work() { assert_eq!( EXECUTE_MSG, app.execute( - Addr::unchecked("sender"), + sender_addr, WasmMsg::Instantiate { admin: None, code_id: 0, From 382209fdb282789dfed7f0d64169546518c3db24 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 10:03:15 +0100 Subject: [PATCH 062/250] Updates. --- src/tests/test_app.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index f865741d..fff5c63a 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -188,7 +188,7 @@ fn duplicate_contract_code() { fn send_tokens() { let api = MockApi::default(); let owner = api.addr_make("owner"); - let rcpt = api.addr_make("receiver"); + let rcpt = api.addr_make("recipient"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let rcpt_funds = vec![coin(5, "btc")]; From e2fb1596cecdf35ae23ed420eb1e928303924737 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 10:06:06 +0100 Subject: [PATCH 063/250] Refactoring. --- src/tests/test_app.rs | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index fff5c63a..7c78e671 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -186,63 +186,66 @@ fn duplicate_contract_code() { #[test] fn send_tokens() { + // prepare user addresses let api = MockApi::default(); - let owner = api.addr_make("owner"); - let rcpt = api.addr_make("recipient"); + let owner_addr = api.addr_make("owner"); + let recipient_addr = api.addr_make("recipient"); + + // set personal balance let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let rcpt_funds = vec![coin(5, "btc")]; - let mut app = App::new(|router, _, storage| { // initialization moved to App construction router .bank - .init_balance(storage, &owner, init_funds) + .init_balance(storage, &owner_addr, init_funds) .unwrap(); router .bank - .init_balance(storage, &rcpt, rcpt_funds) + .init_balance(storage, &recipient_addr, rcpt_funds) .unwrap(); }); // send both tokens let to_send = vec![coin(30, "eth"), coin(5, "btc")]; let msg: CosmosMsg = BankMsg::Send { - to_address: rcpt.clone().into(), + to_address: recipient_addr.clone().into(), amount: to_send, } .into(); - app.execute(owner.clone(), msg.clone()).unwrap(); - let rich = get_balance(&app, &owner); + app.execute(owner_addr.clone(), msg.clone()).unwrap(); + let rich = get_balance(&app, &owner_addr); assert_eq!(vec![coin(15, "btc"), coin(70, "eth")], rich); - let poor = get_balance(&app, &rcpt); + let poor = get_balance(&app, &recipient_addr); assert_eq!(vec![coin(10, "btc"), coin(30, "eth")], poor); // can send from other account (but funds will be deducted from sender) - app.execute(rcpt.clone(), msg).unwrap(); + app.execute(recipient_addr.clone(), msg).unwrap(); // cannot send too much let msg = BankMsg::Send { - to_address: rcpt.into(), + to_address: recipient_addr.into(), amount: coins(20, "btc"), } .into(); - app.execute(owner.clone(), msg).unwrap_err(); + app.execute(owner_addr.clone(), msg).unwrap_err(); - let rich = get_balance(&app, &owner); + let rich = get_balance(&app, &owner_addr); assert_eq!(vec![coin(15, "btc"), coin(70, "eth")], rich); } #[test] fn simple_contract() { - // set personal balance + // prepare user addresses let api = MockApi::default(); - let owner = api.addr_make("owner"); - let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; + let owner_addr = api.addr_make("owner"); + // set personal balance + let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let mut app = App::new(|router, _, storage| { router .bank - .init_balance(storage, &owner, init_funds) + .init_balance(storage, &owner_addr, init_funds) .unwrap(); }); @@ -255,7 +258,7 @@ fn simple_contract() { let contract_address = app .instantiate_contract( code_id, - owner.clone(), + owner_addr.clone(), &msg, &coins(23, "eth"), "Payout", @@ -268,7 +271,7 @@ fn simple_contract() { contract_data, ContractData { code_id, - creator: owner.clone(), + creator: owner_addr.clone(), admin: None, label: "Payout".to_owned(), created: app.block_info().height @@ -276,7 +279,7 @@ fn simple_contract() { ); // sender funds deducted - let sender = get_balance(&app, &owner); + let sender = get_balance(&app, &owner_addr); assert_eq!(sender, vec![coin(20, "btc"), coin(77, "eth")]); // get contract address, has funds let funds = get_balance(&app, &contract_address); From ef317c13de9369400ed39ab454f6abbc6b6066ab Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 10:47:13 +0100 Subject: [PATCH 064/250] Refactoring. --- src/app.rs | 11 +- src/tests/test_app.rs | 205 +++++++++++++++++++------------ src/tests/test_custom_handler.rs | 7 +- src/wasm.rs | 44 ++++--- 4 files changed, 162 insertions(+), 105 deletions(-) diff --git a/src/app.rs b/src/app.rs index cbaeab20..87676864 100644 --- a/src/app.rs +++ b/src/app.rs @@ -255,21 +255,18 @@ where /// 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 { - self.init_modules(|router, _, _| { - router - .wasm - .store_code(Addr::unchecked("code-creator"), code) - }) + let creator_addr = MockApi::default().addr_make("creator"); + self.init_modules(|router, _, _| router.wasm.store_code(creator_addr, code)) } /// Registers contract code (like [store_code](Self::store_code)), /// but takes the address of the code creator as an additional argument. pub fn store_code_with_creator( &mut self, - creator: Addr, + creator_addr: Addr, code: Box>, ) -> u64 { - self.init_modules(|router, _, _| router.wasm.store_code(creator, code)) + self.init_modules(|router, _, _| router.wasm.store_code(creator_addr, code)) } /// Duplicates the contract code identified by `code_id` and returns diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 7c78e671..1ba604a5 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -91,6 +91,11 @@ where val.amount } +/// Utility function for generating user addresses. +fn addr_make(addr: &str) -> Addr { + MockApi::default().addr_make(addr) +} + #[test] fn update_block() { let mut app = App::default(); @@ -103,9 +108,8 @@ fn update_block() { #[test] fn multi_level_bank_cache() { // prepare user addresses - let api = MockApi::default(); - let owner_addr = api.addr_make("owner"); - let recipient_addr = api.addr_make("recipient"); + let owner_addr = addr_make("owner"); + let recipient_addr = addr_make("recipient"); // set personal balance let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; @@ -187,9 +191,8 @@ fn duplicate_contract_code() { #[test] fn send_tokens() { // prepare user addresses - let api = MockApi::default(); - let owner_addr = api.addr_make("owner"); - let recipient_addr = api.addr_make("recipient"); + let owner_addr = addr_make("owner"); + let recipient_addr = addr_make("recipient"); // set personal balance let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; @@ -237,8 +240,7 @@ fn send_tokens() { #[test] fn simple_contract() { // prepare user addresses - let api = MockApi::default(); - let owner_addr = api.addr_make("owner"); + let owner_addr = addr_make("owner"); // set personal balance let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; @@ -331,9 +333,8 @@ fn simple_contract() { #[test] fn reflect_success() { // prepare user addresses - let api = MockApi::default(); - let owner_addr = api.addr_make("owner"); - let random_addr = api.addr_make("random"); + let owner_addr = addr_make("owner"); + let random_addr = addr_make("random"); // set personal balance let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; @@ -439,11 +440,11 @@ fn reflect_success() { #[test] fn reflect_error() { + // prepare user addresses + let owner = addr_make("owner"); + // set personal balance - let api = MockApi::default(); - let owner = api.addr_make("owner"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; - let mut app = custom_app::(|router, _, storage| { router .bank @@ -536,13 +537,15 @@ fn reflect_error() { #[test] fn sudo_works() { - let owner = Addr::unchecked("owner"); - let init_funds = vec![coin(100, "eth")]; + // prepare user addresses + let owner_addr = addr_make("owner"); + // set personal balance + let init_funds = vec![coin(100, "eth")]; let mut app = App::new(|router, _, storage| { router .bank - .init_balance(storage, &owner, init_funds) + .init_balance(storage, &owner_addr, init_funds) .unwrap(); }); @@ -552,7 +555,14 @@ fn sudo_works() { payout: coin(5, "eth"), }; let payout_addr = app - .instantiate_contract(payout_id, owner, &msg, &coins(23, "eth"), "Payout", None) + .instantiate_contract( + payout_id, + owner_addr, + &msg, + &coins(23, "eth"), + "Payout", + None, + ) .unwrap(); // count is 1 @@ -590,11 +600,12 @@ fn sudo_works() { #[test] fn reflect_sub_message_reply_works() { + // prepare user addresses + let owner = addr_make("owner"); + let random = addr_make("random"); + // set personal balance - let owner = Addr::unchecked("owner"); - let random = Addr::unchecked("random"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; - let mut app = custom_app::(|router, _, storage| { router .bank @@ -688,9 +699,9 @@ fn send_update_admin_works() { // check admin set properly let mut app = App::default(); - let owner = app.api().addr_make("owner"); - let owner2 = app.api().addr_make("owner2"); - let beneficiary = app.api().addr_make("beneficiary"); + let owner = addr_make("owner"); + let owner2 = addr_make("owner2"); + let beneficiary = addr_make("beneficiary"); // create a hackatom contract with some funds let code_id = app.store_code(hackatom::contract()); @@ -750,14 +761,18 @@ fn sent_wasm_migration_works() { // migrate fails if not admin // migrate succeeds if admin // check beneficiary updated - let owner = Addr::unchecked("owner"); - let beneficiary = Addr::unchecked("beneficiary"); - let init_funds = coins(30, "btc"); + // prepare user addresses + let owner_addr = addr_make("owner"); + let beneficiary_addr = addr_make("beneficiary"); + let random_addr = addr_make("random"); + + // set personal balance + let init_funds = coins(30, "btc"); let mut app = App::new(|router, _, storage| { router .bank - .init_balance(storage, &owner, init_funds) + .init_balance(storage, &owner_addr, init_funds) .unwrap(); }); @@ -767,40 +782,44 @@ fn sent_wasm_migration_works() { let contract = app .instantiate_contract( code_id, - owner.clone(), + owner_addr.clone(), &hackatom::InstantiateMsg { - beneficiary: beneficiary.as_str().to_owned(), + beneficiary: beneficiary_addr.as_str().to_owned(), }, &coins(20, "btc"), "Hackatom", - Some(owner.to_string()), + Some(owner_addr.to_string()), ) .unwrap(); // check admin set properly let info = app.contract_data(&contract).unwrap(); - assert_eq!(info.admin, Some(owner.clone())); + assert_eq!(info.admin, Some(owner_addr.clone())); // check beneficiary set properly let state: hackatom::InstantiateMsg = app .wrap() .query_wasm_smart(&contract, &hackatom::QueryMsg::Beneficiary {}) .unwrap(); - assert_eq!(state.beneficiary, beneficiary.to_string()); + assert_eq!(state.beneficiary, beneficiary_addr.to_string()); // migrate fails if not admin - let random = Addr::unchecked("random"); let migrate_msg = hackatom::MigrateMsg { - new_guy: random.to_string(), + new_guy: random_addr.to_string(), }; - app.migrate_contract(beneficiary, contract.clone(), &migrate_msg, code_id) + app.migrate_contract(beneficiary_addr, contract.clone(), &migrate_msg, code_id) .unwrap_err(); // migrate fails if unregistered code id - app.migrate_contract(owner.clone(), contract.clone(), &migrate_msg, code_id + 7) - .unwrap_err(); + app.migrate_contract( + owner_addr.clone(), + contract.clone(), + &migrate_msg, + code_id + 7, + ) + .unwrap_err(); // migrate succeeds when the stars align - app.migrate_contract(owner, contract.clone(), &migrate_msg, code_id) + app.migrate_contract(owner_addr, contract.clone(), &migrate_msg, code_id) .unwrap(); // check beneficiary updated @@ -808,7 +827,7 @@ fn sent_wasm_migration_works() { .wrap() .query_wasm_smart(&contract, &hackatom::QueryMsg::Beneficiary {}) .unwrap(); - assert_eq!(state.beneficiary, random.to_string()); + assert_eq!(state.beneficiary, random_addr.to_string()); } #[test] @@ -818,15 +837,17 @@ fn sent_funds_properly_visible_on_execution() { // additional 20btc. Then beneficiary balance is checked - expected 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 api = MockApi::default(); - let owner = api.addr_make("owner"); - let beneficiary = api.addr_make("beneficiary"); - let init_funds = coins(30, "btc"); + // prepare user addresses + let owner_addr = addr_make("owner"); + let beneficiary_addr = addr_make("beneficiary"); + + // set personal balance + let init_funds = coins(30, "btc"); let mut app = App::new(|router, _, storage| { router .bank - .init_balance(storage, &owner, init_funds) + .init_balance(storage, &owner_addr, init_funds) .unwrap(); }); @@ -835,9 +856,9 @@ fn sent_funds_properly_visible_on_execution() { let contract = app .instantiate_contract( code_id, - owner.clone(), + owner_addr.clone(), &hackatom::InstantiateMsg { - beneficiary: beneficiary.as_str().to_owned(), + beneficiary: beneficiary_addr.as_str().to_owned(), }, &coins(10, "btc"), "Hackatom", @@ -846,7 +867,7 @@ fn sent_funds_properly_visible_on_execution() { .unwrap(); app.execute_contract( - owner.clone(), + owner_addr.clone(), contract.clone(), &Empty {}, &coins(20, "btc"), @@ -855,9 +876,9 @@ fn sent_funds_properly_visible_on_execution() { // Check balance of all accounts to ensure no tokens where burned or created, and they are // in correct places - assert_eq!(get_balance(&app, &owner), &[]); + assert_eq!(get_balance(&app, &owner_addr), &[]); assert_eq!(get_balance(&app, &contract), &[]); - assert_eq!(get_balance(&app, &beneficiary), coins(30, "btc")); + assert_eq!(get_balance(&app, &beneficiary_addr), coins(30, "btc")); } /// Demonstrates that we can mint tokens and send from other accounts @@ -1051,7 +1072,7 @@ mod reply_data_overwrite { fn no_submsg() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1111,7 +1132,7 @@ mod reply_data_overwrite { fn single_submsg_no_reply() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1139,7 +1160,7 @@ mod reply_data_overwrite { fn single_no_submsg_data() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1197,10 +1218,11 @@ mod reply_data_overwrite { #[test] fn single_submsg_reply_returns_none() { + // prepare user addresses + let owner = addr_make("owner"); + // set personal balance - let owner = Addr::unchecked("owner"); let init_funds = coins(100, "tgd"); - let mut app = custom_app::(|router, _, storage| { router .bank @@ -1255,7 +1277,7 @@ mod reply_data_overwrite { fn multiple_submsg() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1298,7 +1320,7 @@ mod reply_data_overwrite { fn multiple_submsg_no_reply() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1331,7 +1353,7 @@ mod reply_data_overwrite { fn multiple_submsg_mixed() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1369,7 +1391,7 @@ mod reply_data_overwrite { fn nested_submsg() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1422,7 +1444,7 @@ mod response_validation { fn empty_attribute_key() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1453,7 +1475,7 @@ mod response_validation { fn empty_attribute_value() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1484,7 +1506,7 @@ mod response_validation { fn empty_event_attribute_key() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1514,7 +1536,7 @@ mod response_validation { fn empty_event_attribute_value() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1544,7 +1566,7 @@ mod response_validation { fn too_short_event_type() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1687,10 +1709,11 @@ mod protobuf_wrapped_data { #[test] fn instantiate_wrapped_properly() { + // prepare user addresses + let owner = addr_make("owner"); + // set personal balance - let owner = Addr::unchecked("owner"); let init_funds = vec![coin(20, "btc")]; - let mut app = custom_app::(|router, _, storage| { router .bank @@ -1725,9 +1748,10 @@ mod protobuf_wrapped_data { #[test] fn instantiate_with_data_works() { - let owner = Addr::unchecked("owner"); let mut app = BasicApp::new(no_init); + let owner = app.api().addr_make("owner"); + // set up echo contract let code_id = app.store_code(echo::contract()); @@ -1754,9 +1778,10 @@ mod protobuf_wrapped_data { #[test] fn instantiate_with_reply_works() { - let owner = Addr::unchecked("owner"); let mut app = BasicApp::new(no_init); + let owner = app.api().addr_make("owner"); + // set up echo contract let code_id = app.store_code(echo::contract()); @@ -1806,9 +1831,10 @@ mod protobuf_wrapped_data { #[test] fn execute_wrapped_properly() { - let owner = Addr::unchecked("owner"); let mut app = BasicApp::new(no_init); + let owner = app.api().addr_make("owner"); + // set up reflect contract let code_id = app.store_code(echo::contract()); @@ -1833,9 +1859,10 @@ mod errors { #[test] fn simple_instantiation() { - let owner = Addr::unchecked("owner"); let mut app = App::default(); + let owner = app.api().addr_make("owner"); + // set up contract let code_id = app.store_code(error::contract(false)); @@ -1859,9 +1886,11 @@ mod errors { #[test] fn simple_call() { - let owner = Addr::unchecked("owner"); let mut app = App::default(); + let owner = app.api().addr_make("owner"); + let random_addr = app.api().addr_make("random"); + // set up contract let code_id = app.store_code(error::contract(true)); @@ -1872,7 +1901,7 @@ mod errors { // execute should error let err = app - .execute_contract(Addr::unchecked("random"), contract_addr, &msg, &[]) + .execute_contract(random_addr, contract_addr, &msg, &[]) .unwrap_err(); // we should be able to retrieve the original error by downcasting @@ -1890,9 +1919,11 @@ mod errors { #[test] fn nested_call() { - let owner = Addr::unchecked("owner"); let mut app = App::default(); + let owner = app.api().addr_make("owner"); + let random_addr = app.api().addr_make("random"); + let error_code_id = app.store_code(error::contract(true)); let caller_code_id = app.store_code(caller::contract()); @@ -1912,7 +1943,7 @@ mod errors { funds: vec![], }; let err = app - .execute_contract(Addr::unchecked("random"), caller_addr, &msg, &[]) + .execute_contract(random_addr, caller_addr, &msg, &[]) .unwrap_err(); // we can get the original error by downcasting @@ -1930,22 +1961,38 @@ mod errors { #[test] fn double_nested_call() { - let owner = Addr::unchecked("owner"); let mut app = App::default(); + let owner_addr = app.api().addr_make("owner"); + let random_addr = app.api().addr_make("random"); + let error_code_id = app.store_code(error::contract(true)); let caller_code_id = app.store_code(caller::contract()); // set up contract_helpers let msg = Empty {}; let caller_addr1 = app - .instantiate_contract(caller_code_id, owner.clone(), &msg, &[], "caller", None) + .instantiate_contract( + caller_code_id, + owner_addr.clone(), + &msg, + &[], + "caller", + None, + ) .unwrap(); let caller_addr2 = app - .instantiate_contract(caller_code_id, owner.clone(), &msg, &[], "caller", None) + .instantiate_contract( + caller_code_id, + owner_addr.clone(), + &msg, + &[], + "caller", + None, + ) .unwrap(); let error_addr = app - .instantiate_contract(error_code_id, owner, &msg, &[], "error", None) + .instantiate_contract(error_code_id, owner_addr, &msg, &[], "error", None) .unwrap(); // caller1 calls caller2, caller2 calls error @@ -1960,7 +2007,7 @@ mod errors { funds: vec![], }; let err = app - .execute_contract(Addr::unchecked("random"), caller_addr1, &msg, &[]) + .execute_contract(random_addr, caller_addr1, &msg, &[]) .unwrap_err(); // uncomment to have the test fail and see how the error stringifies diff --git a/src/tests/test_custom_handler.rs b/src/tests/test_custom_handler.rs index 36168264..5ba0d70e 100644 --- a/src/tests/test_custom_handler.rs +++ b/src/tests/test_custom_handler.rs @@ -2,7 +2,7 @@ use crate::custom_handler::CachingCustomHandler; use crate::test_helpers::CustomHelperMsg; use crate::{App, Module}; use cosmwasm_std::testing::MockStorage; -use cosmwasm_std::{Addr, Empty}; +use cosmwasm_std::Empty; ///Custom handlers in CosmWasm allow developers to incorporate their own unique logic into tests. ///This feature is valuable for tailoring the testing environment to reflect specific @@ -16,13 +16,16 @@ fn custom_handler_works() { // create custom handler let custom_handler = CachingCustomHandler::::new(); + // prepare user addresses + let sender_addr = app.api().addr_make("sender"); + // run execute function let _ = custom_handler.execute( app.api(), &mut storage, app.router(), &app.block_info(), - Addr::unchecked("sender"), + sender_addr, CustomHelperMsg::SetAge { age: 32 }, ); diff --git a/src/wasm.rs b/src/wasm.rs index a960b7c6..ed522324 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -390,6 +390,7 @@ where /// use cosmwasm_std::{Addr, Api, Storage}; /// use cw_multi_test::{AddressGenerator, AppBuilder, no_init, WasmKeeper}; /// use cw_multi_test::error::AnyResult; + /// # use cosmwasm_std::testing::MockApi; /// /// struct CustomAddressGenerator; /// @@ -402,7 +403,7 @@ where /// instance_id: u64, /// ) -> AnyResult { /// // here implement your address generation logic - /// # Ok(Addr::unchecked("test_address")) + /// # Ok(MockApi::default().addr_make("test_address")) /// } /// } /// @@ -1235,10 +1236,16 @@ mod test { #[test] fn register_contract() { let api = MockApi::default(); + + // prepare user addresses + let creator_addr = api.addr_make("creator"); + let user_addr = api.addr_make("foobar"); + let admin_addr = api.addr_make("admin"); + let mut wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), error::contract(false)); + let code_id = wasm_keeper.store_code(creator_addr, error::contract(false)); transactional(&mut wasm_storage, |cache, _| { // cannot register contract with unregistered codeId @@ -1246,8 +1253,8 @@ mod test { &api, cache, code_id + 1, - Addr::unchecked("foobar"), - Addr::unchecked("admin"), + user_addr.clone(), + admin_addr.clone(), "label".to_owned(), 1000, None, @@ -1261,8 +1268,8 @@ mod test { &api, cache, code_id, - Addr::unchecked("foobar"), - Addr::unchecked("admin"), + user_addr.clone(), + admin_addr.clone(), "label".to_owned(), 1000, None, @@ -1279,8 +1286,8 @@ mod test { contract_data, ContractData { code_id, - creator: Addr::unchecked("foobar"), - admin: Some(Addr::unchecked("admin")), + creator: user_addr, + admin: admin_addr.into(), label: "label".to_owned(), created: 1000, } @@ -1329,15 +1336,17 @@ mod test { #[test] fn query_contract_info() { let api = MockApi::default(); + + // prepare user addresses + let creator = api.addr_make("creator"); + let admin = api.addr_make("admin"); + let mut wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); + let code_id = wasm_keeper.store_code(creator.clone(), payout::contract()); assert_eq!(1, code_id); - let creator = Addr::unchecked("foobar"); - let admin = Addr::unchecked("admin"); - let contract_addr = wasm_keeper .register_contract( &api, @@ -1371,8 +1380,8 @@ mod test { let wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let creator = api.addr_make("creator"); - let code_id = wasm_keeper.store_code(creator.clone(), payout::contract()); + let creator_addr = api.addr_make("creator"); + let code_id = wasm_keeper.store_code(creator_addr.clone(), payout::contract()); let querier: MockQuerier = MockQuerier::new(&[]); let query = WasmQuery::CodeInfo { code_id }; let code_info = wasm_keeper @@ -1380,18 +1389,19 @@ mod test { .unwrap(); let actual: CodeInfoResponse = from_json(code_info).unwrap(); assert_eq!(code_id, actual.code_id); - assert_eq!(creator.to_string(), actual.creator.to_string()); + assert_eq!(creator_addr.as_str(), actual.creator.as_str()); assert_eq!(32, actual.checksum.as_slice().len()); } #[test] fn different_contracts_must_have_different_checksum() { let api = MockApi::default(); + let creator_addr = api.addr_make("creator"); let wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id_payout = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); - let code_id_caller = wasm_keeper.store_code(Addr::unchecked("creator"), caller::contract()); + let code_id_payout = wasm_keeper.store_code(creator_addr.clone(), payout::contract()); + let code_id_caller = wasm_keeper.store_code(creator_addr, caller::contract()); let querier: MockQuerier = MockQuerier::new(&[]); let query_payout = WasmQuery::CodeInfo { code_id: code_id_payout, From f0208d42e2464214368c732da432f4ab94f41538 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 10:58:42 +0100 Subject: [PATCH 065/250] Refactoring. --- src/wasm.rs | 66 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/src/wasm.rs b/src/wasm.rs index ed522324..0e957959 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1241,6 +1241,7 @@ mod test { let creator_addr = api.addr_make("creator"); let user_addr = api.addr_make("foobar"); let admin_addr = api.addr_make("admin"); + let unregistered_addr = api.addr_make("unregistered"); let mut wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); @@ -1286,7 +1287,7 @@ mod test { contract_data, ContractData { code_id, - creator: user_addr, + creator: user_addr.clone(), admin: admin_addr.into(), label: "label".to_owned(), created: 1000, @@ -1295,7 +1296,7 @@ mod test { let err = transactional(&mut wasm_storage, |cache, _| { // now, we call this contract and see the error message from the contract - let info = mock_info("foobar", &[]); + let info = mock_info(user_addr.as_str(), &[]); wasm_keeper.call_instantiate( contract_addr.clone(), &api, @@ -1316,9 +1317,9 @@ mod test { let err = transactional(&mut wasm_storage, |cache, _| { // and the error for calling an unregistered contract - let info = mock_info("foobar", &[]); + let info = mock_info(user_addr.as_str(), &[]); wasm_keeper.call_instantiate( - Addr::unchecked("unregistered"), + unregistered_addr, &api, cache, &mock_router(), @@ -1338,13 +1339,13 @@ mod test { let api = MockApi::default(); // prepare user addresses - let creator = api.addr_make("creator"); - let admin = api.addr_make("admin"); + let creator_addr = api.addr_make("creator"); + let admin_addr = api.addr_make("admin"); let mut wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(creator.clone(), payout::contract()); + let code_id = wasm_keeper.store_code(creator_addr.clone(), payout::contract()); assert_eq!(1, code_id); let contract_addr = wasm_keeper @@ -1352,8 +1353,8 @@ mod test { &api, &mut wasm_storage, code_id, - creator.clone(), - admin.clone(), + creator_addr.clone(), + admin_addr.clone(), "label".to_owned(), 1000, None, @@ -1370,7 +1371,8 @@ mod test { .unwrap(); let actual: ContractInfoResponse = from_json(contract_info).unwrap(); - let expected = ContractInfoResponse::new(code_id, creator, admin.into(), false, None); + let expected = + ContractInfoResponse::new(code_id, creator_addr, admin_addr.into(), false, None); assert_eq!(expected, actual); } @@ -1442,9 +1444,15 @@ mod test { #[test] fn can_dump_raw_wasm_state() { let api = MockApi::default(); + + // prepare user addresses + let creator_addr = api.addr_make("creator"); + let admin_addr = api.addr_make("admin"); + let user_addr = api.addr_make("foobar"); + let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); + let code_id = wasm_keeper.store_code(creator_addr, payout::contract()); let mut wasm_storage = MockStorage::new(); @@ -1453,8 +1461,8 @@ mod test { &api, &mut wasm_storage, code_id, - Addr::unchecked("foobar"), - Addr::unchecked("admin"), + user_addr, + admin_addr, "label".to_owned(), 1000, None, @@ -1495,9 +1503,14 @@ mod test { #[test] fn contract_send_coins() { let api = MockApi::default(); + + // prepare user addresses + let creator_addr = api.addr_make("creator"); + let user_addr = api.addr_make("foobar"); + let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); + let code_id = wasm_keeper.store_code(creator_addr, payout::contract()); let mut wasm_storage = MockStorage::new(); let mut cache = StorageTransaction::new(&wasm_storage); @@ -1507,7 +1520,7 @@ mod test { &api, &mut cache, code_id, - Addr::unchecked("foobar"), + user_addr.clone(), None, "label".to_owned(), 1000, @@ -1518,7 +1531,7 @@ mod test { let payout = coin(100, "TGD"); // init the contract - let info = mock_info("foobar", &[]); + let info = mock_info(user_addr.as_str(), &[]); let init_msg = to_json_vec(&payout::InstantiateMessage { payout: payout.clone(), }) @@ -1537,7 +1550,7 @@ mod test { assert_eq!(0, res.messages.len()); // execute the contract - let info = mock_info("foobar", &[]); + let info = mock_info(user_addr.as_str(), &[]); let res = wasm_keeper .call_execute( &api, @@ -1552,7 +1565,7 @@ mod test { assert_eq!(1, res.messages.len()); match &res.messages[0].msg { CosmosMsg::Bank(BankMsg::Send { to_address, amount }) => { - assert_eq!(to_address.as_str(), "foobar"); + assert_eq!(to_address.as_str(), user_addr.as_str()); assert_eq!(amount.as_slice(), &[payout.clone()]); } m => panic!("Unexpected message {:?}", m), @@ -1608,9 +1621,14 @@ mod test { #[test] fn multi_level_wasm_cache() { let api = MockApi::default(); + + // prepare user addresses + let creator_addr = api.addr_make("creator"); + let user_addr = api.addr_make("foobar"); + let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); + let code_id = wasm_keeper.store_code(creator_addr, payout::contract()); let mut wasm_storage = MockStorage::new(); @@ -1623,14 +1641,14 @@ mod test { &api, cache, code_id, - Addr::unchecked("foobar"), + user_addr.clone(), None, "".to_string(), 1000, None, ) .unwrap(); - let info = mock_info("foobar", &[]); + let info = mock_info(user_addr.as_str(), &[]); let init_msg = to_json_vec(&payout::InstantiateMessage { payout: payout1.clone(), }) @@ -1664,14 +1682,14 @@ mod test { &api, cache, code_id, - Addr::unchecked("foobar"), + user_addr.clone(), None, "".to_owned(), 1000, None, ) .unwrap(); - let info = mock_info("foobar", &[]); + let info = mock_info(user_addr.as_str(), &[]); let init_msg = to_json_vec(&payout::InstantiateMessage { payout: payout2.clone(), }) @@ -1700,7 +1718,7 @@ mod test { &api, cache2, code_id, - Addr::unchecked("foobar"), + user_addr, None, "".to_owned(), 1000, From b4e92cdeca3375b0881e7597807f807eb26641d2 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 11:22:08 +0100 Subject: [PATCH 066/250] Removed custom stargate message and query. --- src/app.rs | 27 +++-------------- src/lib.rs | 4 +-- src/stargate.rs | 32 +++----------------- src/tests/test_stargate.rs | 2 +- tests/test_app_builder/test_with_stargate.rs | 3 +- 5 files changed, 12 insertions(+), 56 deletions(-) diff --git a/src/app.rs b/src/app.rs index 87676864..27bab476 100644 --- a/src/app.rs +++ b/src/app.rs @@ -6,7 +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::{Stargate, StargateFailingModule, StargateMsg, StargateQuery}; +use crate::stargate::{Stargate, StargateFailingModule}; use crate::transactions::transactional; use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; use crate::{AppBuilder, GovFailingModule, IbcFailingModule}; @@ -604,17 +604,9 @@ 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::Any(msg) => self.stargate.execute( - api, - storage, - self, - block, - sender, - StargateMsg { - type_url: msg.type_url, - value: msg.value, - }, - ), + CosmosMsg::Any(msg) => self + .stargate + .execute(api, storage, self, block, sender, msg), _ => bail!("Cannot execute {:?}", msg), } } @@ -636,16 +628,7 @@ 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::Grpc(grpc) => self.stargate.query( - api, - storage, - &querier, - block, - StargateQuery { - path: grpc.path, - data: grpc.data, - }, - ), + QueryRequest::Grpc(req) => self.stargate.query(api, storage, &querier, block, req), _ => unimplemented!(), } } diff --git a/src/lib.rs b/src/lib.rs index 9a6becda..de4c2702 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -160,7 +160,5 @@ pub use crate::module::{AcceptingModule, FailingModule, Module}; pub use crate::staking::{ Distribution, DistributionKeeper, StakeKeeper, Staking, StakingInfo, StakingSudo, }; -pub use crate::stargate::{ - Stargate, StargateAcceptingModule, StargateFailingModule, StargateMsg, StargateQuery, -}; +pub use crate::stargate::{Stargate, StargateAcceptingModule, StargateFailingModule}; pub use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; diff --git a/src/stargate.rs b/src/stargate.rs index 774aa67f..254d679a 100644 --- a/src/stargate.rs +++ b/src/stargate.rs @@ -1,39 +1,15 @@ use crate::{AcceptingModule, FailingModule, Module}; -use cosmwasm_std::{Binary, Empty}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; - -/// Placeholder for stargate message attributes. -#[non_exhaustive] -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub struct StargateMsg { - /// Stargate message type. - pub type_url: String, - /// Stargate message body. - pub value: Binary, -} - -/// Placeholder for stargate query attributes. -#[non_exhaustive] -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub struct StargateQuery { - /// Fully qualified service path used for routing, e.g. custom/cosmos_sdk.x.bank.v1.Query/QueryBalance. - pub path: String, - /// Expected protobuf message type (not any), binary encoded. - pub data: Binary, -} +use cosmwasm_std::{AnyMsg, Empty, GrpcQuery}; /// Interface to module handling stargate messages and queries. -pub trait Stargate: Module {} +pub trait Stargate: Module {} /// Always accepting stargate module. -pub type StargateAcceptingModule = AcceptingModule; +pub type StargateAcceptingModule = AcceptingModule; impl Stargate for StargateAcceptingModule {} /// Always accepting stargate module. -pub type StargateFailingModule = FailingModule; +pub type StargateFailingModule = FailingModule; impl Stargate for StargateFailingModule {} diff --git a/src/tests/test_stargate.rs b/src/tests/test_stargate.rs index 1f2c77db..157b61b5 100644 --- a/src/tests/test_stargate.rs +++ b/src/tests/test_stargate.rs @@ -27,7 +27,7 @@ fn default_failing_stargate_module_should_work() { .source() .unwrap() .to_string() - .starts_with("Unexpected exec msg StargateMsg")); + .starts_with("Unexpected exec msg AnyMsg")); } #[test] diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index 80b0fe60..85a61e0e 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -2,10 +2,9 @@ use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; use cosmwasm_std::{to_json_vec, AnyMsg, CosmosMsg, Empty, GrpcQuery, QueryRequest}; use cw_multi_test::{ no_init, AppBuilder, Executor, Stargate, StargateAcceptingModule, StargateFailingModule, - StargateMsg, StargateQuery, }; -type MyStargateKeeper = MyKeeper; +type MyStargateKeeper = MyKeeper; impl Stargate for MyStargateKeeper {} From f9c88084c05ac6478f4800322f6edf27482f0bb8 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 11:40:28 +0100 Subject: [PATCH 067/250] Updates. --- src/stargate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stargate.rs b/src/stargate.rs index 254d679a..9065a2b8 100644 --- a/src/stargate.rs +++ b/src/stargate.rs @@ -1,7 +1,7 @@ use crate::{AcceptingModule, FailingModule, Module}; use cosmwasm_std::{AnyMsg, Empty, GrpcQuery}; -/// Interface to module handling stargate messages and queries. +/// Interface to module handling any messages and queries. pub trait Stargate: Module {} /// Always accepting stargate module. From 2b0fbd8d476c318a87e8ae319d0d2d8d9a448cfc Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 12:14:01 +0100 Subject: [PATCH 068/250] Bumped dependencies. --- Cargo.lock | 28 +++++++++++++++++++--------- Cargo.toml | 7 +++---- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8aa0081e..6185a2db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,7 +135,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-crypto" -version = "2.0.0-rc.0" +version = "2.0.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5188089c28996a446b882b61abb74dc5b90f1a4cfe26e4584a722c5f75ed4f43" dependencies = [ "digest 0.10.7", "ed25519-zebra", @@ -146,16 +148,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "2.0.0-rc.0" +version = "2.0.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7436a7247ddcb6125dd55566687e566e7e67b8cbf27f2f9916f4bfb731f9bf4b" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "2.0.0-rc.0" +version = "2.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0cf9c873ae321836f0781f8f9e135862d6ccc9fd563bfaebec42990fa7315c" +checksum = "7877c1debbe8dc6e8026de081c39d357579d5baa5c79d76e4428c1b26013bd38" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -166,9 +170,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.0.0-rc.0" +version = "2.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8c5a8183b78c6749908ee1f4582cb11d6dbab15cca9ccf894722c13e63b73fd" +checksum = "fa51536f0c56ac14971576cff2ef4bde35d21eafcb619e16d6e89417d41e85ed" dependencies = [ "proc-macro2", "quote", @@ -177,7 +181,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "2.0.0-rc.0" +version = "2.0.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cb9f0cb520832e993af5cbe97bc3c163bd0c3870989e99d5f1d5499e6f28a53" dependencies = [ "base64", "bech32", @@ -262,7 +268,9 @@ dependencies = [ [[package]] name = "cw-storage-plus" -version = "2.0.0-beta.0" +version = "2.0.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8950902b662b249447c86ddf35b70f83603aedfb5e388434f53fb4aba6a1378" dependencies = [ "cosmwasm-std", "schemars", @@ -271,7 +279,9 @@ dependencies = [ [[package]] name = "cw-utils" -version = "2.0.0-beta.0" +version = "2.0.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e9dfd846ca70673781742aa739bae515bc833e8cf1c033611288df5067d734" dependencies = [ "cosmwasm-schema", "cosmwasm-std", diff --git a/Cargo.toml b/Cargo.toml index 2bfd3697..111ac1d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,10 +16,9 @@ cosmwasm_2_0 = ["cosmwasm-std/cosmwasm_2_0"] [dependencies] anyhow = "1.0.79" bech32 = "0.9.1" -# cosmwasm-std = { version = "2.0.0-rc.0", features = ["iterator", "staking", "stargate"] } -cosmwasm-std = { path = "../cosmwasm/packages/std", features = ["iterator", "staking", "stargate"] } -cw-storage-plus = { path = "../cw-storage-plus"} -cw-utils = { path = "../cw-utils"} +cosmwasm-std = { version = "2.0.0-rc.1", features = ["iterator", "staking", "stargate"] } +cw-storage-plus = "2.0.0-rc.0" +cw-utils = "2.0.0-rc.0" derivative = "2.2.0" itertools = "0.12.1" prost = "0.12.3" From c8ec121a00388cd1e2f2d23a1f2da2f62ee9c379 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 12:51:15 +0100 Subject: [PATCH 069/250] Updates. --- Cargo.lock | 2 +- Cargo.toml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6185a2db..57696d74 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -247,7 +247,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "2.0.0" +version = "2.0.0-rc.0" dependencies = [ "anyhow", "bech32", diff --git a/Cargo.toml b/Cargo.toml index 111ac1d8..e7be4da8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "cw-multi-test" -version = "2.0.0" +version = "2.0.0-rc.0" authors = ["Ethan Frey "] -edition = "2021" description = "Testing tools for multi-contract interactions" -license = "Apache-2.0" repository = "https://github.com/CosmWasm/cw-multi-test" homepage = "https://cosmwasm.com" +license = "Apache-2.0" +edition = "2021" [features] default = ["cosmwasm_2_0"] From e6270c97e87503b8edcf7e246c89128319557920 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 12:52:43 +0100 Subject: [PATCH 070/250] Updates. --- .circleci/config.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e9a3a574..0c2b4a9e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -73,10 +73,10 @@ jobs: - cargocache-v2-multi-test:1.65.0-minimal-{{ checksum "Cargo.toml" }} - run: name: Build library for native target - command: cargo build -Zminimal-versions --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 + command: cargo build -Zminimal-versions --all-features - run: name: Run unit tests - command: cargo test --workspace -Zminimal-versions --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 + command: cargo test --workspace -Zminimal-versions --all-features - save_cache: paths: - /usr/local/cargo/registry @@ -103,7 +103,7 @@ jobs: command: cargo build --locked --all-features - run: name: Run unit tests - command: cargo test --workspace --locked --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 + command: cargo test --workspace --locked --all-features - save_cache: paths: - /usr/local/cargo/registry @@ -156,6 +156,6 @@ jobs: command: | mkdir -p cov docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin \ - sh -c "cargo tarpaulin --workspace --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 --force-clean --engine llvm --out xml --output-dir cov" + sh -c "cargo tarpaulin --workspace --all-features --force-clean --engine llvm --out xml --output-dir cov" - codecov/upload: file: cov/cobertura.xml From 6d680b91eebc3ae2872266bfc24292c2fad29174 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 13:01:52 +0100 Subject: [PATCH 071/250] Fixed clippy warnings. --- src/tests/test_app.rs | 2 +- src/wasm.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 1ba604a5..a8e96bdd 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -1614,7 +1614,7 @@ mod contract_instantiation { msg: init_msg, funds: vec![], label: "label".into(), - salt: salt.clone().into(), + salt: salt.into(), }; let res = app.execute(sender, msg.into()).unwrap(); diff --git a/src/wasm.rs b/src/wasm.rs index 0e957959..e49b1531 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1974,7 +1974,7 @@ mod test { admin, "label".to_owned(), 1000, - Binary::from(salt.clone()), + Binary::from(salt), ) .unwrap(); From 40d55cd6c846e810b06d7d908c661dd4295307fc Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 13:18:12 +0100 Subject: [PATCH 072/250] Updates. --- src/wasm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm.rs b/src/wasm.rs index e49b1531..20d59523 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -237,7 +237,7 @@ where let code_base_id = self.code_base.len(); self.code_base.push(code); let code_id = (self.code_data.len() + 1) as u64; - let checksum: Checksum = self.checksum_generator.checksum(&creator, code_id); + let checksum = self.checksum_generator.checksum(&creator, code_id); self.code_data.push(CodeData { creator, checksum, From 27a454b7486f4c1579b34c2ad0a99657af6727b3 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 13:54:05 +0100 Subject: [PATCH 073/250] Removed addons - cosmwasm-std 2.0 has everything we need. --- src/addons/addresses/mock.rs | 148 -------------- src/addons/addresses/mod.rs | 1 - src/addons/api/bech32.rs | 187 ------------------ src/addons/api/bech32m.rs | 154 --------------- src/addons/api/mod.rs | 2 - src/addons/mod.rs | 12 -- src/lib.rs | 1 - tests/mod.rs | 2 +- tests/test_addons/mod.rs | 1 - tests/test_addons/test_api/test_bech32m.rs | 107 ---------- tests/{test_addons => }/test_api/mod.rs | 3 +- .../test_prefixed.rs} | 62 +++--- tests/test_app/test_instantiate2.rs | 13 +- tests/test_app_builder/test_with_api.rs | 4 +- tests/test_wasm/test_with_addr_gen.rs | 32 ++- 15 files changed, 46 insertions(+), 683 deletions(-) delete mode 100644 src/addons/addresses/mock.rs delete mode 100644 src/addons/addresses/mod.rs delete mode 100644 src/addons/api/bech32.rs delete mode 100644 src/addons/api/bech32m.rs delete mode 100644 src/addons/api/mod.rs delete mode 100644 src/addons/mod.rs delete mode 100644 tests/test_addons/mod.rs delete mode 100644 tests/test_addons/test_api/test_bech32m.rs rename tests/{test_addons => }/test_api/mod.rs (98%) rename tests/{test_addons/test_api/test_bech32.rs => test_api/test_prefixed.rs} (50%) diff --git a/src/addons/addresses/mock.rs b/src/addons/addresses/mock.rs deleted file mode 100644 index ab166f95..00000000 --- a/src/addons/addresses/mock.rs +++ /dev/null @@ -1,148 +0,0 @@ -use crate::error::AnyResult; -use crate::AddressGenerator; -use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage}; -use sha2::digest::Update; -use sha2::{Digest, Sha256}; - -/// Address generator that mimics the [wasmd](https://github.com/CosmWasm/wasmd) behavior. -/// -/// [MockAddressGenerator] implements [AddressGenerator] trait in terms of -/// [`contract_address`](AddressGenerator::contract_address) and -/// [`predictable_contract_address`](AddressGenerator::predictable_contract_address) functions: -/// - `contract_address` generates non-predictable addresses for contracts, -/// using the same algorithm as `wasmd`, see: [`BuildContractAddressClassic`] for details. -/// - `predictable_contract_address` generates predictable addresses for contracts using -/// [`instantiate2_address`] function defined in `cosmwasm-std`. -/// -/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41 -/// [`instantiate2_address`]:https://github.com/CosmWasm/cosmwasm/blob/8a652d7cd8071f71139deca6be8194ed4a278b2c/packages/std/src/addresses.rs#L309-L318 -#[derive(Default)] -pub struct MockAddressGenerator; - -impl AddressGenerator for MockAddressGenerator { - /// Generates a _non-predictable_ contract address, like `wasmd` does it in real-life chain. - /// - /// Note that addresses generated by `wasmd` may change and users **should not** - /// rely on this value in any extend. - /// - /// Returns the contract address after its instantiation. - /// Address generated by this function is returned as a result - /// of processing `WasmMsg::Instantiate` message. - /// - /// **NOTES** - /// > 👉 The canonical address generated by this function is humanized using the - /// > `Api::addr_humanize` function, so the resulting value depends on used `Api` implementation. - /// > The following example uses Bech32 format for humanizing canonical addresses. - /// - /// > 👉 Do NOT use this function **directly** to generate a contract address, - /// > pass this address generator to `WasmKeeper`: - /// > `WasmKeeper::new().with_address_generator(MockAddressGenerator::default());` - /// - /// # Example - /// - /// ``` - /// # use cosmwasm_std::testing::MockStorage; - /// # use cw_multi_test::AddressGenerator; - /// # use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; - /// // use `Api` that implements Bech32 format - /// let api = MockApiBech32::new("juno"); - /// // prepare mock storage - /// let mut storage = MockStorage::default(); - /// // initialize the address generator - /// let address_generator = MockAddressGenerator::default(); - /// // generate the address - /// let addr = address_generator.contract_address(&api, &mut storage, 1, 1).unwrap(); - /// - /// assert_eq!(addr.to_string(), - /// "juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8"); - /// ``` - fn contract_address( - &self, - api: &dyn Api, - _storage: &mut dyn Storage, - code_id: u64, - instance_id: u64, - ) -> AnyResult { - let canonical_addr = instantiate_address(code_id, instance_id); - Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) - } - - /// Generates a _predictable_ contract address, like `wasmd` does it in real-life chain. - /// - /// Returns a contract address after its instantiation. - /// Address generated by this function is returned as a result - /// of processing `WasmMsg::Instantiate2` message. - /// - /// **NOTES** - /// > 👉 The canonical address generated by this function is humanized using the - /// > `Api::addr_humanize` function, so the resulting value depends on used `Api` implementation. - /// > The following example uses Bech32 format for humanizing canonical addresses. - /// - /// > 👉 Do NOT use this function **directly** to generate a contract address, - /// > pass this address generator to WasmKeeper: - /// > `WasmKeeper::new().with_address_generator(MockAddressGenerator::default());` - /// - /// # Example - /// - /// ``` - /// # use cosmwasm_std::Api; - /// # use cosmwasm_std::testing::MockStorage; - /// # use cw_multi_test::AddressGenerator; - /// # use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; - /// // use `Api` that implements Bech32 format - /// let api = MockApiBech32::new("juno"); - /// // prepare mock storage - /// let mut storage = MockStorage::default(); - /// // initialize the address generator - /// let address_generator = MockAddressGenerator::default(); - /// // checksum of the contract code base - /// let checksum = [0, 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10, - /// 11,12,13,14,15,16,17,18,19,20,21, - /// 22,23,24,25,26,27,28,29,30,31]; - /// // creator address - /// let creator = api.addr_canonicalize(api.addr_make("creator").as_str()).unwrap(); - /// // salt - /// let salt = [10,11,12]; - /// // generate the address - /// let addr = address_generator - /// .predictable_contract_address(&api, &mut storage, 1, 1, &checksum, &creator, &salt) - /// .unwrap(); - /// - /// assert_eq!(addr.to_string(), - /// "juno1sv3gjp85m3xxluxreruards8ruxk5ykys8qfljwrdj5tv8kqxuhsmlfyud"); - /// ``` - fn predictable_contract_address( - &self, - api: &dyn Api, - _storage: &mut dyn Storage, - _code_id: u64, - _instance_id: u64, - checksum: &[u8], - - creator: &CanonicalAddr, - salt: &[u8], - ) -> AnyResult { - let canonical_addr = instantiate2_address(checksum, creator, salt)?; - Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) - } -} - -/// Returns non-predictable contract address. -/// -/// Address is generated using the same algorithm as [`BuildContractAddressClassic`] -/// implementation in `wasmd`. -/// -/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41 -fn instantiate_address(code_id: u64, instance_id: u64) -> CanonicalAddr { - let mut key = Vec::::new(); - key.extend_from_slice(b"wasm\0"); - key.extend_from_slice(&code_id.to_be_bytes()); - key.extend_from_slice(&instance_id.to_be_bytes()); - let module = Sha256::digest("module".as_bytes()); - Sha256::new() - .chain(module) - .chain(key) - .finalize() - .to_vec() - .into() -} diff --git a/src/addons/addresses/mod.rs b/src/addons/addresses/mod.rs deleted file mode 100644 index 9afc1d5e..00000000 --- a/src/addons/addresses/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod mock; diff --git a/src/addons/api/bech32.rs b/src/addons/api/bech32.rs deleted file mode 100644 index 923b3961..00000000 --- a/src/addons/api/bech32.rs +++ /dev/null @@ -1,187 +0,0 @@ -use bech32::{decode, encode, FromBase32, ToBase32, Variant}; -use cosmwasm_std::testing::MockApi; -use cosmwasm_std::{ - Addr, Api, CanonicalAddr, RecoverPubkeyError, StdError, StdResult, VerificationError, -}; -use sha2::{Digest, Sha256}; - -/// Implementation of the [Api](cosmwasm_std::Api) trait that uses [Bech32] format -/// for humanizing canonical addresses. -/// -/// [Bech32]: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki -pub struct MockApiBech32 { - api: MockApi, - prefix: &'static str, - variant: Variant, -} - -impl MockApiBech32 { - /// Returns `Api` implementation that uses specified prefix - /// to generate addresses in **Bech32** format. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(addr.as_str(), - /// "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"); - /// ``` - pub fn new(prefix: &'static str) -> Self { - Self::new_with_variant(prefix, Variant::Bech32) - } - - /// Creates `Api` implementation that uses specified prefix - /// to generate addresses in format defined by provided Bech32 variant. - pub(crate) fn new_with_variant(prefix: &'static str, variant: Variant) -> Self { - Self { - api: MockApi::default(), - prefix, - variant, - } - } -} - -impl Api for MockApiBech32 { - /// Takes a human readable address in **Bech32** format and checks if it is valid. - /// - /// If the validation succeeds, an `Addr` containing the same string as the input is returned. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(api.addr_validate(addr.as_str()).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_validate(&self, input: &str) -> StdResult { - self.addr_humanize(&self.addr_canonicalize(input)?) - } - - /// Takes a human readable address in **Bech32** format and returns - /// a canonical binary representation of it. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(api.addr_canonicalize(addr.as_str()).unwrap().to_string(), - /// "BC6BFD848EBD7819C9A82BF124D65E7F739D08E002601E23BB906AACD40A3D81"); - /// ``` - fn addr_canonicalize(&self, input: &str) -> StdResult { - if let Ok((prefix, decoded, variant)) = decode(input) { - if prefix == self.prefix && variant == self.variant { - if let Ok(bytes) = Vec::::from_base32(&decoded) { - return Ok(bytes.into()); - } - } - } - Err(StdError::generic_err("Invalid input")) - } - - /// Takes a canonical address and returns a human readable address in **Bech32** format. - /// - /// This is the inverse operation of [`addr_canonicalize`]. - /// - /// [`addr_canonicalize`]: MockApiBech32::addr_canonicalize - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// let canonical_addr = api.addr_canonicalize(addr.as_str()).unwrap(); - /// assert_eq!(api.addr_humanize(&canonical_addr).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - if let Ok(encoded) = encode(self.prefix, canonical.as_slice().to_base32(), self.variant) { - Ok(Addr::unchecked(encoded)) - } else { - Err(StdError::generic_err("Invalid canonical address")) - } - } - - fn secp256k1_verify( - &self, - message_hash: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.api - .secp256k1_verify(message_hash, signature, public_key) - } - - fn secp256k1_recover_pubkey( - &self, - message_hash: &[u8], - signature: &[u8], - recovery_param: u8, - ) -> Result, RecoverPubkeyError> { - self.api - .secp256k1_recover_pubkey(message_hash, signature, recovery_param) - } - - fn ed25519_verify( - &self, - message: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.api.ed25519_verify(message, signature, public_key) - } - - fn ed25519_batch_verify( - &self, - messages: &[&[u8]], - signatures: &[&[u8]], - public_keys: &[&[u8]], - ) -> Result { - self.api - .ed25519_batch_verify(messages, signatures, public_keys) - } - - fn debug(&self, message: &str) { - self.api.debug(message) - } -} - -impl MockApiBech32 { - /// Returns an address in **Bech32** format, built from provided input string. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(addr.as_str(), - /// "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"); - /// ``` - /// - /// # Panics - /// - /// This function panics when generating a valid address in **Bech32** - /// format is not possible, especially when prefix is too long or empty. - pub fn addr_make(&self, input: &str) -> Addr { - let digest = Sha256::digest(input).to_vec(); - match encode(self.prefix, digest.to_base32(), self.variant) { - Ok(address) => Addr::unchecked(address), - Err(reason) => panic!("Generating address failed with reason: {}", reason), - } - } -} diff --git a/src/addons/api/bech32m.rs b/src/addons/api/bech32m.rs deleted file mode 100644 index 40311cd1..00000000 --- a/src/addons/api/bech32m.rs +++ /dev/null @@ -1,154 +0,0 @@ -use crate::addons::MockApiBech32; -use bech32::Variant; -use cosmwasm_std::{Addr, Api, CanonicalAddr, RecoverPubkeyError, StdResult, VerificationError}; - -/// Implementation of the [Api](cosmwasm_std::Api) trait that uses [Bech32m] format -/// for humanizing canonical addresses. -/// -/// [Bech32m]: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki -pub struct MockApiBech32m(MockApiBech32); - -impl MockApiBech32m { - /// Returns `Api` implementation that uses specified prefix - /// to generate addresses in **Bech32m** format. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::addons::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmosis"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(addr.as_str(), - /// "osmosis1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qgv9940"); - /// ``` - pub fn new(prefix: &'static str) -> Self { - Self(MockApiBech32::new_with_variant(prefix, Variant::Bech32m)) - } -} - -impl Api for MockApiBech32m { - /// Takes a human readable address in **Bech32m** format and checks if it is valid. - /// - /// If the validation succeeds, an `Addr` containing the same string as the input is returned. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmosis"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(api.addr_validate(addr.as_str()).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_validate(&self, input: &str) -> StdResult { - self.0.addr_validate(input) - } - - /// Takes a human readable address in **Bech32m** format and returns - /// a canonical binary representation of it. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("osmosis"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(api.addr_canonicalize(addr.as_str()).unwrap().to_string(), - /// "0A367B92CF0B037DFD89960EE832D56F7FC151681BB41E53690E776F5786998A"); - /// ``` - fn addr_canonicalize(&self, input: &str) -> StdResult { - self.0.addr_canonicalize(input) - } - - /// Takes a canonical address and returns a human readable address in **Bech32m** format. - /// - /// This is the inverse operation of [`addr_canonicalize`]. - /// - /// [`addr_canonicalize`]: MockApiBech32m::addr_canonicalize - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmosis"); - /// let addr = api.addr_make("sender"); - /// let canonical_addr = api.addr_canonicalize(addr.as_str()).unwrap(); - /// assert_eq!(api.addr_humanize(&canonical_addr).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - self.0.addr_humanize(canonical) - } - - fn secp256k1_verify( - &self, - message_hash: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.0.secp256k1_verify(message_hash, signature, public_key) - } - - fn secp256k1_recover_pubkey( - &self, - message_hash: &[u8], - signature: &[u8], - recovery_param: u8, - ) -> Result, RecoverPubkeyError> { - self.0 - .secp256k1_recover_pubkey(message_hash, signature, recovery_param) - } - - fn ed25519_verify( - &self, - message: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.0.ed25519_verify(message, signature, public_key) - } - - fn ed25519_batch_verify( - &self, - messages: &[&[u8]], - signatures: &[&[u8]], - public_keys: &[&[u8]], - ) -> Result { - self.0 - .ed25519_batch_verify(messages, signatures, public_keys) - } - - fn debug(&self, message: &str) { - self.0.debug(message) - } -} - -impl MockApiBech32m { - /// Returns an address in **Bech32m** format, built from provided input string. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::addons::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmosis"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(addr.as_str(), - /// "osmosis1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qgv9940"); - /// ``` - /// - /// # Panics - /// - /// This function panics when generating a valid address in **Bech32** - /// format is not possible, especially when prefix is too long or empty. - pub fn addr_make(&self, input: &str) -> Addr { - self.0.addr_make(input) - } -} diff --git a/src/addons/api/mod.rs b/src/addons/api/mod.rs deleted file mode 100644 index d59bbae5..00000000 --- a/src/addons/api/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod bech32; -pub mod bech32m; diff --git a/src/addons/mod.rs b/src/addons/mod.rs deleted file mode 100644 index 5dd4401b..00000000 --- a/src/addons/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! # Additional testing tools (extensions) -//! -//! **CosmWasm MultiTest** addons provide additional tools for testing smart contracts, -//! simulating complex blockchain scenarios that developers might encounter. -//! They enhance the CosmWasm environment, enabling more advanced and nuanced testing. - -mod addresses; -mod api; - -pub use addresses::mock::MockAddressGenerator; -pub use api::bech32::MockApiBech32; -pub use api::bech32m::MockApiBech32m; diff --git a/src/lib.rs b/src/lib.rs index de4c2702..c88b17eb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -124,7 +124,6 @@ #![deny(rustdoc::broken_intra_doc_links)] #![deny(rustdoc::missing_crate_level_docs)] -pub mod addons; mod addresses; mod app; mod app_builder; diff --git a/tests/mod.rs b/tests/mod.rs index d14c1479..f5370608 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -3,7 +3,7 @@ use cw_storage_plus::Item; use serde::{Deserialize, Serialize}; -mod test_addons; +mod test_api; mod test_app; mod test_app_builder; mod test_module; diff --git a/tests/test_addons/mod.rs b/tests/test_addons/mod.rs deleted file mode 100644 index 0ce9c88e..00000000 --- a/tests/test_addons/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod test_api; diff --git a/tests/test_addons/test_api/test_bech32m.rs b/tests/test_addons/test_api/test_bech32m.rs deleted file mode 100644 index 9cdc70ca..00000000 --- a/tests/test_addons/test_api/test_bech32m.rs +++ /dev/null @@ -1,107 +0,0 @@ -use super::*; -use cosmwasm_std::CanonicalAddr; -use cw_multi_test::addons::{MockApiBech32, MockApiBech32m}; - -const HUMAN_ADDRESS: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsrvt8pr"; - -#[test] -fn new_api_bech32m_should_work() { - assert_eq!( - MockApiBech32m::new("juno").addr_make("creator").as_str(), - HUMAN_ADDRESS - ); -} - -#[test] -fn api_bech32m_should_differ_from_bech32() { - assert_ne!( - MockApiBech32m::new("juno").addr_make("sender").as_str(), - MockApiBech32::new("juno").addr_make("sender").as_str() - ); -} - -#[test] -fn address_validate_should_work() { - assert_eq!( - MockApiBech32m::new("juno") - .addr_validate(HUMAN_ADDRESS) - .unwrap() - .as_str(), - HUMAN_ADDRESS - ) -} - -#[test] -fn address_validate_invalid_address() { - MockApiBech32m::new("juno") - .addr_validate("creator") - .unwrap_err(); -} - -#[test] -fn addr_validate_invalid_prefix() { - MockApiBech32m::new("juno") - .addr_validate(MockApiBech32m::new("osmosis").addr_make("creator").as_str()) - .unwrap_err(); -} - -#[test] -fn address_validate_invalid_variant() { - MockApiBech32m::new("juno") - .addr_validate(MockApiBech32::new("juno").addr_make("creator").as_str()) - .unwrap_err(); -} - -#[test] -fn address_canonicalize_humanize_should_work() { - let api = MockApiBech32m::new("juno"); - assert_eq!( - api.addr_humanize(&api.addr_canonicalize(HUMAN_ADDRESS).unwrap()) - .unwrap() - .as_str(), - HUMAN_ADDRESS - ); -} - -#[test] -fn address_humanize_prefix_too_long() { - MockApiBech32m::new( - "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", - ) - .addr_humanize(&CanonicalAddr::from([1, 2, 3, 4, 5])) - .unwrap_err(); -} - -#[test] -fn debug_should_not_panic() { - assert_debug_does_not_panic(&MockApiBech32m::new("juno")); -} - -#[test] -#[should_panic(expected = "Generating address failed with reason: invalid length")] -fn address_make_prefix_too_long() { - MockApiBech32m::new( - "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", - ) - .addr_make("creator"); -} - -#[test] -fn secp256k1_verify_works() { - assert_secp256k1_verify_works(&MockApiBech32m::new("juno")); -} - -#[test] -fn secp256k1_recover_pubkey_works() { - assert_secp256k1_recover_pubkey_works(&MockApiBech32m::new("juno")); -} - -#[test] -fn ed25519_verify_works() { - assert_ed25519_verify_works(&MockApiBech32m::new("juno")); -} - -#[test] -fn ed25519_batch_verify_works() { - assert_ed25519_batch_verify_works(&MockApiBech32m::new("juno")); -} diff --git a/tests/test_addons/test_api/mod.rs b/tests/test_api/mod.rs similarity index 98% rename from tests/test_addons/test_api/mod.rs rename to tests/test_api/mod.rs index d049acc5..e6be8297 100644 --- a/tests/test_addons/test_api/mod.rs +++ b/tests/test_api/mod.rs @@ -1,8 +1,7 @@ use cosmwasm_std::Api; use hex_literal::hex; -mod test_bech32; -mod test_bech32m; +mod test_prefixed; const SECP256K1_MSG_HASH: [u8; 32] = hex!("5ae8317d34d1e595e3fa7247db80c0af4320cce1116de187f8f7e2e099c0d8d0"); diff --git a/tests/test_addons/test_api/test_bech32.rs b/tests/test_api/test_prefixed.rs similarity index 50% rename from tests/test_addons/test_api/test_bech32.rs rename to tests/test_api/test_prefixed.rs index 4b5101ef..0af6a8ca 100644 --- a/tests/test_addons/test_api/test_bech32.rs +++ b/tests/test_api/test_prefixed.rs @@ -1,60 +1,50 @@ use super::*; +use cosmwasm_std::testing::MockApi; use cosmwasm_std::{Api, CanonicalAddr}; -use cw_multi_test::addons::{MockApiBech32, MockApiBech32m}; const HUMAN_ADDRESS: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"; -#[test] -fn new_api_bech32_should_work() { - assert_eq!( - MockApiBech32::new("juno").addr_make("creator").as_str(), - HUMAN_ADDRESS - ); +fn api_prefix(prefix: &'static str) -> MockApi { + MockApi::default().with_prefix(prefix) +} + +fn api_juno() -> MockApi { + api_prefix("juno") +} + +fn api_osmo() -> MockApi { + api_prefix("osmo") } #[test] -fn api_bech32_should_differ_from_bech32m() { - assert_ne!( - MockApiBech32::new("juno").addr_make("creator").as_str(), - MockApiBech32m::new("juno").addr_make("creator").as_str(), - ); +fn new_api_bech32_should_work() { + let addr = api_juno().addr_make("creator"); + assert_eq!(HUMAN_ADDRESS, addr.as_str(),); } #[test] fn address_validate_should_work() { assert_eq!( - MockApiBech32::new("juno") - .addr_validate(HUMAN_ADDRESS) - .unwrap() - .as_str(), + api_juno().addr_validate(HUMAN_ADDRESS).unwrap().as_str(), HUMAN_ADDRESS ) } #[test] fn address_validate_invalid_address() { - MockApiBech32::new("juno") - .addr_validate("creator") - .unwrap_err(); + api_juno().addr_validate("creator").unwrap_err(); } #[test] fn addr_validate_invalid_prefix() { - MockApiBech32::new("juno") - .addr_validate(MockApiBech32m::new("osmosis").addr_make("creator").as_str()) - .unwrap_err(); -} - -#[test] -fn address_validate_invalid_variant() { - MockApiBech32::new("juno") - .addr_validate(MockApiBech32m::new("juno").addr_make("creator").as_str()) + api_juno() + .addr_validate(api_osmo().addr_make("creator").as_str()) .unwrap_err(); } #[test] fn address_canonicalize_humanize_should_work() { - let api = MockApiBech32::new("juno"); + let api = api_juno(); assert_eq!( api.addr_humanize(&api.addr_canonicalize(HUMAN_ADDRESS).unwrap()) .unwrap() @@ -65,7 +55,7 @@ fn address_canonicalize_humanize_should_work() { #[test] fn address_humanize_prefix_too_long() { - MockApiBech32::new( + api_prefix( "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", ) .addr_humanize(&CanonicalAddr::from([1, 2, 3, 4, 5])) @@ -74,13 +64,13 @@ fn address_humanize_prefix_too_long() { #[test] fn debug_should_not_panic() { - assert_debug_does_not_panic(&MockApiBech32::new("juno")); + assert_debug_does_not_panic(&api_juno()); } #[test] #[should_panic(expected = "Generating address failed with reason: invalid length")] fn address_make_prefix_too_long() { - MockApiBech32::new( + api_prefix( "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", ) .addr_make("creator"); @@ -88,20 +78,20 @@ fn address_make_prefix_too_long() { #[test] fn secp256k1_verify_works() { - assert_secp256k1_verify_works(&MockApiBech32::new("juno")); + assert_secp256k1_verify_works(&api_juno()); } #[test] fn secp256k1_recover_pubkey_works() { - assert_secp256k1_recover_pubkey_works(&MockApiBech32::new("juno")); + assert_secp256k1_recover_pubkey_works(&api_juno()); } #[test] fn ed25519_verify_works() { - assert_ed25519_verify_works(&MockApiBech32::new("juno")); + assert_ed25519_verify_works(&api_juno()); } #[test] fn ed25519_batch_verify_works() { - assert_ed25519_batch_verify_works(&MockApiBech32::new("juno")); + assert_ed25519_batch_verify_works(&api_juno()); } diff --git a/tests/test_app/test_instantiate2.rs b/tests/test_app/test_instantiate2.rs index c0e7f191..95fc8eed 100644 --- a/tests/test_app/test_instantiate2.rs +++ b/tests/test_app/test_instantiate2.rs @@ -1,15 +1,14 @@ use crate::test_contracts::counter; +use cosmwasm_std::testing::MockApi; use cosmwasm_std::{instantiate2_address, to_json_binary, Api, Empty, WasmMsg}; -use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; -use cw_multi_test::{no_init, AppBuilder, Executor, WasmKeeper}; +use cw_multi_test::{no_init, AppBuilder, Executor}; use cw_utils::parse_instantiate_response_data; #[test] fn instantiate2_works() { // prepare the application with custom Api and custom address generator let mut app = AppBuilder::default() - .with_api(MockApiBech32::new("juno")) - .with_wasm(WasmKeeper::default().with_address_generator(MockAddressGenerator)) + .with_api(MockApi::default().with_prefix("juno")) .build(no_init); // prepare addresses for sender and creator @@ -73,8 +72,7 @@ fn instantiate2_works() { fn instantiate2_should_work_for_multiple_salts() { // prepare the application with custom Api and custom address generator let mut app = AppBuilder::default() - .with_api(MockApiBech32::new("juno")) - .with_wasm(WasmKeeper::default().with_address_generator(MockAddressGenerator)) + .with_api(MockApi::default().with_prefix("juno")) .build(no_init); // prepare addresses for sender and creator @@ -107,8 +105,7 @@ fn instantiate2_should_work_for_multiple_salts() { fn instantiate2_fails_for_duplicated_addresses() { // prepare the application with custom Api and custom address generator let mut app = AppBuilder::default() - .with_api(MockApiBech32::new("osmo")) - .with_wasm(WasmKeeper::default().with_address_generator(MockAddressGenerator)) + .with_api(MockApi::default().with_prefix("osmo")) .build(no_init); // prepare addresses for sender and creator diff --git a/tests/test_app_builder/test_with_api.rs b/tests/test_app_builder/test_with_api.rs index 26be8e25..91ee4de9 100644 --- a/tests/test_app_builder/test_with_api.rs +++ b/tests/test_app_builder/test_with_api.rs @@ -1,5 +1,5 @@ +use cosmwasm_std::testing::MockApi; use cosmwasm_std::{Api, CanonicalAddr, HexBinary}; -use cw_multi_test::addons::MockApiBech32; use cw_multi_test::{no_init, AppBuilder}; #[test] @@ -11,7 +11,7 @@ fn building_app_with_custom_api_should_work() { // create application with custom api that implements // Bech32 address encoding with 'juno' prefix let app = AppBuilder::default() - .with_api(MockApiBech32::new("juno")) + .with_api(MockApi::default().with_prefix("juno")) .build(no_init); // check address validation function diff --git a/tests/test_wasm/test_with_addr_gen.rs b/tests/test_wasm/test_with_addr_gen.rs index 24b53bf6..2863fed0 100644 --- a/tests/test_wasm/test_with_addr_gen.rs +++ b/tests/test_wasm/test_with_addr_gen.rs @@ -1,5 +1,5 @@ +use cosmwasm_std::testing::MockApi; use cosmwasm_std::{Addr, Api, Empty, Storage}; -use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; use cw_multi_test::error::AnyResult; use cw_multi_test::{no_init, AddressGenerator, AppBuilder, Executor, WasmKeeper}; @@ -7,14 +7,9 @@ use crate::test_contracts; #[test] fn contract_address_should_work() { - // prepare wasm module with custom address generator - let wasm_keeper: WasmKeeper = - WasmKeeper::new().with_address_generator(MockAddressGenerator); - // prepare application with custom API let mut app = AppBuilder::default() - .with_api(MockApiBech32::new("purple")) - .with_wasm(wasm_keeper) + .with_api(MockApi::default().with_prefix("purple")) .build(no_init); // prepare user addresses @@ -60,7 +55,9 @@ fn custom_address_generator_should_work() { _code_id: u64, _instance_id: u64, ) -> AnyResult { - Ok(MockApiBech32::new("osmo").addr_make("test_addr")) + Ok(MockApi::default() + .with_prefix("osmo") + .addr_make("test_addr")) } } @@ -83,20 +80,18 @@ fn custom_address_generator_should_work() { // make sure that contract address equals to value generated by custom address generator assert_eq!( contract_addr.as_str(), - MockApiBech32::new("osmo").addr_make("test_addr").as_str() + MockApi::default() + .with_prefix("osmo") + .addr_make("test_addr") + .as_str() ); } #[test] fn predictable_contract_address_should_work() { - // prepare wasm module with custom address generator - let wasm_keeper: WasmKeeper = - WasmKeeper::new().with_address_generator(MockAddressGenerator); - // prepare application with custom api let mut app = AppBuilder::default() - .with_api(MockApiBech32::new("juno")) - .with_wasm(wasm_keeper) + .with_api(MockApi::default().with_prefix("juno")) .build(no_init); let creator = app.api().addr_make("creator"); @@ -146,14 +141,9 @@ fn predictable_contract_address_should_work() { #[test] fn creating_contract_with_the_same_predictable_address_should_fail() { - // prepare wasm module with custom address generator - let wasm_keeper: WasmKeeper = - WasmKeeper::new().with_address_generator(MockAddressGenerator); - // prepare application with custom api let mut app = AppBuilder::default() - .with_api(MockApiBech32::new("juno")) - .with_wasm(wasm_keeper) + .with_api(MockApi::default().with_prefix("juno")) .build(no_init); let creator = app.api().addr_make("creator"); From df918d9648b63a1336de0644f65d208b7e746844 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 14:21:59 +0100 Subject: [PATCH 074/250] Removed deprecated staking sudo variant. --- src/staking.rs | 65 +++++++++------------ tests/test_app_builder/test_with_staking.rs | 20 +------ 2 files changed, 32 insertions(+), 53 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 136c8483..abcdcf33 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -115,11 +115,6 @@ pub enum StakingSudo { /// Percentage of the validator's stake. percentage: Decimal, }, - /// Causes the unbonding queue to be processed. - /// This needs to be triggered manually, since there is no good place to do this right now. - /// In cosmos-sdk, this is done in `EndBlock`, but we don't have that here. - #[deprecated(note = "This is not needed anymore. Just call `update_block`")] - ProcessQueue {}, } /// A trait defining a behavior of the stake keeper. @@ -132,11 +127,13 @@ pub trait Staking: Module( &self, - api: &dyn Api, - storage: &mut dyn Storage, - router: &dyn CosmosRouter, - block: &BlockInfo, - ) -> AnyResult; + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + ) -> AnyResult { + Ok(AppResponse::default()) + } } /// A trait defining a behavior of the distribution keeper. @@ -747,32 +744,6 @@ impl Module for StakeKeeper { } } - fn sudo( - &self, - api: &dyn Api, - storage: &mut dyn Storage, - router: &dyn CosmosRouter, - block: &BlockInfo, - msg: StakingSudo, - ) -> AnyResult { - match msg { - StakingSudo::Slash { - validator, - percentage, - } => { - let mut staking_storage = prefixed(storage, NAMESPACE_STAKING); - let validator = api.addr_validate(&validator)?; - self.validate_percentage(percentage)?; - - self.slash(api, &mut staking_storage, block, &validator, percentage)?; - - Ok(AppResponse::default()) - } - #[allow(deprecated)] - StakingSudo::ProcessQueue {} => self.process_queue(api, storage, router, block), - } - } - fn query( &self, api: &dyn Api, @@ -870,6 +841,28 @@ impl Module for StakeKeeper { q => bail!("Unsupported staking sudo message: {:?}", q), } } + + fn sudo( + &self, + api: &dyn Api, + storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + block: &BlockInfo, + msg: StakingSudo, + ) -> AnyResult { + match msg { + StakingSudo::Slash { + validator, + percentage, + } => { + let mut staking_storage = prefixed(storage, NAMESPACE_STAKING); + let validator = api.addr_validate(&validator)?; + self.validate_percentage(percentage)?; + self.slash(api, &mut staking_storage, block, &validator, percentage)?; + Ok(AppResponse::default()) + } + } + } } /// A structure representing a default distribution keeper. diff --git a/tests/test_app_builder/test_with_staking.rs b/tests/test_app_builder/test_with_staking.rs index 784bab95..ac429062 100644 --- a/tests/test_app_builder/test_with_staking.rs +++ b/tests/test_app_builder/test_with_staking.rs @@ -1,24 +1,10 @@ use crate::test_app_builder::MyKeeper; -use cosmwasm_std::{Api, BlockInfo, Coin, CustomQuery, StakingMsg, StakingQuery, Storage}; -use cw_multi_test::error::AnyResult; -use cw_multi_test::{ - no_init, AppBuilder, AppResponse, CosmosRouter, Executor, Staking, StakingSudo, -}; +use cosmwasm_std::{Coin, StakingMsg, StakingQuery}; +use cw_multi_test::{no_init, AppBuilder, Executor, Staking, StakingSudo}; type MyStakeKeeper = MyKeeper; -impl Staking for MyStakeKeeper { - fn process_queue( - &self, - api: &dyn Api, - storage: &mut dyn Storage, - router: &dyn CosmosRouter, - block: &BlockInfo, - ) -> AnyResult { - let _ = (api, storage, router, block); - todo!() - } -} +impl Staking for MyStakeKeeper {} const EXECUTE_MSG: &str = "staking execute called"; const QUERY_MSG: &str = "staking query called"; From c65422c9c9d8ec111f7a29793aa80e42c92ba2e1 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 14:27:51 +0100 Subject: [PATCH 075/250] Updates. --- src/wasm.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/wasm.rs b/src/wasm.rs index 20d59523..6ef2efa6 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -225,7 +225,6 @@ where msg: Binary, ) -> AnyResult { let custom_event = Event::new("sudo").add_attribute(CONTRACT_ATTR, &contract); - let res = self.call_sudo(contract.clone(), api, storage, router, block, msg.to_vec())?; let (res, msgs) = self.build_app_response(&contract, custom_event, res); self.process_response(api, router, storage, block, contract, res, msgs) From cfdd6cfa1e1c2b7e770b9070a2c9f9665a1bc67b Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 9 Feb 2024 14:40:49 +0100 Subject: [PATCH 076/250] Refactored WasmSudo. --- src/app.rs | 14 ++--- src/tests/test_app.rs | 2 +- src/wasm.rs | 79 +++++++++++++----------- tests/test_app_builder/test_with_wasm.rs | 5 +- 4 files changed, 51 insertions(+), 49 deletions(-) diff --git a/src/app.rs b/src/app.rs index 27bab476..5bfba9e9 100644 --- a/src/app.rs +++ b/src/app.rs @@ -412,7 +412,10 @@ where contract_addr: U, msg: &T, ) -> AnyResult { - let msg = to_json_binary(msg)?; + let msg = WasmSudo { + contract_addr: contract_addr.into(), + message: to_json_binary(msg)?, + }; let Self { block, @@ -422,9 +425,7 @@ where } = self; transactional(&mut *storage, |write_cache, _| { - router - .wasm - .sudo(&*api, contract_addr.into(), write_cache, router, block, msg) + router.wasm.sudo(&*api, write_cache, router, block, msg) }) } @@ -641,10 +642,7 @@ where msg: SudoMsg, ) -> AnyResult { match msg { - SudoMsg::Wasm(msg) => { - self.wasm - .sudo(api, msg.contract_addr, storage, self, block, msg.msg) - } + SudoMsg::Wasm(msg) => self.wasm.sudo(api, storage, self, block, msg), SudoMsg::Bank(msg) => self.bank.sudo(api, storage, self, block, msg), SudoMsg::Staking(msg) => self.staking.sudo(api, storage, self, block, msg), SudoMsg::Custom(_) => unimplemented!(), diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index a8e96bdd..e2d48018 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -587,7 +587,7 @@ fn sudo_works() { let msg = payout::SudoMsg { set_count: 49 }; let sudo_msg = WasmSudo { contract_addr: payout_addr.clone(), - msg: to_json_binary(&msg).unwrap(), + message: to_json_binary(&msg).unwrap(), }; app.sudo(sudo_msg.into()).unwrap(); diff --git a/src/wasm.rs b/src/wasm.rs index 6ef2efa6..55460d05 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -35,8 +35,8 @@ const CONTRACT_ATTR: &str = "_contract_address"; pub struct WasmSudo { /// Address of a contract the privileged action will be sent to. pub contract_addr: Addr, - /// Message representing privileged action to be executed by contract `sudo` entry-point. - pub msg: Binary, + /// Message representing privileged action to be executed by contract's `sudo` entry-point. + pub message: Binary, } impl WasmSudo { @@ -44,7 +44,7 @@ impl WasmSudo { pub fn new(contract_addr: &Addr, msg: &T) -> StdResult { Ok(WasmSudo { contract_addr: contract_addr.clone(), - msg: to_json_binary(msg)?, + message: to_json_binary(msg)?, }) } } @@ -79,16 +79,6 @@ struct CodeData { /// This trait is crucial for testing smart contracts written in languages that compile to WebAssembly, /// which is common in the Cosmos and CosmWasm ecosystems. pub trait Wasm { - /// Handles all `WasmQuery` requests. - fn query( - &self, - api: &dyn Api, - storage: &dyn Storage, - querier: &dyn Querier, - block: &BlockInfo, - request: WasmQuery, - ) -> AnyResult; - /// Handles all `WasmMsg` messages. fn execute( &self, @@ -100,15 +90,24 @@ pub trait Wasm { msg: WasmMsg, ) -> AnyResult; + /// Handles all `WasmQuery` requests. + fn query( + &self, + api: &dyn Api, + storage: &dyn Storage, + querier: &dyn Querier, + block: &BlockInfo, + request: WasmQuery, + ) -> AnyResult; + /// Handles all sudo messages, this is an admin interface and can not be called via `CosmosMsg`. fn sudo( &self, api: &dyn Api, - contract_addr: Addr, storage: &mut dyn Storage, router: &dyn CosmosRouter, block: &BlockInfo, - msg: Binary, + msg: WasmSudo, ) -> AnyResult; /// Stores the contract's code and returns an identifier of the stored contract's code. @@ -157,6 +156,22 @@ where ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { + fn execute( + &self, + api: &dyn Api, + storage: &mut dyn Storage, + router: &dyn CosmosRouter, + block: &BlockInfo, + sender: Addr, + msg: WasmMsg, + ) -> AnyResult { + self.execute_wasm(api, storage, router, block, sender.clone(), msg.clone()) + .context(format!( + "Error executing WasmMsg:\n sender: {}\n {:?}", + sender, msg + )) + } + fn query( &self, api: &dyn Api, @@ -199,35 +214,25 @@ where } } - fn execute( - &self, - api: &dyn Api, - storage: &mut dyn Storage, - router: &dyn CosmosRouter, - block: &BlockInfo, - sender: Addr, - msg: WasmMsg, - ) -> AnyResult { - self.execute_wasm(api, storage, router, block, sender.clone(), msg.clone()) - .context(format!( - "Error executing WasmMsg:\n sender: {}\n {:?}", - sender, msg - )) - } - fn sudo( &self, api: &dyn Api, - contract: Addr, storage: &mut dyn Storage, router: &dyn CosmosRouter, block: &BlockInfo, - msg: Binary, + msg: WasmSudo, ) -> AnyResult { - let custom_event = Event::new("sudo").add_attribute(CONTRACT_ATTR, &contract); - let res = self.call_sudo(contract.clone(), api, storage, router, block, msg.to_vec())?; - let (res, msgs) = self.build_app_response(&contract, custom_event, res); - self.process_response(api, router, storage, block, contract, res, msgs) + let custom_event = Event::new("sudo").add_attribute(CONTRACT_ATTR, &msg.contract_addr); + let res = self.call_sudo( + msg.contract_addr.clone(), + api, + storage, + router, + block, + msg.message.to_vec(), + )?; + let (res, msgs) = self.build_app_response(&msg.contract_addr, custom_event, res); + self.process_response(api, router, storage, block, msg.contract_addr, res, msgs) } /// Stores the contract's code in the in-memory lookup table. diff --git a/tests/test_app_builder/test_with_wasm.rs b/tests/test_app_builder/test_with_wasm.rs index 31e772e8..72dbcd1c 100644 --- a/tests/test_app_builder/test_with_wasm.rs +++ b/tests/test_app_builder/test_with_wasm.rs @@ -51,11 +51,10 @@ impl Wasm for MyWasmKeeper { fn sudo( &self, _api: &dyn Api, - _contract_addr: Addr, _storage: &mut dyn Storage, _router: &dyn CosmosRouter, _block: &BlockInfo, - _msg: Binary, + _msg: WasmSudo, ) -> AnyResult { bail!(self.3); } @@ -132,7 +131,7 @@ fn building_app_with_custom_wasm_should_work() { app.sudo( WasmSudo { contract_addr, - msg: Default::default() + message: Default::default() } .into() ) From baa5961c86a5bfbb338ac8990ad16b1dd1a1823b Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 29 Feb 2024 11:21:15 +0100 Subject: [PATCH 077/250] Updated dependencies, fixed warnings. --- Cargo.lock | 67 +++++++++++++++++---------------- Cargo.toml | 6 +-- src/staking.rs | 4 +- src/tests/test_app.rs | 6 +-- src/wasm.rs | 4 +- tests/test_api/test_prefixed.rs | 2 +- 6 files changed, 43 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 57696d74..fb5e1142 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom", "once_cell", @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" dependencies = [ "backtrace", ] @@ -76,6 +76,12 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +[[package]] +name = "bech32" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" + [[package]] name = "block-buffer" version = "0.9.0" @@ -114,12 +120,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" [[package]] name = "cfg-if" @@ -186,7 +189,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cb9f0cb520832e993af5cbe97bc3c163bd0c3870989e99d5f1d5499e6f28a53" dependencies = [ "base64", - "bech32", + "bech32 0.9.1", "bnum", "cosmwasm-crypto", "cosmwasm-derive", @@ -250,7 +253,7 @@ name = "cw-multi-test" version = "2.0.0-rc.0" dependencies = [ "anyhow", - "bech32", + "bech32 0.11.0", "cosmwasm-std", "cw-storage-plus", "cw-utils", @@ -334,9 +337,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "ecdsa" @@ -369,9 +372,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "elliptic-curve" @@ -596,7 +599,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -641,9 +644,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "schemars" @@ -685,9 +688,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -703,13 +706,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -725,9 +728,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -803,9 +806,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -814,22 +817,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e7be4da8..2503e167 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,8 +14,8 @@ backtrace = ["anyhow/backtrace"] cosmwasm_2_0 = ["cosmwasm-std/cosmwasm_2_0"] [dependencies] -anyhow = "1.0.79" -bech32 = "0.9.1" +anyhow = "1.0.80" +bech32 = "0.11.0" cosmwasm-std = { version = "2.0.0-rc.1", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "2.0.0-rc.0" cw-utils = "2.0.0-rc.0" @@ -25,7 +25,7 @@ prost = "0.12.3" schemars = "0.8.16" serde = "1.0.196" sha2 = "0.10.8" -thiserror = "1.0.56" +thiserror = "1.0.57" [dev-dependencies] hex = "0.4.3" diff --git a/src/staking.rs b/src/staking.rs index abcdcf33..ff887ccc 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1446,9 +1446,7 @@ mod test { } mod msg { - use cosmwasm_std::{ - coins, Addr, BondedDenomResponse, Decimal, QuerierWrapper, StakingQuery, - }; + use cosmwasm_std::{coins, QuerierWrapper}; use serde::de::DeserializeOwned; use super::*; diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index e2d48018..f5dc5351 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -885,7 +885,7 @@ fn sent_funds_properly_visible_on_execution() { /// via a custom module, as an example of ability to do privileged actions. mod custom_handler { use super::*; - use crate::{BankSudo, BasicAppBuilder, CosmosRouter}; + use crate::{BankSudo, BasicAppBuilder}; const LOTTERY: Item = Item::new("lottery"); const PITY: Item = Item::new("pity"); @@ -1024,9 +1024,6 @@ mod custom_handler { mod reply_data_overwrite { use super::*; - use cosmwasm_std::to_json_binary; - - use echo::EXECUTE_REPLY_BASE_ID; fn make_echo_submsg( contract: Addr, @@ -1855,7 +1852,6 @@ mod protobuf_wrapped_data { mod errors { use super::*; - use cosmwasm_std::to_json_binary; #[test] fn simple_instantiation() { diff --git a/src/wasm.rs b/src/wasm.rs index 55460d05..2117d294 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1204,8 +1204,8 @@ mod test { use crate::{GovFailingModule, IbcFailingModule}; use cosmwasm_std::testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage}; use cosmwasm_std::{ - coin, from_json, to_json_vec, BankMsg, CanonicalAddr, CodeInfoResponse, Coin, CosmosMsg, - Empty, HexBinary, StdError, + coin, from_json, to_json_vec, CanonicalAddr, CodeInfoResponse, CosmosMsg, Empty, HexBinary, + StdError, }; /// Type alias for default build `Router` to make its reference in typical scenario diff --git a/tests/test_api/test_prefixed.rs b/tests/test_api/test_prefixed.rs index 0af6a8ca..1feff2d5 100644 --- a/tests/test_api/test_prefixed.rs +++ b/tests/test_api/test_prefixed.rs @@ -1,6 +1,6 @@ use super::*; use cosmwasm_std::testing::MockApi; -use cosmwasm_std::{Api, CanonicalAddr}; +use cosmwasm_std::CanonicalAddr; const HUMAN_ADDRESS: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"; From 95dd2401d5f22ec542a889ed072d6124e798c7c2 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 1 Mar 2024 14:01:45 +0100 Subject: [PATCH 078/250] Updates. --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb5e1142..6099f8c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -556,9 +556,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "pkcs8" From 0fee7978a70db3a14f8c9e3ce2eb5be509598277 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 1 Mar 2024 14:33:35 +0100 Subject: [PATCH 079/250] Updates. --- Cargo.lock | 9 +-------- Cargo.toml | 1 - 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6099f8c4..d08b4be9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,12 +76,6 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" -[[package]] -name = "bech32" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" - [[package]] name = "block-buffer" version = "0.9.0" @@ -189,7 +183,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cb9f0cb520832e993af5cbe97bc3c163bd0c3870989e99d5f1d5499e6f28a53" dependencies = [ "base64", - "bech32 0.9.1", + "bech32", "bnum", "cosmwasm-crypto", "cosmwasm-derive", @@ -253,7 +247,6 @@ name = "cw-multi-test" version = "2.0.0-rc.0" dependencies = [ "anyhow", - "bech32 0.11.0", "cosmwasm-std", "cw-storage-plus", "cw-utils", diff --git a/Cargo.toml b/Cargo.toml index 2503e167..5a503526 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ cosmwasm_2_0 = ["cosmwasm-std/cosmwasm_2_0"] [dependencies] anyhow = "1.0.80" -bech32 = "0.11.0" cosmwasm-std = { version = "2.0.0-rc.1", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "2.0.0-rc.0" cw-utils = "2.0.0-rc.0" From e15577d4f28d422564d6935df0ec95aa7f772c6f Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 1 Mar 2024 14:49:56 +0100 Subject: [PATCH 080/250] Fixed dependencies. --- Cargo.lock | 108 +++++++++++----------- Cargo.toml | 11 ++- src/staking.rs | 4 +- src/tests/test_app.rs | 6 +- src/wasm.rs | 5 +- tests/test_addons/test_api/test_bech32.rs | 2 +- 6 files changed, 63 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4173657e..a9a3e947 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom", "once_cell", @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" dependencies = [ "backtrace", ] @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "bnum" -version = "0.8.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab9008b6bb9fc80b5277f2fe481c09e828743d9151203e804583eb4c9e15b31d" +checksum = "56953345e39537a3e18bdaeba4cb0c58a78c1f61f361dc0fa7c5c7340ae87c5f" [[package]] name = "byteorder" @@ -114,12 +114,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" [[package]] name = "cfg-if" @@ -135,9 +132,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-crypto" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ed6aa9f904de106fa16443ad14ec2abe75e94ba003bb61c681c0e43d4c58d2a" +checksum = "9934c79e58d9676edfd592557dee765d2a6ef54c09d5aa2edb06156b00148966" dependencies = [ "digest 0.10.7", "ecdsa", @@ -149,18 +146,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40abec852f3d4abec6d44ead9a58b78325021a1ead1e7229c3471414e57b2e49" +checksum = "bc5e72e330bd3bdab11c52b5ecbdeb6a8697a004c57964caeb5d876f0b088b3c" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b166215fbfe93dc5575bae062aa57ae7bb41121cffe53bac33b033257949d2a9" +checksum = "ac3e3a2136e2a60e8b6582f5dffca5d1a683ed77bf38537d330bc1dfccd69010" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -171,9 +168,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf12f8e20bb29d1db66b7ca590bc2f670b548d21e9be92499bc0f9022a994a8" +checksum = "f5d803bea6bd9ed61bd1ee0b4a2eb09ee20dbb539cc6e0b8795614d20952ebb1" dependencies = [ "proc-macro2", "quote", @@ -182,9 +179,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad011ae7447188e26e4a7dbca2fcd0fc186aa21ae5c86df0503ea44c78f9e469" +checksum = "ef8666e572a3a2519010dde88c04d16e9339ae751b56b2bb35081fe3f7d6be74" dependencies = [ "base64", "bech32", @@ -252,13 +249,14 @@ version = "0.20.0" dependencies = [ "anyhow", "bech32", + "bnum", "cosmwasm-std", "cw-storage-plus", "cw-utils", "derivative", "hex", "hex-literal", - "itertools 0.12.0", + "itertools 0.12.1", "once_cell", "prost", "schemars", @@ -352,9 +350,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "ecdsa" @@ -387,9 +385,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "elliptic-curve" @@ -506,9 +504,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] @@ -521,9 +519,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "k256" -version = "0.13.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ "cfg-if", "ecdsa", @@ -535,9 +533,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.152" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "memchr" @@ -547,9 +545,9 @@ checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] @@ -571,9 +569,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "pkcs8" @@ -614,7 +612,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -659,9 +657,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "schemars" @@ -703,15 +701,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -727,13 +725,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -749,9 +747,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -827,9 +825,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -838,22 +836,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 22f97897..ba9ce118 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,18 +17,19 @@ cosmwasm_1_3 = ["cosmwasm_1_2", "cosmwasm-std/cosmwasm_1_3"] cosmwasm_1_4 = ["cosmwasm_1_3", "cosmwasm-std/cosmwasm_1_4"] [dependencies] -anyhow = "1.0.79" +anyhow = "1.0.80" bech32 = "0.9.1" -cosmwasm-std = { version = "1.5.2", features = ["iterator", "staking", "stargate"] } +cosmwasm-std = { version = "1.5.3", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "1.2.0" cw-utils = "1.0.3" derivative = "2.2.0" -itertools = "0.12.0" +itertools = "0.12.1" prost = "0.12.3" schemars = "0.8.16" -serde = "1.0.196" +serde = "1.0.197" sha2 = "0.10.8" -thiserror = "1.0.56" +thiserror = "1.0.57" +bnum = "0.10.0" [dev-dependencies] hex = "0.4.3" diff --git a/src/staking.rs b/src/staking.rs index 9d8166fa..4c49ad57 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1462,9 +1462,7 @@ mod test { } mod msg { - use cosmwasm_std::{ - coins, Addr, BondedDenomResponse, Decimal, QuerierWrapper, StakingQuery, - }; + use cosmwasm_std::{coins, QuerierWrapper}; use serde::de::DeserializeOwned; use super::*; diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 58ae2924..95a0c82c 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -850,7 +850,7 @@ fn sent_funds_properly_visible_on_execution() { /// via a custom module, as an example of ability to do privileged actions. mod custom_handler { use super::*; - use crate::{BankSudo, BasicAppBuilder, CosmosRouter}; + use crate::{BankSudo, BasicAppBuilder}; const LOTTERY: Item = Item::new("lottery"); const PITY: Item = Item::new("pity"); @@ -988,9 +988,6 @@ mod custom_handler { mod reply_data_overwrite { use super::*; - use cosmwasm_std::to_json_binary; - - use echo::EXECUTE_REPLY_BASE_ID; fn make_echo_submsg( contract: Addr, @@ -1819,7 +1816,6 @@ mod protobuf_wrapped_data { mod errors { use super::*; - use cosmwasm_std::to_json_binary; #[test] fn simple_instantiation() { diff --git a/src/wasm.rs b/src/wasm.rs index dac40c86..9ffce731 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1206,10 +1206,7 @@ mod test { use crate::transactions::StorageTransaction; use crate::{GovFailingModule, IbcFailingModule}; use cosmwasm_std::testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage}; - use cosmwasm_std::{ - coin, from_json, to_json_vec, BankMsg, CanonicalAddr, Coin, CosmosMsg, Empty, HexBinary, - StdError, - }; + use cosmwasm_std::{coin, from_json, to_json_vec, CanonicalAddr, CosmosMsg, Empty, StdError}; /// Type alias for default build `Router` to make its reference in typical scenario type BasicRouter = Router< diff --git a/tests/test_addons/test_api/test_bech32.rs b/tests/test_addons/test_api/test_bech32.rs index 4b5101ef..c99de049 100644 --- a/tests/test_addons/test_api/test_bech32.rs +++ b/tests/test_addons/test_api/test_bech32.rs @@ -1,5 +1,5 @@ use super::*; -use cosmwasm_std::{Api, CanonicalAddr}; +use cosmwasm_std::CanonicalAddr; use cw_multi_test::addons::{MockApiBech32, MockApiBech32m}; const HUMAN_ADDRESS: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"; From 0eab8658aff63e000b1e8506a1544e2df4168ebb Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 1 Mar 2024 15:02:52 +0100 Subject: [PATCH 081/250] Fixed dependencies. --- Cargo.lock | 107 +++++++++++----------- Cargo.toml | 10 +- src/staking.rs | 4 +- src/tests/test_app.rs | 6 +- src/wasm.rs | 5 +- tests/test_addons/test_api/test_bech32.rs | 2 +- 6 files changed, 61 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4173657e..168d7d20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom", "once_cell", @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" dependencies = [ "backtrace", ] @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "bnum" -version = "0.8.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab9008b6bb9fc80b5277f2fe481c09e828743d9151203e804583eb4c9e15b31d" +checksum = "56953345e39537a3e18bdaeba4cb0c58a78c1f61f361dc0fa7c5c7340ae87c5f" [[package]] name = "byteorder" @@ -114,12 +114,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" [[package]] name = "cfg-if" @@ -135,9 +132,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-crypto" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ed6aa9f904de106fa16443ad14ec2abe75e94ba003bb61c681c0e43d4c58d2a" +checksum = "9934c79e58d9676edfd592557dee765d2a6ef54c09d5aa2edb06156b00148966" dependencies = [ "digest 0.10.7", "ecdsa", @@ -149,18 +146,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40abec852f3d4abec6d44ead9a58b78325021a1ead1e7229c3471414e57b2e49" +checksum = "bc5e72e330bd3bdab11c52b5ecbdeb6a8697a004c57964caeb5d876f0b088b3c" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b166215fbfe93dc5575bae062aa57ae7bb41121cffe53bac33b033257949d2a9" +checksum = "ac3e3a2136e2a60e8b6582f5dffca5d1a683ed77bf38537d330bc1dfccd69010" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -171,9 +168,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf12f8e20bb29d1db66b7ca590bc2f670b548d21e9be92499bc0f9022a994a8" +checksum = "f5d803bea6bd9ed61bd1ee0b4a2eb09ee20dbb539cc6e0b8795614d20952ebb1" dependencies = [ "proc-macro2", "quote", @@ -182,9 +179,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad011ae7447188e26e4a7dbca2fcd0fc186aa21ae5c86df0503ea44c78f9e469" +checksum = "ef8666e572a3a2519010dde88c04d16e9339ae751b56b2bb35081fe3f7d6be74" dependencies = [ "base64", "bech32", @@ -258,7 +255,7 @@ dependencies = [ "derivative", "hex", "hex-literal", - "itertools 0.12.0", + "itertools 0.12.1", "once_cell", "prost", "schemars", @@ -352,9 +349,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "ecdsa" @@ -387,9 +384,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "elliptic-curve" @@ -506,9 +503,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] @@ -521,9 +518,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "k256" -version = "0.13.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ "cfg-if", "ecdsa", @@ -535,9 +532,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.152" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "memchr" @@ -547,9 +544,9 @@ checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] @@ -571,9 +568,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "pkcs8" @@ -614,7 +611,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -659,9 +656,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "schemars" @@ -703,15 +700,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -727,13 +724,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -749,9 +746,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -827,9 +824,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -838,22 +835,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 22f97897..efba827d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,18 +17,18 @@ cosmwasm_1_3 = ["cosmwasm_1_2", "cosmwasm-std/cosmwasm_1_3"] cosmwasm_1_4 = ["cosmwasm_1_3", "cosmwasm-std/cosmwasm_1_4"] [dependencies] -anyhow = "1.0.79" +anyhow = "1.0.80" bech32 = "0.9.1" -cosmwasm-std = { version = "1.5.2", features = ["iterator", "staking", "stargate"] } +cosmwasm-std = { version = "1.5.3", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "1.2.0" cw-utils = "1.0.3" derivative = "2.2.0" -itertools = "0.12.0" +itertools = "0.12.1" prost = "0.12.3" schemars = "0.8.16" -serde = "1.0.196" +serde = "1.0.197" sha2 = "0.10.8" -thiserror = "1.0.56" +thiserror = "1.0.57" [dev-dependencies] hex = "0.4.3" diff --git a/src/staking.rs b/src/staking.rs index 9d8166fa..4c49ad57 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1462,9 +1462,7 @@ mod test { } mod msg { - use cosmwasm_std::{ - coins, Addr, BondedDenomResponse, Decimal, QuerierWrapper, StakingQuery, - }; + use cosmwasm_std::{coins, QuerierWrapper}; use serde::de::DeserializeOwned; use super::*; diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 58ae2924..95a0c82c 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -850,7 +850,7 @@ fn sent_funds_properly_visible_on_execution() { /// via a custom module, as an example of ability to do privileged actions. mod custom_handler { use super::*; - use crate::{BankSudo, BasicAppBuilder, CosmosRouter}; + use crate::{BankSudo, BasicAppBuilder}; const LOTTERY: Item = Item::new("lottery"); const PITY: Item = Item::new("pity"); @@ -988,9 +988,6 @@ mod custom_handler { mod reply_data_overwrite { use super::*; - use cosmwasm_std::to_json_binary; - - use echo::EXECUTE_REPLY_BASE_ID; fn make_echo_submsg( contract: Addr, @@ -1819,7 +1816,6 @@ mod protobuf_wrapped_data { mod errors { use super::*; - use cosmwasm_std::to_json_binary; #[test] fn simple_instantiation() { diff --git a/src/wasm.rs b/src/wasm.rs index dac40c86..9ffce731 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1206,10 +1206,7 @@ mod test { use crate::transactions::StorageTransaction; use crate::{GovFailingModule, IbcFailingModule}; use cosmwasm_std::testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage}; - use cosmwasm_std::{ - coin, from_json, to_json_vec, BankMsg, CanonicalAddr, Coin, CosmosMsg, Empty, HexBinary, - StdError, - }; + use cosmwasm_std::{coin, from_json, to_json_vec, CanonicalAddr, CosmosMsg, Empty, StdError}; /// Type alias for default build `Router` to make its reference in typical scenario type BasicRouter = Router< diff --git a/tests/test_addons/test_api/test_bech32.rs b/tests/test_addons/test_api/test_bech32.rs index 4b5101ef..c99de049 100644 --- a/tests/test_addons/test_api/test_bech32.rs +++ b/tests/test_addons/test_api/test_bech32.rs @@ -1,5 +1,5 @@ use super::*; -use cosmwasm_std::{Api, CanonicalAddr}; +use cosmwasm_std::CanonicalAddr; use cw_multi_test::addons::{MockApiBech32, MockApiBech32m}; const HUMAN_ADDRESS: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"; From 37e943cbd7d6a2f2ff4fffb7811cc85c67a22e3b Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 1 Mar 2024 15:16:40 +0100 Subject: [PATCH 082/250] Renamed modules. --- src/addons/api/{bech32.rs => b32.rs} | 0 src/addons/api/{bech32m.rs => b32m.rs} | 0 src/addons/api/mod.rs | 4 ++-- src/addons/mod.rs | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/addons/api/{bech32.rs => b32.rs} (100%) rename src/addons/api/{bech32m.rs => b32m.rs} (100%) diff --git a/src/addons/api/bech32.rs b/src/addons/api/b32.rs similarity index 100% rename from src/addons/api/bech32.rs rename to src/addons/api/b32.rs diff --git a/src/addons/api/bech32m.rs b/src/addons/api/b32m.rs similarity index 100% rename from src/addons/api/bech32m.rs rename to src/addons/api/b32m.rs diff --git a/src/addons/api/mod.rs b/src/addons/api/mod.rs index d59bbae5..ebbd9cc7 100644 --- a/src/addons/api/mod.rs +++ b/src/addons/api/mod.rs @@ -1,2 +1,2 @@ -pub mod bech32; -pub mod bech32m; +pub mod b32; +pub mod b32m; diff --git a/src/addons/mod.rs b/src/addons/mod.rs index 5dd4401b..648c9b5f 100644 --- a/src/addons/mod.rs +++ b/src/addons/mod.rs @@ -8,5 +8,5 @@ mod addresses; mod api; pub use addresses::mock::MockAddressGenerator; -pub use api::bech32::MockApiBech32; -pub use api::bech32m::MockApiBech32m; +pub use api::b32::MockApiBech32; +pub use api::b32m::MockApiBech32m; From 19aa38b596070daa77594b9d37d31d0fc82e4677 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 1 Mar 2024 15:20:19 +0100 Subject: [PATCH 083/250] Updates. --- src/addons/api/b32.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/addons/api/b32.rs b/src/addons/api/b32.rs index 923b3961..d3349b25 100644 --- a/src/addons/api/b32.rs +++ b/src/addons/api/b32.rs @@ -5,7 +5,7 @@ use cosmwasm_std::{ }; use sha2::{Digest, Sha256}; -/// Implementation of the [Api](cosmwasm_std::Api) trait that uses [Bech32] format +/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32] format /// for humanizing canonical addresses. /// /// [Bech32]: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki @@ -45,7 +45,7 @@ impl MockApiBech32 { } impl Api for MockApiBech32 { - /// Takes a human readable address in **Bech32** format and checks if it is valid. + /// Takes a human-readable address in **Bech32** format and checks if it is valid. /// /// If the validation succeeds, an `Addr` containing the same string as the input is returned. /// @@ -64,7 +64,7 @@ impl Api for MockApiBech32 { self.addr_humanize(&self.addr_canonicalize(input)?) } - /// Takes a human readable address in **Bech32** format and returns + /// Takes a human-readable address in **Bech32** format and returns /// a canonical binary representation of it. /// /// # Example @@ -89,7 +89,7 @@ impl Api for MockApiBech32 { Err(StdError::generic_err("Invalid input")) } - /// Takes a canonical address and returns a human readable address in **Bech32** format. + /// Takes a canonical address and returns a human-readable address in **Bech32** format. /// /// This is the inverse operation of [`addr_canonicalize`]. /// From 8cd30e6a675e6baf5f44added90ea356b3dbadff Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 1 Mar 2024 15:40:04 +0100 Subject: [PATCH 084/250] Updates. --- Cargo.lock | 1 - Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9a3e947..168d7d20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -249,7 +249,6 @@ version = "0.20.0" dependencies = [ "anyhow", "bech32", - "bnum", "cosmwasm-std", "cw-storage-plus", "cw-utils", diff --git a/Cargo.toml b/Cargo.toml index ba9ce118..efba827d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,6 @@ schemars = "0.8.16" serde = "1.0.197" sha2 = "0.10.8" thiserror = "1.0.57" -bnum = "0.10.0" [dev-dependencies] hex = "0.4.3" From 4a4384b75b04f689d412a7b31fa0b924b6fe9e15 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 1 Mar 2024 16:50:17 +0100 Subject: [PATCH 085/250] Hrp must be fixed in tests. --- Cargo.lock | 10 +++++-- Cargo.toml | 2 +- src/addons/api/b32.rs | 29 ++++++++------------ src/addons/api/b32m.rs | 62 ++++++++++++++++++++++++++++++------------ 4 files changed, 66 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 168d7d20..b62107ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,6 +76,12 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +[[package]] +name = "bech32" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" + [[package]] name = "block-buffer" version = "0.9.0" @@ -184,7 +190,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef8666e572a3a2519010dde88c04d16e9339ae751b56b2bb35081fe3f7d6be74" dependencies = [ "base64", - "bech32", + "bech32 0.9.1", "bnum", "cosmwasm-crypto", "cosmwasm-derive", @@ -248,7 +254,7 @@ name = "cw-multi-test" version = "0.20.0" dependencies = [ "anyhow", - "bech32", + "bech32 0.11.0", "cosmwasm-std", "cw-storage-plus", "cw-utils", diff --git a/Cargo.toml b/Cargo.toml index efba827d..3d0304e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ cosmwasm_1_4 = ["cosmwasm_1_3", "cosmwasm-std/cosmwasm_1_4"] [dependencies] anyhow = "1.0.80" -bech32 = "0.9.1" +bech32 = "0.11.0" cosmwasm-std = { version = "1.5.3", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "1.2.0" cw-utils = "1.0.3" diff --git a/src/addons/api/b32.rs b/src/addons/api/b32.rs index d3349b25..7468eee2 100644 --- a/src/addons/api/b32.rs +++ b/src/addons/api/b32.rs @@ -1,4 +1,5 @@ -use bech32::{decode, encode, FromBase32, ToBase32, Variant}; +use bech32::primitives::decode::CheckedHrpstring; +use bech32::{encode, Bech32, Hrp}; use cosmwasm_std::testing::MockApi; use cosmwasm_std::{ Addr, Api, CanonicalAddr, RecoverPubkeyError, StdError, StdResult, VerificationError, @@ -12,7 +13,6 @@ use sha2::{Digest, Sha256}; pub struct MockApiBech32 { api: MockApi, prefix: &'static str, - variant: Variant, } impl MockApiBech32 { @@ -30,16 +30,9 @@ impl MockApiBech32 { /// "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"); /// ``` pub fn new(prefix: &'static str) -> Self { - Self::new_with_variant(prefix, Variant::Bech32) - } - - /// Creates `Api` implementation that uses specified prefix - /// to generate addresses in format defined by provided Bech32 variant. - pub(crate) fn new_with_variant(prefix: &'static str, variant: Variant) -> Self { Self { api: MockApi::default(), prefix, - variant, } } } @@ -79,11 +72,9 @@ impl Api for MockApiBech32 { /// "BC6BFD848EBD7819C9A82BF124D65E7F739D08E002601E23BB906AACD40A3D81"); /// ``` fn addr_canonicalize(&self, input: &str) -> StdResult { - if let Ok((prefix, decoded, variant)) = decode(input) { - if prefix == self.prefix && variant == self.variant { - if let Ok(bytes) = Vec::::from_base32(&decoded) { - return Ok(bytes.into()); - } + if let Ok(s) = CheckedHrpstring::new::(input) { + if s.hrp().to_string() == self.prefix { + return Ok(s.byte_iter().collect::>().into()); } } Err(StdError::generic_err("Invalid input")) @@ -108,7 +99,9 @@ impl Api for MockApiBech32 { /// addr.as_str()); /// ``` fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - if let Ok(encoded) = encode(self.prefix, canonical.as_slice().to_base32(), self.variant) { + if let Ok(encoded) = + encode::(Hrp::parse_unchecked(self.prefix), canonical.as_slice()) + { Ok(Addr::unchecked(encoded)) } else { Err(StdError::generic_err("Invalid canonical address")) @@ -178,8 +171,10 @@ impl MockApiBech32 { /// This function panics when generating a valid address in **Bech32** /// format is not possible, especially when prefix is too long or empty. pub fn addr_make(&self, input: &str) -> Addr { - let digest = Sha256::digest(input).to_vec(); - match encode(self.prefix, digest.to_base32(), self.variant) { + match encode::( + Hrp::parse_unchecked(self.prefix), + Sha256::digest(input).as_slice(), + ) { Ok(address) => Addr::unchecked(address), Err(reason) => panic!("Generating address failed with reason: {}", reason), } diff --git a/src/addons/api/b32m.rs b/src/addons/api/b32m.rs index 40311cd1..271a27af 100644 --- a/src/addons/api/b32m.rs +++ b/src/addons/api/b32m.rs @@ -1,12 +1,19 @@ -use crate::addons::MockApiBech32; -use bech32::Variant; -use cosmwasm_std::{Addr, Api, CanonicalAddr, RecoverPubkeyError, StdResult, VerificationError}; +use bech32::primitives::decode::CheckedHrpstring; +use bech32::{encode, Bech32m, Hrp}; +use cosmwasm_std::testing::MockApi; +use cosmwasm_std::{ + Addr, Api, CanonicalAddr, RecoverPubkeyError, StdError, StdResult, VerificationError, +}; +use sha2::{Digest, Sha256}; -/// Implementation of the [Api](cosmwasm_std::Api) trait that uses [Bech32m] format +/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32m] format /// for humanizing canonical addresses. /// /// [Bech32m]: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki -pub struct MockApiBech32m(MockApiBech32); +pub struct MockApiBech32m { + api: MockApi, + prefix: &'static str, +} impl MockApiBech32m { /// Returns `Api` implementation that uses specified prefix @@ -23,12 +30,15 @@ impl MockApiBech32m { /// "osmosis1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qgv9940"); /// ``` pub fn new(prefix: &'static str) -> Self { - Self(MockApiBech32::new_with_variant(prefix, Variant::Bech32m)) + Self { + api: MockApi::default(), + prefix, + } } } impl Api for MockApiBech32m { - /// Takes a human readable address in **Bech32m** format and checks if it is valid. + /// Takes a human-readable address in **Bech32m** format and checks if it is valid. /// /// If the validation succeeds, an `Addr` containing the same string as the input is returned. /// @@ -44,10 +54,10 @@ impl Api for MockApiBech32m { /// addr.as_str()); /// ``` fn addr_validate(&self, input: &str) -> StdResult { - self.0.addr_validate(input) + self.addr_humanize(&self.addr_canonicalize(input)?) } - /// Takes a human readable address in **Bech32m** format and returns + /// Takes a human-readable address in **Bech32m** format and returns /// a canonical binary representation of it. /// /// # Example @@ -62,7 +72,12 @@ impl Api for MockApiBech32m { /// "0A367B92CF0B037DFD89960EE832D56F7FC151681BB41E53690E776F5786998A"); /// ``` fn addr_canonicalize(&self, input: &str) -> StdResult { - self.0.addr_canonicalize(input) + if let Ok(s) = CheckedHrpstring::new::(input) { + if s.hrp().to_string() == self.prefix { + return Ok(s.byte_iter().collect::>().into()); + } + } + Err(StdError::generic_err("Invalid input")) } /// Takes a canonical address and returns a human readable address in **Bech32m** format. @@ -84,7 +99,13 @@ impl Api for MockApiBech32m { /// addr.as_str()); /// ``` fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - self.0.addr_humanize(canonical) + if let Ok(encoded) = + encode::(Hrp::parse_unchecked(self.prefix), canonical.as_slice()) + { + Ok(Addr::unchecked(encoded)) + } else { + Err(StdError::generic_err("Invalid canonical address")) + } } fn secp256k1_verify( @@ -93,7 +114,8 @@ impl Api for MockApiBech32m { signature: &[u8], public_key: &[u8], ) -> Result { - self.0.secp256k1_verify(message_hash, signature, public_key) + self.api + .secp256k1_verify(message_hash, signature, public_key) } fn secp256k1_recover_pubkey( @@ -102,7 +124,7 @@ impl Api for MockApiBech32m { signature: &[u8], recovery_param: u8, ) -> Result, RecoverPubkeyError> { - self.0 + self.api .secp256k1_recover_pubkey(message_hash, signature, recovery_param) } @@ -112,7 +134,7 @@ impl Api for MockApiBech32m { signature: &[u8], public_key: &[u8], ) -> Result { - self.0.ed25519_verify(message, signature, public_key) + self.api.ed25519_verify(message, signature, public_key) } fn ed25519_batch_verify( @@ -121,12 +143,12 @@ impl Api for MockApiBech32m { signatures: &[&[u8]], public_keys: &[&[u8]], ) -> Result { - self.0 + self.api .ed25519_batch_verify(messages, signatures, public_keys) } fn debug(&self, message: &str) { - self.0.debug(message) + self.api.debug(message) } } @@ -149,6 +171,12 @@ impl MockApiBech32m { /// This function panics when generating a valid address in **Bech32** /// format is not possible, especially when prefix is too long or empty. pub fn addr_make(&self, input: &str) -> Addr { - self.0.addr_make(input) + match encode::( + Hrp::parse_unchecked(self.prefix), + Sha256::digest(input).as_slice(), + ) { + Ok(address) => Addr::unchecked(address), + Err(reason) => panic!("Generating address failed with reason: {}", reason), + } } } From caa3f7227b15f688e3ebeaa66d2c8366f9d762b8 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 4 Mar 2024 09:52:07 +0100 Subject: [PATCH 086/250] Updates. --- src/addons/api/b32m.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/addons/api/b32m.rs b/src/addons/api/b32m.rs index 271a27af..1de84a35 100644 --- a/src/addons/api/b32m.rs +++ b/src/addons/api/b32m.rs @@ -80,7 +80,7 @@ impl Api for MockApiBech32m { Err(StdError::generic_err("Invalid input")) } - /// Takes a canonical address and returns a human readable address in **Bech32m** format. + /// Takes a canonical address and returns a human-readable address in **Bech32m** format. /// /// This is the inverse operation of [`addr_canonicalize`]. /// From 07b539431ffe278096a83e9e213e45da7edaad2e Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 4 Mar 2024 10:24:06 +0100 Subject: [PATCH 087/250] Fixed tests. --- src/addons/api/b32.rs | 15 +++++++-------- src/addons/api/b32m.rs | 15 +++++++-------- tests/test_addons/test_api/test_bech32.rs | 4 +++- tests/test_addons/test_api/test_bech32m.rs | 4 +++- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/addons/api/b32.rs b/src/addons/api/b32.rs index 7468eee2..ba76f699 100644 --- a/src/addons/api/b32.rs +++ b/src/addons/api/b32.rs @@ -99,9 +99,8 @@ impl Api for MockApiBech32 { /// addr.as_str()); /// ``` fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - if let Ok(encoded) = - encode::(Hrp::parse_unchecked(self.prefix), canonical.as_slice()) - { + let hrp = Hrp::parse(self.prefix).map_err(|e| StdError::generic_err(e.to_string()))?; + if let Ok(encoded) = encode::(hrp, canonical.as_slice()) { Ok(Addr::unchecked(encoded)) } else { Err(StdError::generic_err("Invalid canonical address")) @@ -171,11 +170,11 @@ impl MockApiBech32 { /// This function panics when generating a valid address in **Bech32** /// format is not possible, especially when prefix is too long or empty. pub fn addr_make(&self, input: &str) -> Addr { - match encode::( - Hrp::parse_unchecked(self.prefix), - Sha256::digest(input).as_slice(), - ) { - Ok(address) => Addr::unchecked(address), + match Hrp::parse(self.prefix) { + Ok(hrp) => match encode::(hrp, Sha256::digest(input).as_slice()) { + Ok(address) => Addr::unchecked(address), + Err(reason) => panic!("Generating address failed with reason: {}", reason), + }, Err(reason) => panic!("Generating address failed with reason: {}", reason), } } diff --git a/src/addons/api/b32m.rs b/src/addons/api/b32m.rs index 1de84a35..f9e00299 100644 --- a/src/addons/api/b32m.rs +++ b/src/addons/api/b32m.rs @@ -99,9 +99,8 @@ impl Api for MockApiBech32m { /// addr.as_str()); /// ``` fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - if let Ok(encoded) = - encode::(Hrp::parse_unchecked(self.prefix), canonical.as_slice()) - { + let hrp = Hrp::parse(self.prefix).map_err(|e| StdError::generic_err(e.to_string()))?; + if let Ok(encoded) = encode::(hrp, canonical.as_slice()) { Ok(Addr::unchecked(encoded)) } else { Err(StdError::generic_err("Invalid canonical address")) @@ -171,11 +170,11 @@ impl MockApiBech32m { /// This function panics when generating a valid address in **Bech32** /// format is not possible, especially when prefix is too long or empty. pub fn addr_make(&self, input: &str) -> Addr { - match encode::( - Hrp::parse_unchecked(self.prefix), - Sha256::digest(input).as_slice(), - ) { - Ok(address) => Addr::unchecked(address), + match Hrp::parse(self.prefix) { + Ok(hrp) => match encode::(hrp, Sha256::digest(input).as_slice()) { + Ok(address) => Addr::unchecked(address), + Err(reason) => panic!("Generating address failed with reason: {}", reason), + }, Err(reason) => panic!("Generating address failed with reason: {}", reason), } } diff --git a/tests/test_addons/test_api/test_bech32.rs b/tests/test_addons/test_api/test_bech32.rs index c99de049..68448488 100644 --- a/tests/test_addons/test_api/test_bech32.rs +++ b/tests/test_addons/test_api/test_bech32.rs @@ -78,7 +78,9 @@ fn debug_should_not_panic() { } #[test] -#[should_panic(expected = "Generating address failed with reason: invalid length")] +#[should_panic( + expected = "Generating address failed with reason: hrp is too long, found 85 characters, must be <= 126" +)] fn address_make_prefix_too_long() { MockApiBech32::new( "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", diff --git a/tests/test_addons/test_api/test_bech32m.rs b/tests/test_addons/test_api/test_bech32m.rs index 9cdc70ca..ffb1d48e 100644 --- a/tests/test_addons/test_api/test_bech32m.rs +++ b/tests/test_addons/test_api/test_bech32m.rs @@ -78,7 +78,9 @@ fn debug_should_not_panic() { } #[test] -#[should_panic(expected = "Generating address failed with reason: invalid length")] +#[should_panic( + expected = "Generating address failed with reason: hrp is too long, found 85 characters, must be <= 126" +)] fn address_make_prefix_too_long() { MockApiBech32m::new( "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", From 3c41473121b4adbd890be3b4c56ea2f22442e3ee Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 4 Mar 2024 10:57:17 +0100 Subject: [PATCH 088/250] Refactored mock api for bech formats. --- src/addons/api/b32.rs | 55 ++++++-------------- src/addons/api/b32m.rs | 55 ++++++-------------- src/addons/api/mod.rs | 111 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 82 deletions(-) diff --git a/src/addons/api/b32.rs b/src/addons/api/b32.rs index ba76f699..d48d6851 100644 --- a/src/addons/api/b32.rs +++ b/src/addons/api/b32.rs @@ -1,19 +1,12 @@ -use bech32::primitives::decode::CheckedHrpstring; -use bech32::{encode, Bech32, Hrp}; -use cosmwasm_std::testing::MockApi; -use cosmwasm_std::{ - Addr, Api, CanonicalAddr, RecoverPubkeyError, StdError, StdResult, VerificationError, -}; -use sha2::{Digest, Sha256}; +use crate::addons::api::MockApiBech; +use bech32::Bech32; +use cosmwasm_std::{Addr, Api, CanonicalAddr, RecoverPubkeyError, StdResult, VerificationError}; /// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32] format /// for humanizing canonical addresses. /// /// [Bech32]: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki -pub struct MockApiBech32 { - api: MockApi, - prefix: &'static str, -} +pub struct MockApiBech32(MockApiBech); impl MockApiBech32 { /// Returns `Api` implementation that uses specified prefix @@ -30,10 +23,7 @@ impl MockApiBech32 { /// "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"); /// ``` pub fn new(prefix: &'static str) -> Self { - Self { - api: MockApi::default(), - prefix, - } + Self(MockApiBech::new(prefix)) } } @@ -54,7 +44,7 @@ impl Api for MockApiBech32 { /// addr.as_str()); /// ``` fn addr_validate(&self, input: &str) -> StdResult { - self.addr_humanize(&self.addr_canonicalize(input)?) + self.0.addr_humanize(&self.addr_canonicalize(input)?) } /// Takes a human-readable address in **Bech32** format and returns @@ -72,12 +62,7 @@ impl Api for MockApiBech32 { /// "BC6BFD848EBD7819C9A82BF124D65E7F739D08E002601E23BB906AACD40A3D81"); /// ``` fn addr_canonicalize(&self, input: &str) -> StdResult { - if let Ok(s) = CheckedHrpstring::new::(input) { - if s.hrp().to_string() == self.prefix { - return Ok(s.byte_iter().collect::>().into()); - } - } - Err(StdError::generic_err("Invalid input")) + self.0.addr_canonicalize(input) } /// Takes a canonical address and returns a human-readable address in **Bech32** format. @@ -99,12 +84,7 @@ impl Api for MockApiBech32 { /// addr.as_str()); /// ``` fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - let hrp = Hrp::parse(self.prefix).map_err(|e| StdError::generic_err(e.to_string()))?; - if let Ok(encoded) = encode::(hrp, canonical.as_slice()) { - Ok(Addr::unchecked(encoded)) - } else { - Err(StdError::generic_err("Invalid canonical address")) - } + self.0.addr_humanize(canonical) } fn secp256k1_verify( @@ -113,8 +93,7 @@ impl Api for MockApiBech32 { signature: &[u8], public_key: &[u8], ) -> Result { - self.api - .secp256k1_verify(message_hash, signature, public_key) + self.0.secp256k1_verify(message_hash, signature, public_key) } fn secp256k1_recover_pubkey( @@ -123,7 +102,7 @@ impl Api for MockApiBech32 { signature: &[u8], recovery_param: u8, ) -> Result, RecoverPubkeyError> { - self.api + self.0 .secp256k1_recover_pubkey(message_hash, signature, recovery_param) } @@ -133,7 +112,7 @@ impl Api for MockApiBech32 { signature: &[u8], public_key: &[u8], ) -> Result { - self.api.ed25519_verify(message, signature, public_key) + self.0.ed25519_verify(message, signature, public_key) } fn ed25519_batch_verify( @@ -142,12 +121,12 @@ impl Api for MockApiBech32 { signatures: &[&[u8]], public_keys: &[&[u8]], ) -> Result { - self.api + self.0 .ed25519_batch_verify(messages, signatures, public_keys) } fn debug(&self, message: &str) { - self.api.debug(message) + self.0.debug(message) } } @@ -170,12 +149,6 @@ impl MockApiBech32 { /// This function panics when generating a valid address in **Bech32** /// format is not possible, especially when prefix is too long or empty. pub fn addr_make(&self, input: &str) -> Addr { - match Hrp::parse(self.prefix) { - Ok(hrp) => match encode::(hrp, Sha256::digest(input).as_slice()) { - Ok(address) => Addr::unchecked(address), - Err(reason) => panic!("Generating address failed with reason: {}", reason), - }, - Err(reason) => panic!("Generating address failed with reason: {}", reason), - } + self.0.addr_make(input) } } diff --git a/src/addons/api/b32m.rs b/src/addons/api/b32m.rs index f9e00299..ce031841 100644 --- a/src/addons/api/b32m.rs +++ b/src/addons/api/b32m.rs @@ -1,19 +1,12 @@ -use bech32::primitives::decode::CheckedHrpstring; -use bech32::{encode, Bech32m, Hrp}; -use cosmwasm_std::testing::MockApi; -use cosmwasm_std::{ - Addr, Api, CanonicalAddr, RecoverPubkeyError, StdError, StdResult, VerificationError, -}; -use sha2::{Digest, Sha256}; +use crate::addons::api::MockApiBech; +use bech32::Bech32m; +use cosmwasm_std::{Addr, Api, CanonicalAddr, RecoverPubkeyError, StdResult, VerificationError}; /// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32m] format /// for humanizing canonical addresses. /// /// [Bech32m]: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki -pub struct MockApiBech32m { - api: MockApi, - prefix: &'static str, -} +pub struct MockApiBech32m(MockApiBech); impl MockApiBech32m { /// Returns `Api` implementation that uses specified prefix @@ -30,10 +23,7 @@ impl MockApiBech32m { /// "osmosis1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qgv9940"); /// ``` pub fn new(prefix: &'static str) -> Self { - Self { - api: MockApi::default(), - prefix, - } + Self(MockApiBech::new(prefix)) } } @@ -54,7 +44,7 @@ impl Api for MockApiBech32m { /// addr.as_str()); /// ``` fn addr_validate(&self, input: &str) -> StdResult { - self.addr_humanize(&self.addr_canonicalize(input)?) + self.0.addr_humanize(&self.addr_canonicalize(input)?) } /// Takes a human-readable address in **Bech32m** format and returns @@ -72,12 +62,7 @@ impl Api for MockApiBech32m { /// "0A367B92CF0B037DFD89960EE832D56F7FC151681BB41E53690E776F5786998A"); /// ``` fn addr_canonicalize(&self, input: &str) -> StdResult { - if let Ok(s) = CheckedHrpstring::new::(input) { - if s.hrp().to_string() == self.prefix { - return Ok(s.byte_iter().collect::>().into()); - } - } - Err(StdError::generic_err("Invalid input")) + self.0.addr_canonicalize(input) } /// Takes a canonical address and returns a human-readable address in **Bech32m** format. @@ -99,12 +84,7 @@ impl Api for MockApiBech32m { /// addr.as_str()); /// ``` fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - let hrp = Hrp::parse(self.prefix).map_err(|e| StdError::generic_err(e.to_string()))?; - if let Ok(encoded) = encode::(hrp, canonical.as_slice()) { - Ok(Addr::unchecked(encoded)) - } else { - Err(StdError::generic_err("Invalid canonical address")) - } + self.0.addr_humanize(canonical) } fn secp256k1_verify( @@ -113,8 +93,7 @@ impl Api for MockApiBech32m { signature: &[u8], public_key: &[u8], ) -> Result { - self.api - .secp256k1_verify(message_hash, signature, public_key) + self.0.secp256k1_verify(message_hash, signature, public_key) } fn secp256k1_recover_pubkey( @@ -123,7 +102,7 @@ impl Api for MockApiBech32m { signature: &[u8], recovery_param: u8, ) -> Result, RecoverPubkeyError> { - self.api + self.0 .secp256k1_recover_pubkey(message_hash, signature, recovery_param) } @@ -133,7 +112,7 @@ impl Api for MockApiBech32m { signature: &[u8], public_key: &[u8], ) -> Result { - self.api.ed25519_verify(message, signature, public_key) + self.0.ed25519_verify(message, signature, public_key) } fn ed25519_batch_verify( @@ -142,12 +121,12 @@ impl Api for MockApiBech32m { signatures: &[&[u8]], public_keys: &[&[u8]], ) -> Result { - self.api + self.0 .ed25519_batch_verify(messages, signatures, public_keys) } fn debug(&self, message: &str) { - self.api.debug(message) + self.0.debug(message) } } @@ -170,12 +149,6 @@ impl MockApiBech32m { /// This function panics when generating a valid address in **Bech32** /// format is not possible, especially when prefix is too long or empty. pub fn addr_make(&self, input: &str) -> Addr { - match Hrp::parse(self.prefix) { - Ok(hrp) => match encode::(hrp, Sha256::digest(input).as_slice()) { - Ok(address) => Addr::unchecked(address), - Err(reason) => panic!("Generating address failed with reason: {}", reason), - }, - Err(reason) => panic!("Generating address failed with reason: {}", reason), - } + self.0.addr_make(input) } } diff --git a/src/addons/api/mod.rs b/src/addons/api/mod.rs index ebbd9cc7..1e16c5ab 100644 --- a/src/addons/api/mod.rs +++ b/src/addons/api/mod.rs @@ -1,2 +1,113 @@ +use bech32::primitives::decode::CheckedHrpstring; +use bech32::{encode, Hrp}; +use cosmwasm_std::testing::MockApi; +use cosmwasm_std::{ + Addr, Api, CanonicalAddr, RecoverPubkeyError, StdError, StdResult, VerificationError, +}; +use sha2::{Digest, Sha256}; + pub mod b32; pub mod b32m; + +struct MockApiBech { + api: MockApi, + prefix: &'static str, + _phantom_data: std::marker::PhantomData, +} + +impl MockApiBech { + /// Returns `Api` implementation that uses specified prefix + /// to generate addresses in `Bech32` or `Bech32m` format. + pub fn new(prefix: &'static str) -> Self { + Self { + api: MockApi::default(), + prefix, + _phantom_data: std::marker::PhantomData, + } + } +} + +impl Api for MockApiBech { + fn addr_validate(&self, input: &str) -> StdResult { + self.addr_humanize(&self.addr_canonicalize(input)?) + } + + fn addr_canonicalize(&self, input: &str) -> StdResult { + if let Ok(s) = CheckedHrpstring::new::(input) { + if s.hrp().to_string() == self.prefix { + return Ok(s.byte_iter().collect::>().into()); + } + } + Err(StdError::generic_err("Invalid input")) + } + + fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { + let hrp = Hrp::parse(self.prefix).map_err(|e| StdError::generic_err(e.to_string()))?; + if let Ok(encoded) = encode::(hrp, canonical.as_slice()) { + Ok(Addr::unchecked(encoded)) + } else { + Err(StdError::generic_err("Invalid canonical address")) + } + } + + fn secp256k1_verify( + &self, + message_hash: &[u8], + signature: &[u8], + public_key: &[u8], + ) -> Result { + self.api + .secp256k1_verify(message_hash, signature, public_key) + } + + fn secp256k1_recover_pubkey( + &self, + message_hash: &[u8], + signature: &[u8], + recovery_param: u8, + ) -> Result, RecoverPubkeyError> { + self.api + .secp256k1_recover_pubkey(message_hash, signature, recovery_param) + } + + fn ed25519_verify( + &self, + message: &[u8], + signature: &[u8], + public_key: &[u8], + ) -> Result { + self.api.ed25519_verify(message, signature, public_key) + } + + fn ed25519_batch_verify( + &self, + messages: &[&[u8]], + signatures: &[&[u8]], + public_keys: &[&[u8]], + ) -> Result { + self.api + .ed25519_batch_verify(messages, signatures, public_keys) + } + + fn debug(&self, message: &str) { + self.api.debug(message) + } +} + +impl MockApiBech { + /// Returns an address in `Bech32` or `Bech32m` format, built from provided input string. + /// + /// # Panics + /// + /// This function panics when generating a valid address in `Bech32` or `Bech32m` + /// format is not possible, especially when prefix is too long or empty. + pub fn addr_make(&self, input: &str) -> Addr { + match Hrp::parse(self.prefix) { + Ok(hrp) => match encode::(hrp, Sha256::digest(input).as_slice()) { + Ok(address) => Addr::unchecked(address), + Err(reason) => panic!("Generating address failed with reason: {}", reason), + }, + Err(reason) => panic!("Generating address failed with reason: {}", reason), + } + } +} From 5ba60e25aa73a5ca8d749a7b19fe3f09f76a83aa Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 4 Mar 2024 11:06:28 +0100 Subject: [PATCH 089/250] Updates. --- src/addons/api/b32.rs | 10 +++++----- src/addons/api/b32m.rs | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/addons/api/b32.rs b/src/addons/api/b32.rs index d48d6851..0837567d 100644 --- a/src/addons/api/b32.rs +++ b/src/addons/api/b32.rs @@ -10,7 +10,7 @@ pub struct MockApiBech32(MockApiBech); impl MockApiBech32 { /// Returns `Api` implementation that uses specified prefix - /// to generate addresses in **Bech32** format. + /// to generate addresses in `Bech32` format. /// /// # Example /// @@ -28,7 +28,7 @@ impl MockApiBech32 { } impl Api for MockApiBech32 { - /// Takes a human-readable address in **Bech32** format and checks if it is valid. + /// Takes a human-readable address in `Bech32` format and checks if it is valid. /// /// If the validation succeeds, an `Addr` containing the same string as the input is returned. /// @@ -47,7 +47,7 @@ impl Api for MockApiBech32 { self.0.addr_humanize(&self.addr_canonicalize(input)?) } - /// Takes a human-readable address in **Bech32** format and returns + /// Takes a human-readable address in `Bech32` format and returns /// a canonical binary representation of it. /// /// # Example @@ -65,7 +65,7 @@ impl Api for MockApiBech32 { self.0.addr_canonicalize(input) } - /// Takes a canonical address and returns a human-readable address in **Bech32** format. + /// Takes a canonical address and returns a human-readable address in `Bech32` format. /// /// This is the inverse operation of [`addr_canonicalize`]. /// @@ -131,7 +131,7 @@ impl Api for MockApiBech32 { } impl MockApiBech32 { - /// Returns an address in **Bech32** format, built from provided input string. + /// Returns an address in `Bech32` format, built from provided input string. /// /// # Example /// diff --git a/src/addons/api/b32m.rs b/src/addons/api/b32m.rs index ce031841..2c91477f 100644 --- a/src/addons/api/b32m.rs +++ b/src/addons/api/b32m.rs @@ -10,17 +10,17 @@ pub struct MockApiBech32m(MockApiBech); impl MockApiBech32m { /// Returns `Api` implementation that uses specified prefix - /// to generate addresses in **Bech32m** format. + /// to generate addresses in `Bech32m` format. /// /// # Example /// /// ``` /// use cw_multi_test::addons::MockApiBech32m; /// - /// let api = MockApiBech32m::new("osmosis"); + /// let api = MockApiBech32m::new("osmo"); /// let addr = api.addr_make("sender"); /// assert_eq!(addr.as_str(), - /// "osmosis1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qgv9940"); + /// "osmo1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qdlmaeg"); /// ``` pub fn new(prefix: &'static str) -> Self { Self(MockApiBech::new(prefix)) @@ -28,7 +28,7 @@ impl MockApiBech32m { } impl Api for MockApiBech32m { - /// Takes a human-readable address in **Bech32m** format and checks if it is valid. + /// Takes a human-readable address in `Bech32m` format and checks if it is valid. /// /// If the validation succeeds, an `Addr` containing the same string as the input is returned. /// @@ -38,7 +38,7 @@ impl Api for MockApiBech32m { /// use cosmwasm_std::Api; /// use cw_multi_test::addons::MockApiBech32m; /// - /// let api = MockApiBech32m::new("osmosis"); + /// let api = MockApiBech32m::new("osmo"); /// let addr = api.addr_make("sender"); /// assert_eq!(api.addr_validate(addr.as_str()).unwrap().as_str(), /// addr.as_str()); @@ -47,7 +47,7 @@ impl Api for MockApiBech32m { self.0.addr_humanize(&self.addr_canonicalize(input)?) } - /// Takes a human-readable address in **Bech32m** format and returns + /// Takes a human-readable address in `Bech32m` format and returns /// a canonical binary representation of it. /// /// # Example @@ -56,7 +56,7 @@ impl Api for MockApiBech32m { /// use cosmwasm_std::Api; /// use cw_multi_test::addons::MockApiBech32; /// - /// let api = MockApiBech32::new("osmosis"); + /// let api = MockApiBech32::new("osmo"); /// let addr = api.addr_make("sender"); /// assert_eq!(api.addr_canonicalize(addr.as_str()).unwrap().to_string(), /// "0A367B92CF0B037DFD89960EE832D56F7FC151681BB41E53690E776F5786998A"); @@ -65,7 +65,7 @@ impl Api for MockApiBech32m { self.0.addr_canonicalize(input) } - /// Takes a canonical address and returns a human-readable address in **Bech32m** format. + /// Takes a canonical address and returns a human-readable address in `Bech32m` format. /// /// This is the inverse operation of [`addr_canonicalize`]. /// @@ -77,7 +77,7 @@ impl Api for MockApiBech32m { /// use cosmwasm_std::Api; /// use cw_multi_test::addons::MockApiBech32m; /// - /// let api = MockApiBech32m::new("osmosis"); + /// let api = MockApiBech32m::new("osmo"); /// let addr = api.addr_make("sender"); /// let canonical_addr = api.addr_canonicalize(addr.as_str()).unwrap(); /// assert_eq!(api.addr_humanize(&canonical_addr).unwrap().as_str(), @@ -131,17 +131,17 @@ impl Api for MockApiBech32m { } impl MockApiBech32m { - /// Returns an address in **Bech32m** format, built from provided input string. + /// Returns an address in `Bech32m` format, built from provided input string. /// /// # Example /// /// ``` /// use cw_multi_test::addons::MockApiBech32m; /// - /// let api = MockApiBech32m::new("osmosis"); + /// let api = MockApiBech32m::new("osmo"); /// let addr = api.addr_make("sender"); /// assert_eq!(addr.as_str(), - /// "osmosis1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qgv9940"); + /// "osmo1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qdlmaeg"); /// ``` /// /// # Panics From c74b63526a95320e08af252662514da9e92127a7 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 4 Mar 2024 11:17:53 +0100 Subject: [PATCH 090/250] Updates. --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b62107ae..396c9ffd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,9 +120,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" +checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723" [[package]] name = "cfg-if" From b8311bb8bdc2e07d6e778cdfc380735e1e19bb96 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 4 Mar 2024 11:29:01 +0100 Subject: [PATCH 091/250] Updated image for CircleCI. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e9a3a574..52675aa4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -148,7 +148,7 @@ jobs: coverage: # https://circleci.com/developer/images?imageType=machine machine: - image: ubuntu-2004:202201-02 + image: ubuntu-2204:2024.01.1 steps: - checkout - run: From b0d9a7f827a9d74789e39b5010e36092f41f271a Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 4 Mar 2024 13:23:46 +0100 Subject: [PATCH 092/250] Updates. --- src/wasm.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wasm.rs b/src/wasm.rs index 3296d486..c0d24662 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -2000,7 +2000,9 @@ mod test { "default address generator returned incorrect address" ); - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), None, payout::contract()).unwrap(); + let code_id = wasm_keeper + .store_code(Addr::unchecked("creator"), None, payout::contract()) + .unwrap(); assert_eq!(2, code_id); let contract_addr = wasm_keeper From b4680ec59e140dc9e5d4047a3ebb8b3498bb621a Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 4 Mar 2024 13:36:27 +0100 Subject: [PATCH 093/250] Refactored store_code_id function's interface. --- src/app.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/app.rs b/src/app.rs index 34af5915..4a2063e2 100644 --- a/src/app.rs +++ b/src/app.rs @@ -256,7 +256,7 @@ where /// so it can later be used to instantiate a contract. pub fn store_code(&mut self, code: Box>) -> u64 { self.init_modules(|router, _, _| { - let creator = Addr::unchecked("creator"); + let creator = MockApi::default().addr_make("creator"); router.wasm.store_code(creator, None, code) }) .unwrap() @@ -273,18 +273,15 @@ where .unwrap() } - /// Registers contract code (like [store_code](Self::store_code)), + /// Registers contract code (like [store_code_with_creator](Self::store_code_with_creator)), /// but takes the code identifier as an additional argument. pub fn store_code_with_id( &mut self, + creator: Addr, code_id: u64, code: Box>, - ) -> u64 { - self.init_modules(|router, _, _| { - let creator = Addr::unchecked("creator"); - router.wasm.store_code(creator, code_id.into(), code) - }) - .unwrap() + ) -> AnyResult { + self.init_modules(|router, _, _| router.wasm.store_code(creator, code_id.into(), code)) } /// Duplicates the contract code identified by `code_id` and returns From 46bc2c57309765284a539c529725a0a136456ef1 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 4 Mar 2024 13:58:01 +0100 Subject: [PATCH 094/250] Added tests. --- tests/test_app/mod.rs | 1 + tests/test_app/test_store_code.rs | 35 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/test_app/test_store_code.rs diff --git a/tests/test_app/mod.rs b/tests/test_app/mod.rs index 340885be..e5a648b4 100644 --- a/tests/test_app/mod.rs +++ b/tests/test_app/mod.rs @@ -1 +1,2 @@ mod test_instantiate2; +mod test_store_code; diff --git a/tests/test_app/test_store_code.rs b/tests/test_app/test_store_code.rs new file mode 100644 index 00000000..76ef3290 --- /dev/null +++ b/tests/test_app/test_store_code.rs @@ -0,0 +1,35 @@ +use crate::test_contracts::counter; +#[cfg(feature = "cosmwasm_1_2")] +use cosmwasm_std::testing::MockApi; +use cw_multi_test::App; + +#[test] +fn storing_code_assigns_consecutive_identifiers() { + // prepare the application + let mut app = App::default(); + + // storing contract's code assigns consecutive code identifiers + for i in 1..=10 { + assert_eq!(i, app.store_code(counter::contract())); + } +} + +#[test] +#[cfg(feature = "cosmwasm_1_2")] +fn store_code_generates_default_address_for_creator() { + // prepare the application + let mut app = App::default(); + + // store contract's code + let code_id = app.store_code(counter::contract()); + assert_eq!(1, code_id); + + // retrieve contract code info + let code_info_response = app.wrap().query_wasm_code_info(code_id).unwrap(); + + // address of the creator should be the default one + assert_eq!( + MockApi::default().addr_make("creator").as_str(), + code_info_response.creator + ); +} From fae77464e2753576c17e97a4d3dd6ee5e59d553c Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 4 Mar 2024 15:01:36 +0100 Subject: [PATCH 095/250] Added tests. --- tests/test_app/mod.rs | 1 + .../test_app/test_store_code_with_creator.rs | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/test_app/test_store_code_with_creator.rs diff --git a/tests/test_app/mod.rs b/tests/test_app/mod.rs index e5a648b4..a306a495 100644 --- a/tests/test_app/mod.rs +++ b/tests/test_app/mod.rs @@ -1,2 +1,3 @@ mod test_instantiate2; mod test_store_code; +mod test_store_code_with_creator; diff --git a/tests/test_app/test_store_code_with_creator.rs b/tests/test_app/test_store_code_with_creator.rs new file mode 100644 index 00000000..5a639fa3 --- /dev/null +++ b/tests/test_app/test_store_code_with_creator.rs @@ -0,0 +1,33 @@ +use crate::test_contracts::counter; +use cw_multi_test::addons::{MockApiBech32, MockApiBech32m}; +use cw_multi_test::{no_init, AppBuilder}; + +#[test] +#[cfg(feature = "cosmwasm_1_2")] +fn store_code_with_custom_creator_address_should_work() { + // prepare the application + let mut app = AppBuilder::default() + .with_api(MockApiBech32m::new("juno")) + .build(no_init); + + let creator = app.api().addr_make("zeus"); + + // store contract's code + let code_id = app.store_code_with_creator(creator, counter::contract()); + assert_eq!(1, code_id); + + // retrieve contract code info + let code_info_response = app.wrap().query_wasm_code_info(code_id).unwrap(); + + // address of the creator should be the custom one in Bech32m format + assert_eq!( + MockApiBech32m::new("juno").addr_make("zeus"), + code_info_response.creator + ); + + // address of the creator should be the custom one but not in Bech32 format + assert_ne!( + MockApiBech32::new("juno").addr_make("zeus"), + code_info_response.creator + ); +} From bae1896bc592de44b80e1c964c4f03058994584d Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 4 Mar 2024 15:27:07 +0100 Subject: [PATCH 096/250] Added tests. --- src/wasm.rs | 4 +- tests/test_app/mod.rs | 1 + .../test_app/test_store_code_with_creator.rs | 3 +- tests/test_app/test_store_code_with_id.rs | 67 +++++++++++++++++++ 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 tests/test_app/test_store_code_with_id.rs diff --git a/src/wasm.rs b/src/wasm.rs index c0d24662..f4650f04 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -384,6 +384,8 @@ impl WasmKeeper { if let Some(code_id) = requested_code_id { if self.code_data.contains_key(&code_id) { bail!(Error::duplicated_code_id(code_id)); + } else if code_id == 0 { + bail!(Error::invalid_contract_code_id()); } else { Ok(code_id) } @@ -394,7 +396,7 @@ impl WasmKeeper { .last() .unwrap_or(&0u64) .checked_add(1) - .ok_or(Error::InvalidCodeId)?) + .ok_or_else(Error::invalid_contract_code_id)?) } } } diff --git a/tests/test_app/mod.rs b/tests/test_app/mod.rs index a306a495..3bcc0d98 100644 --- a/tests/test_app/mod.rs +++ b/tests/test_app/mod.rs @@ -1,3 +1,4 @@ mod test_instantiate2; mod test_store_code; mod test_store_code_with_creator; +mod test_store_code_with_id; diff --git a/tests/test_app/test_store_code_with_creator.rs b/tests/test_app/test_store_code_with_creator.rs index 5a639fa3..9cdc590c 100644 --- a/tests/test_app/test_store_code_with_creator.rs +++ b/tests/test_app/test_store_code_with_creator.rs @@ -1,9 +1,10 @@ +#![cfg(feature = "cosmwasm_1_2")] + use crate::test_contracts::counter; use cw_multi_test::addons::{MockApiBech32, MockApiBech32m}; use cw_multi_test::{no_init, AppBuilder}; #[test] -#[cfg(feature = "cosmwasm_1_2")] fn store_code_with_custom_creator_address_should_work() { // prepare the application let mut app = AppBuilder::default() diff --git a/tests/test_app/test_store_code_with_id.rs b/tests/test_app/test_store_code_with_id.rs new file mode 100644 index 00000000..5a758e09 --- /dev/null +++ b/tests/test_app/test_store_code_with_id.rs @@ -0,0 +1,67 @@ +use crate::test_contracts::counter; +use cw_multi_test::App; + +#[test] +fn storing_code_with_custom_identifier_should_work() { + let mut app = App::default(); + let creator = app.api().addr_make("prometheus"); + assert_eq!( + 10, + app.store_code_with_id(creator.clone(), 10, counter::contract()) + .unwrap() + ); + assert_eq!( + u64::MAX, + app.store_code_with_id(creator, u64::MAX, counter::contract()) + .unwrap() + ); +} + +#[test] +fn zero_code_id_is_not_allowed() { + let mut app = App::default(); + let creator = app.api().addr_make("prometheus"); + app.store_code_with_id(creator, 0, counter::contract()) + .unwrap_err(); +} + +#[test] +fn storing_code_with_consecutive_identifiers() { + let mut app = App::default(); + let creator = app.api().addr_make("prometheus"); + assert_eq!( + 11, + app.store_code_with_id(creator, 11, counter::contract()) + .unwrap() + ); + for i in 12..=20 { + assert_eq!(i, app.store_code(counter::contract())); + } +} + +#[test] +fn storing_with_the_same_id_is_not_allowed() { + let mut app = App::default(); + let creator = app.api().addr_make("prometheus"); + let code_id = 2056; + assert_eq!( + code_id, + app.store_code_with_id(creator.clone(), code_id, counter::contract()) + .unwrap() + ); + app.store_code_with_id(creator, code_id, counter::contract()) + .unwrap_err(); +} + +#[test] +#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: code id: invalid")] +fn no_more_identifiers_available() { + let mut app = App::default(); + let creator = app.api().addr_make("prometheus"); + assert_eq!( + u64::MAX, + app.store_code_with_id(creator, u64::MAX, counter::contract()) + .unwrap() + ); + app.store_code(counter::contract()); +} From 5c9d4d422f8576d5246ae4ed93482e159ba629f8 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 4 Mar 2024 15:29:35 +0100 Subject: [PATCH 097/250] Updates. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0c2b4a9e..3dbfe9e5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -148,7 +148,7 @@ jobs: coverage: # https://circleci.com/developer/images?imageType=machine machine: - image: ubuntu-2004:202201-02 + image: ubuntu-2204:2024.01.1 steps: - checkout - run: From 1b8389a621c286c12355dfaf69c6e58207d73875 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 5 Mar 2024 10:48:13 +0100 Subject: [PATCH 098/250] Improved code coverage script. --- .circleci/config.yml | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 52675aa4..121671b3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -146,16 +146,28 @@ jobs: key: cargocache-v2-lint-rust:1.65.0-{{ checksum "Cargo.lock" }} coverage: - # https://circleci.com/developer/images?imageType=machine - machine: - image: ubuntu-2204:2024.01.1 + name: Code coverage + runs-on: ubuntu-latest + container: + image: xd009642/tarpaulin:0.27.1 + options: --security-opt seccomp=unconfined steps: - - checkout - - run: - name: Run tests with coverage - command: | - mkdir -p cov - docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin \ - sh -c "cargo tarpaulin --workspace --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 --force-clean --engine llvm --out xml --output-dir cov" - - codecov/upload: - file: cov/cobertura.xml + - name: Checkout sources + uses: actions/checkout@v2 + - name: Cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + - name: Generate code coverage + run: | + cargo tarpaulin --verbose --all-features --workspace --timeout 120 --out xml --engine llvm + - name: Upload to codecov.io + uses: codecov/codecov-action@v2 + with: + fail_ci_if_error: true From 9e21ed22bcfad3687d572e9e546d256bc0062845 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 5 Mar 2024 10:50:52 +0100 Subject: [PATCH 099/250] Improved code coverage script. --- .circleci/config.yml | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 121671b3..f9739841 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -146,28 +146,16 @@ jobs: key: cargocache-v2-lint-rust:1.65.0-{{ checksum "Cargo.lock" }} coverage: - name: Code coverage - runs-on: ubuntu-latest - container: - image: xd009642/tarpaulin:0.27.1 - options: --security-opt seccomp=unconfined + # https://circleci.com/developer/images?imageType=machine + machine: + image: ubuntu-2204:2024.01.1 steps: - - name: Checkout sources - uses: actions/checkout@v2 - - name: Cache - uses: actions/cache@v3 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - target/ - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - - name: Generate code coverage - run: | - cargo tarpaulin --verbose --all-features --workspace --timeout 120 --out xml --engine llvm - - name: Upload to codecov.io - uses: codecov/codecov-action@v2 - with: - fail_ci_if_error: true + - checkout + - run: + name: Run tests with coverage + command: | + mkdir -p cov + docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.1 \ + sh -c "cargo tarpaulin --workspace --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 --force-clean --engine llvm --out xml --output-dir cov" + - codecov/upload: + file: cov/cobertura.xml From 1dcf81688f39e84173244c8785640e609a6145e4 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 5 Mar 2024 11:33:04 +0100 Subject: [PATCH 100/250] Bumped terpaulin image version. --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f9739841..26ccc665 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -155,7 +155,7 @@ jobs: name: Run tests with coverage command: | mkdir -p cov - docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.1 \ - sh -c "cargo tarpaulin --workspace --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 --force-clean --engine llvm --out xml --output-dir cov" + docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.3 \ + sh -c "cargo tarpaulin --workspace --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 --force-clean --engine llvm --out xml --output-dir cov" - codecov/upload: file: cov/cobertura.xml From 16152cac57c84a885ad37959f2817cb23c97483b Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 5 Mar 2024 11:36:28 +0100 Subject: [PATCH 101/250] Changed terpaulin image version. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 26ccc665..053d56f6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -155,7 +155,7 @@ jobs: name: Run tests with coverage command: | mkdir -p cov - docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.3 \ + docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.2 \ sh -c "cargo tarpaulin --workspace --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 --force-clean --engine llvm --out xml --output-dir cov" - codecov/upload: file: cov/cobertura.xml From 0a78200a246992855e69e06f9b13b399d8fa20c4 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 5 Mar 2024 11:37:17 +0100 Subject: [PATCH 102/250] Reverted terpaulin image version. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 053d56f6..5c60efe9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -155,7 +155,7 @@ jobs: name: Run tests with coverage command: | mkdir -p cov - docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.2 \ + docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.1 \ sh -c "cargo tarpaulin --workspace --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 --force-clean --engine llvm --out xml --output-dir cov" - codecov/upload: file: cov/cobertura.xml From 776a0b631ddb6cf6a34613a23508e3e72eed079c Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 5 Mar 2024 11:39:21 +0100 Subject: [PATCH 103/250] Reverted terpaulin image version. --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5c60efe9..f9739841 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -155,7 +155,7 @@ jobs: name: Run tests with coverage command: | mkdir -p cov - docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.1 \ - sh -c "cargo tarpaulin --workspace --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 --force-clean --engine llvm --out xml --output-dir cov" + docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.1 \ + sh -c "cargo tarpaulin --workspace --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 --force-clean --engine llvm --out xml --output-dir cov" - codecov/upload: file: cov/cobertura.xml From ce2e6f6fd5a8fadcdbba3f18510c64329bf0c475 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 5 Mar 2024 11:50:57 +0100 Subject: [PATCH 104/250] Bumped tarpaulin image once again. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f9739841..05aee862 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -155,7 +155,7 @@ jobs: name: Run tests with coverage command: | mkdir -p cov - docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.1 \ + docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.3 \ sh -c "cargo tarpaulin --workspace --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 --force-clean --engine llvm --out xml --output-dir cov" - codecov/upload: file: cov/cobertura.xml From 433894c878d2b1017c7a165c1bb8aec2d3969872 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 5 Mar 2024 12:19:29 +0100 Subject: [PATCH 105/250] Reverted tarpaulin image version again. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 05aee862..f9739841 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -155,7 +155,7 @@ jobs: name: Run tests with coverage command: | mkdir -p cov - docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.3 \ + docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.1 \ sh -c "cargo tarpaulin --workspace --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 --force-clean --engine llvm --out xml --output-dir cov" - codecov/upload: file: cov/cobertura.xml From eaee839e0591961a57bdf14d54b849072161ecc4 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 5 Mar 2024 12:51:43 +0100 Subject: [PATCH 106/250] Fixed tarpaulin docker image version. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3dbfe9e5..e6bef762 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -155,7 +155,7 @@ jobs: name: Run tests with coverage command: | mkdir -p cov - docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin \ + docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.1 \ sh -c "cargo tarpaulin --workspace --all-features --force-clean --engine llvm --out xml --output-dir cov" - codecov/upload: file: cov/cobertura.xml From f5184ee8b2abea14ae50663ab4f40ef58f7c8b7c Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 5 Mar 2024 13:46:59 +0100 Subject: [PATCH 107/250] Refactoring after review. --- src/app.rs | 8 +- src/error.rs | 11 +- src/tests/test_error.rs | 5 +- src/wasm.rs | 144 ++++++++++------------ tests/test_app/test_store_code_with_id.rs | 2 +- tests/test_app_builder/test_with_wasm.rs | 10 +- 6 files changed, 88 insertions(+), 92 deletions(-) diff --git a/src/app.rs b/src/app.rs index 4a2063e2..ff1925c7 100644 --- a/src/app.rs +++ b/src/app.rs @@ -257,9 +257,8 @@ where pub fn store_code(&mut self, code: Box>) -> u64 { self.init_modules(|router, _, _| { let creator = MockApi::default().addr_make("creator"); - router.wasm.store_code(creator, None, code) + router.wasm.store_code(creator, code) }) - .unwrap() } /// Registers contract code (like [store_code](Self::store_code)), @@ -269,8 +268,7 @@ where creator: Addr, code: Box>, ) -> u64 { - self.init_modules(|router, _, _| router.wasm.store_code(creator, None, code)) - .unwrap() + self.init_modules(|router, _, _| router.wasm.store_code(creator, code)) } /// Registers contract code (like [store_code_with_creator](Self::store_code_with_creator)), @@ -281,7 +279,7 @@ where code_id: u64, code: Box>, ) -> AnyResult { - self.init_modules(|router, _, _| router.wasm.store_code(creator, code_id.into(), code)) + self.init_modules(|router, _, _| router.wasm.store_code_with_id(creator, code_id, code)) } /// Duplicates the contract code identified by `code_id` and returns diff --git a/src/error.rs b/src/error.rs index 0c3e8f59..fce588b2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -43,6 +43,10 @@ pub enum Error { #[error("duplicated code id {0}")] DuplicatedCodeId(u64), + /// Error variant for reporting a situation when no more contract code identifiers are available. + #[error("no more code identifiers available")] + NoMoreCodeIdAvailable, + /// Error variant for reporting duplicated contract addresses. #[error("Contract with this address already exists: {0}")] DuplicatedContractAddress(String), @@ -80,7 +84,7 @@ impl Error { } /// Creates an instance of the [Error](Self) for invalid contract code identifier. - pub fn invalid_contract_code_id() -> Self { + pub fn invalid_code_id() -> Self { Self::InvalidCodeId } @@ -94,6 +98,11 @@ impl Error { Self::DuplicatedCodeId(code_id) } + /// Creates an instance of the [Error](Self) for exhausted contract code identifiers. + pub fn no_more_code_id_available() -> Self { + Self::NoMoreCodeIdAvailable + } + /// Creates an instance of the [Error](Self) for duplicated contract addresses. pub fn duplicated_contract_address(address: impl Into) -> Self { Self::DuplicatedContractAddress(address.into()) diff --git a/src/tests/test_error.rs b/src/tests/test_error.rs index eb113e72..91292f4e 100644 --- a/src/tests/test_error.rs +++ b/src/tests/test_error.rs @@ -35,10 +35,7 @@ fn instantiating_error_should_work() { }) .to_string() ); - assert_eq!( - "code id: invalid", - Error::invalid_contract_code_id().to_string() - ); + assert_eq!("code id: invalid", Error::invalid_code_id().to_string()); assert_eq!( "code id 53: no such code", Error::unregistered_code_id(53).to_string() diff --git a/src/wasm.rs b/src/wasm.rs index f4650f04..6bc3bf60 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -113,10 +113,14 @@ pub trait Wasm { ) -> AnyResult; /// Stores the contract's code and returns an identifier of the stored contract's code. - fn store_code( + fn store_code(&mut self, creator: Addr, code: Box>) -> u64; + + /// Stores the contract's code under specified identifier, + /// returns the same code identifier when successful. + fn store_code_with_id( &mut self, creator: Addr, - opt_code_id: Option, + code_id: u64, code: Box>, ) -> AnyResult; @@ -236,37 +240,37 @@ where /// Stores the contract's code in the in-memory lookup table. /// Returns an identifier of the stored contract code. - fn store_code( + fn store_code(&mut self, creator: Addr, code: Box>) -> u64 { + let code_id = self + .next_code_id() + .unwrap_or_else(|| panic!("{}", Error::NoMoreCodeIdAvailable)); + self.save_code(code_id, creator, code) + } + + /// Stores the contract's code in the in-memory lookup table. + /// Returns an identifier of the stored contract code. + fn store_code_with_id( &mut self, creator: Addr, - opt_code_id: Option, + code_id: u64, code: Box>, ) -> AnyResult { - // prepare the next identifier for the contract 'source' code - let source_id = self.code_base.len(); - // prepare the next contract code identifier - let code_id = self.next_code_id(opt_code_id)?; - // calculate the checksum of the contract 'source' code based on code_id - let checksum = self.checksum_generator.checksum(&creator, code_id); - // store the 'source' code of the contract - self.code_base.push(code); - // store the additional code attributes like creator address and checksum - self.code_data.insert( - code_id, - CodeData { - creator, - checksum, - source_id, - }, - ); - Ok(code_id) + // validate provided contract code identifier + if self.code_data.contains_key(&code_id) { + bail!(Error::duplicated_code_id(code_id)); + } else if code_id == 0 { + bail!(Error::invalid_code_id()); + } + Ok(self.save_code(code_id, creator, code)) } /// Duplicates the contract's code with specified identifier. /// Returns an identifier of the copy of the contract's code. fn duplicate_code(&mut self, code_id: u64) -> AnyResult { let code_data = self.code_data(code_id)?; - let new_code_id = self.next_code_id(None)?; + let new_code_id = self + .next_code_id() + .ok_or_else(Error::no_more_code_id_available)?; self.code_data.insert( new_code_id, CodeData { @@ -302,7 +306,7 @@ impl WasmKeeper { /// Returns code data of the contract with specified code id. fn code_data(&self, code_id: u64) -> AnyResult<&CodeData> { if code_id < 1 { - bail!(Error::invalid_contract_code_id()); + bail!(Error::invalid_code_id()); } Ok(self .code_data @@ -379,25 +383,33 @@ impl WasmKeeper { Ok(response) } + fn save_code( + &mut self, + code_id: u64, + creator: Addr, + code: Box>, + ) -> u64 { + // prepare the next identifier for the contract 'source' code + let source_id = self.code_base.len(); + // calculate the checksum of the contract 'source' code based on code_id + let checksum = self.checksum_generator.checksum(&creator, code_id); + // store the 'source' code of the contract + self.code_base.push(code); + // store the additional code attributes like creator address and checksum + self.code_data.insert( + code_id, + CodeData { + creator, + checksum, + source_id, + }, + ); + code_id + } + /// Returns the next code identifier. - fn next_code_id(&self, requested_code_id: Option) -> AnyResult { - if let Some(code_id) = requested_code_id { - if self.code_data.contains_key(&code_id) { - bail!(Error::duplicated_code_id(code_id)); - } else if code_id == 0 { - bail!(Error::invalid_contract_code_id()); - } else { - Ok(code_id) - } - } else { - Ok(self - .code_data - .keys() - .last() - .unwrap_or(&0u64) - .checked_add(1) - .ok_or_else(Error::invalid_contract_code_id)?) - } + fn next_code_id(&self) -> Option { + self.code_data.keys().last().unwrap_or(&0u64).checked_add(1) } } @@ -1284,9 +1296,7 @@ mod test { let mut wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper - .store_code(Addr::unchecked("creator"), None, error::contract(false)) - .unwrap(); + let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), error::contract(false)); transactional(&mut wasm_storage, |cache, _| { // cannot register contract with unregistered codeId @@ -1380,9 +1390,7 @@ mod test { let mut wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper - .store_code(Addr::unchecked("buzz"), None, payout::contract()) - .unwrap(); + let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); assert_eq!(1, code_id); let creator = "foobar"; @@ -1425,9 +1433,7 @@ mod test { let wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper - .store_code(Addr::unchecked("creator"), None, payout::contract()) - .unwrap(); + let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); let querier: MockQuerier = MockQuerier::new(&[]); let query = WasmQuery::CodeInfo { code_id }; let code_info = wasm_keeper @@ -1446,12 +1452,8 @@ mod test { let wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id_payout = wasm_keeper - .store_code(Addr::unchecked("creator"), None, payout::contract()) - .unwrap(); - let code_id_caller = wasm_keeper - .store_code(Addr::unchecked("creator"), None, caller::contract()) - .unwrap(); + let code_id_payout = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); + let code_id_caller = wasm_keeper.store_code(Addr::unchecked("creator"), caller::contract()); let querier: MockQuerier = MockQuerier::new(&[]); let query_payout = WasmQuery::CodeInfo { code_id: code_id_payout, @@ -1495,9 +1497,7 @@ mod test { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper - .store_code(Addr::unchecked("buzz"), None, payout::contract()) - .unwrap(); + let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); let mut wasm_storage = MockStorage::new(); @@ -1550,9 +1550,7 @@ mod test { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper - .store_code(Addr::unchecked("buzz"), None, payout::contract()) - .unwrap(); + let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); let mut wasm_storage = MockStorage::new(); let mut cache = StorageTransaction::new(&wasm_storage); @@ -1665,9 +1663,7 @@ mod test { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper - .store_code(Addr::unchecked("buzz"), None, payout::contract()) - .unwrap(); + let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); let mut wasm_storage = MockStorage::new(); @@ -1837,9 +1833,7 @@ mod test { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper - .store_code(Addr::unchecked("creator"), None, caller::contract()) - .unwrap(); + let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), caller::contract()); let mut wasm_storage = MockStorage::new(); @@ -1953,9 +1947,7 @@ mod test { fn uses_simple_address_generator_by_default() { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); - let code_id = wasm_keeper - .store_code(Addr::unchecked("creator"), None, payout::contract()) - .unwrap(); + let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); let mut wasm_storage = MockStorage::new(); @@ -2002,9 +1994,7 @@ mod test { "default address generator returned incorrect address" ); - let code_id = wasm_keeper - .store_code(Addr::unchecked("creator"), None, payout::contract()) - .unwrap(); + let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); assert_eq!(2, code_id); let contract_addr = wasm_keeper @@ -2071,9 +2061,7 @@ mod test { address: expected_addr.clone(), predictable_address: expected_predictable_addr.clone(), }); - let code_id = wasm_keeper - .store_code(Addr::unchecked("creator"), None, payout::contract()) - .unwrap(); + let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); let mut wasm_storage = MockStorage::new(); diff --git a/tests/test_app/test_store_code_with_id.rs b/tests/test_app/test_store_code_with_id.rs index 5a758e09..382764b3 100644 --- a/tests/test_app/test_store_code_with_id.rs +++ b/tests/test_app/test_store_code_with_id.rs @@ -54,7 +54,7 @@ fn storing_with_the_same_id_is_not_allowed() { } #[test] -#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: code id: invalid")] +#[should_panic(expected = "no more code identifiers available")] fn no_more_identifiers_available() { let mut app = App::default(); let creator = app.api().addr_make("prometheus"); diff --git a/tests/test_app_builder/test_with_wasm.rs b/tests/test_app_builder/test_with_wasm.rs index e8a26a4b..364a32bd 100644 --- a/tests/test_app_builder/test_with_wasm.rs +++ b/tests/test_app_builder/test_with_wasm.rs @@ -60,13 +60,17 @@ impl Wasm for MyWasmKeeper { bail!(self.3); } - fn store_code( + fn store_code(&mut self, _creator: Addr, _code: Box>) -> u64 { + CODE_ID + } + + fn store_code_with_id( &mut self, _creator: Addr, - _code_id: Option, + code_id: u64, _code: Box>, ) -> AnyResult { - Ok(CODE_ID) + Ok(code_id) } fn duplicate_code(&mut self, _code_id: u64) -> AnyResult { From c9bb30adbf090befa36fdb10885327671c16050c Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 5 Mar 2024 16:16:07 +0100 Subject: [PATCH 108/250] Removed next_address frunction. --- src/addresses.rs | 25 +----------------------- src/wasm.rs | 28 +++++++-------------------- tests/test_wasm/test_with_addr_gen.rs | 7 ------- 3 files changed, 8 insertions(+), 52 deletions(-) diff --git a/src/addresses.rs b/src/addresses.rs index 50c5fb67..4b6c4f93 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -1,9 +1,7 @@ //! # Implementation of address generators use crate::error::AnyResult; -use crate::prefixed_storage::prefixed_read; -use crate::wasm::{CONTRACTS, NAMESPACE_WASM}; -use cosmwasm_std::{Addr, Api, CanonicalAddr, HexBinary, Order, Storage}; +use cosmwasm_std::{Addr, Api, CanonicalAddr, HexBinary, Storage}; /// Common address generator interface. /// @@ -12,27 +10,6 @@ use cosmwasm_std::{Addr, Api, CanonicalAddr, HexBinary, Order, Storage}; /// or [predictable_contract_address](AddressGenerator::predictable_contract_address) is used, /// but users should not make any assumptions about the value of the generated address. pub trait AddressGenerator { - #[deprecated( - since = "0.18.0", - note = "use `contract_address` or `predictable_contract_address` instead; will be removed in version 1.0.0" - )] - /// Generates a _non-predictable_ contract address based on the number of contract's instances. - /// This is a simplified version of simulating contract addresses that is deprecated in favour of - /// [contract_address](Self::contract_address) and - /// [predictable_contract_address](Self::predictable_contract_address) functions. - fn next_address(&self, storage: &mut dyn Storage) -> Addr { - //TODO After removing this function in version 1.0, make `CONTRACTS` and `NAMESPACE_WASM` private in `wasm.rs`. - let count = CONTRACTS - .range_raw( - &prefixed_read(storage, NAMESPACE_WASM), - None, - None, - Order::Ascending, - ) - .count(); - Addr::unchecked(format!("contract{}", count)) - } - /// Generates a _non-predictable_ contract address, just like the real-life chain /// returns contract address after its instantiation. /// Address generated by this function is returned as a result of processing diff --git a/src/wasm.rs b/src/wasm.rs index 6bc3bf60..10c03a1a 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -22,13 +22,15 @@ use std::borrow::Borrow; use std::collections::BTreeMap; use std::fmt::Debug; -//TODO Make `CONTRACTS` private in version 1.0 when the function AddressGenerator::next_address will be removed. /// Contract state kept in storage, separate from the contracts themselves (contract code). -pub(crate) const CONTRACTS: Map<&Addr, ContractData> = Map::new("contracts"); +const CONTRACTS: Map<&Addr, ContractData> = Map::new("contracts"); -//TODO Make `NAMESPACE_WASM` private in version 1.0 when the function AddressGenerator::next_address will be removed. -pub(crate) const NAMESPACE_WASM: &[u8] = b"wasm"; -/// See +/// Wasm module namespace. +const NAMESPACE_WASM: &[u8] = b"wasm"; + +/// Contract [address namespace]. +/// +/// [address namespace]: https://github.com/CosmWasm/wasmd/blob/96e2b91144c9a371683555f3c696f882583cc6a2/x/wasm/types/events.go#L59 const CONTRACT_ATTR: &str = "_contract_address"; /// A structure representing a privileged message. @@ -2101,20 +2103,4 @@ mod test { "custom address generator returned incorrect address" ); } - - #[test] - #[allow(deprecated)] - fn remove_this_test_in_version_1_0() { - //TODO Remove this test in version 1.0.0 of multitest, now provided only for code coverage. - - let addr_gen = TestAddressGenerator { - address: Addr::unchecked("a"), - predictable_address: Addr::unchecked("b"), - }; - let mut storage = MockStorage::default(); - let contract_addr = addr_gen.next_address(&mut storage); - assert_eq!(contract_addr, "contract0"); - - let _: WasmKeeper = WasmKeeper::new_with_custom_address_generator(addr_gen); - } } diff --git a/tests/test_wasm/test_with_addr_gen.rs b/tests/test_wasm/test_with_addr_gen.rs index af0035c4..619f2e56 100644 --- a/tests/test_wasm/test_with_addr_gen.rs +++ b/tests/test_wasm/test_with_addr_gen.rs @@ -53,13 +53,6 @@ fn custom_address_generator_should_work() { struct CustomAddressGenerator; impl AddressGenerator for CustomAddressGenerator { - // deprecated since version 0.18.0 - fn next_address(&self, _storage: &mut dyn Storage) -> Addr { - // Panic in case of calling this function - unreachable!("this function should not be called") - } - - // use this function instead of next_address fn contract_address( &self, _api: &dyn Api, From 5c4e7aa9bef7eae91617c58fbb40cb518d403e24 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 5 Mar 2024 16:36:16 +0100 Subject: [PATCH 109/250] Removed new_with_custom_address_generator function. --- src/wasm.rs | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/src/wasm.rs b/src/wasm.rs index 6bc3bf60..50764f16 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -435,22 +435,6 @@ where Self::default() } - #[deprecated( - since = "0.18.0", - note = "use `WasmKeeper::new().with_address_generator` instead; will be removed in version 1.0.0" - )] - /// Populates an existing [WasmKeeper] with custom contract address generator. - /// - /// See description of [with_address_generator](Self::with_address_generator) function for details. - pub fn new_with_custom_address_generator( - address_generator: impl AddressGenerator + 'static, - ) -> Self { - Self { - address_generator: Box::new(address_generator), - ..Default::default() - } - } - /// Populates an existing [WasmKeeper] with custom contract address generator. /// /// # Example @@ -2101,20 +2085,4 @@ mod test { "custom address generator returned incorrect address" ); } - - #[test] - #[allow(deprecated)] - fn remove_this_test_in_version_1_0() { - //TODO Remove this test in version 1.0.0 of multitest, now provided only for code coverage. - - let addr_gen = TestAddressGenerator { - address: Addr::unchecked("a"), - predictable_address: Addr::unchecked("b"), - }; - let mut storage = MockStorage::default(); - let contract_addr = addr_gen.next_address(&mut storage); - assert_eq!(contract_addr, "contract0"); - - let _: WasmKeeper = WasmKeeper::new_with_custom_address_generator(addr_gen); - } } From d37a3f9a53d36e4579ad1b671f9b3b220f10f144 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 7 Mar 2024 11:03:36 +0100 Subject: [PATCH 110/250] Updated CI configuration. --- .circleci/config.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e6bef762..fb260f3e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -148,7 +148,9 @@ jobs: coverage: # https://circleci.com/developer/images?imageType=machine machine: - image: ubuntu-2204:2024.01.1 + - image: ubuntu-2204:2024.01.1 + docker: + - image: xd009642/tarpaulin:0.27.1 steps: - checkout - run: From 694a53177ed4e9a5c6c29332637b63b3382dd495 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 7 Mar 2024 11:05:25 +0100 Subject: [PATCH 111/250] Updated CI configuration. --- .circleci/config.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fb260f3e..575ba919 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -146,9 +146,6 @@ jobs: key: cargocache-v2-lint-rust:1.65.0-{{ checksum "Cargo.lock" }} coverage: - # https://circleci.com/developer/images?imageType=machine - machine: - - image: ubuntu-2204:2024.01.1 docker: - image: xd009642/tarpaulin:0.27.1 steps: From d6c598f7295981dec82ad2a8e28faba25310f72e Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 7 Mar 2024 11:12:08 +0100 Subject: [PATCH 112/250] Updates. --- .circleci/config.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 575ba919..55a072ae 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -146,8 +146,9 @@ jobs: key: cargocache-v2-lint-rust:1.65.0-{{ checksum "Cargo.lock" }} coverage: - docker: - - image: xd009642/tarpaulin:0.27.1 + # https://circleci.com/developer/images?imageType=machine + machine: + - image: ubuntu-2204:2024.01.1 steps: - checkout - run: From 735cdf1be5b9fc452d5382ce3792a14d0810f757 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 7 Mar 2024 11:12:40 +0100 Subject: [PATCH 113/250] Updates. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 55a072ae..e6bef762 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -148,7 +148,7 @@ jobs: coverage: # https://circleci.com/developer/images?imageType=machine machine: - - image: ubuntu-2204:2024.01.1 + image: ubuntu-2204:2024.01.1 steps: - checkout - run: From f2e074916c450db3a86181d408d91bc2ca321114 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 7 Mar 2024 11:47:56 +0100 Subject: [PATCH 114/250] Editorial and typo fixes. --- Cargo.lock | 4 +- src/app_builder.rs | 2 +- src/custom_handler.rs | 2 +- src/executor.rs | 2 +- src/prefixed_storage/mod.rs | 38 +++++++++--------- src/staking.rs | 74 ++++++++++++++++++------------------ src/test_helpers/echo.rs | 2 +- src/test_helpers/hackatom.rs | 2 +- src/transactions.rs | 47 ++++++++++++----------- 9 files changed, 87 insertions(+), 86 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 396c9ffd..ac06bd85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,9 +120,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.89" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" [[package]] name = "cfg-if" diff --git a/src/app_builder.rs b/src/app_builder.rs index 46de71a3..ca60d294 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -294,7 +294,7 @@ where } } - /// Overwrites the default custom messages handler. + /// Overwrites the default custom messages' handler. /// /// At this point it is needed that new custom implements some `Module` trait, but it doesn't need /// to be bound to ExecC or QueryC yet - as those may change. The cross-components validation is diff --git a/src/custom_handler.rs b/src/custom_handler.rs index a29f30d8..1ab9dbeb 100644 --- a/src/custom_handler.rs +++ b/src/custom_handler.rs @@ -39,7 +39,7 @@ impl CachingCustomHandlerState { /// Custom handler that stores all received messages and queries. /// -/// State is thin shared state, so it can be hold after mock is passed to [App](crate::App) to read state. +/// State is thin shared state, so it can be held after mock is passed to [App](crate::App) to read state. #[derive(Clone, Derivative)] #[derivative(Default(bound = "", new = "true"))] pub struct CachingCustomHandler { diff --git a/src/executor.rs b/src/executor.rs index 0e80f171..b1ffbcee 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -29,7 +29,7 @@ impl AppResponse { /// Checks if there is an Event that is a super-set of this. /// - /// It has the same type, and all compare.attributes are included in it as well. + /// It has the same type, and all compare attributes are included in it as well. /// You don't need to specify them all. pub fn has_event(&self, expected: &Event) -> bool { self.events.iter().any(|ev| { diff --git a/src/prefixed_storage/mod.rs b/src/prefixed_storage/mod.rs index 9e9da867..2666a855 100644 --- a/src/prefixed_storage/mod.rs +++ b/src/prefixed_storage/mod.rs @@ -47,16 +47,8 @@ impl<'a> Storage for PrefixedStorage<'a> { get_with_prefix(self.storage, &self.prefix, key) } - fn set(&mut self, key: &[u8], value: &[u8]) { - set_with_prefix(self.storage, &self.prefix, key, value); - } - - fn remove(&mut self, key: &[u8]) { - remove_with_prefix(self.storage, &self.prefix, key); - } - - /// range allows iteration over a set of keys, either forwards or backwards - /// uses standard rust range notation, and eg db.range(b"foo"..b"bar") also works reverse + /// Range allows iteration over a set of keys, either forwards or backwards. + /// Uses standard rust range notation, and e.g. `db.range(b"foo"‥b"bar")` and also works reverse. fn range<'b>( &'b self, start: Option<&[u8]>, @@ -65,6 +57,14 @@ impl<'a> Storage for PrefixedStorage<'a> { ) -> Box + 'b> { range_with_prefix(self.storage, &self.prefix, start, end, order) } + + fn set(&mut self, key: &[u8], value: &[u8]) { + set_with_prefix(self.storage, &self.prefix, key, value); + } + + fn remove(&mut self, key: &[u8]) { + remove_with_prefix(self.storage, &self.prefix, key); + } } pub struct ReadonlyPrefixedStorage<'a> { @@ -95,15 +95,7 @@ impl<'a> Storage for ReadonlyPrefixedStorage<'a> { get_with_prefix(self.storage, &self.prefix, key) } - fn set(&mut self, _key: &[u8], _value: &[u8]) { - unimplemented!(); - } - - fn remove(&mut self, _key: &[u8]) { - unimplemented!(); - } - - /// range allows iteration over a set of keys, either forwards or backwards + /// Range allows iteration over a set of keys, either forwards or backwards. fn range<'b>( &'b self, start: Option<&[u8]>, @@ -112,6 +104,14 @@ impl<'a> Storage for ReadonlyPrefixedStorage<'a> { ) -> Box + 'b> { range_with_prefix(self.storage, &self.prefix, start, end, order) } + + fn set(&mut self, _key: &[u8], _value: &[u8]) { + unimplemented!(); + } + + fn remove(&mut self, _key: &[u8]) { + unimplemented!(); + } } #[cfg(test)] diff --git a/src/staking.rs b/src/staking.rs index 4c49ad57..a78d2999 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -747,32 +747,6 @@ impl Module for StakeKeeper { } } - fn sudo( - &self, - api: &dyn Api, - storage: &mut dyn Storage, - router: &dyn CosmosRouter, - block: &BlockInfo, - msg: StakingSudo, - ) -> AnyResult { - match msg { - StakingSudo::Slash { - validator, - percentage, - } => { - let mut staking_storage = prefixed(storage, NAMESPACE_STAKING); - let validator = api.addr_validate(&validator)?; - self.validate_percentage(percentage)?; - - self.slash(api, &mut staking_storage, block, &validator, percentage)?; - - Ok(AppResponse::default()) - } - #[allow(deprecated)] - StakingSudo::ProcessQueue {} => self.process_queue(api, storage, router, block), - } - } - fn query( &self, api: &dyn Api, @@ -875,6 +849,32 @@ impl Module for StakeKeeper { q => bail!("Unsupported staking sudo message: {:?}", q), } } + + fn sudo( + &self, + api: &dyn Api, + storage: &mut dyn Storage, + router: &dyn CosmosRouter, + block: &BlockInfo, + msg: StakingSudo, + ) -> AnyResult { + match msg { + StakingSudo::Slash { + validator, + percentage, + } => { + let mut staking_storage = prefixed(storage, NAMESPACE_STAKING); + let validator = api.addr_validate(&validator)?; + self.validate_percentage(percentage)?; + + self.slash(api, &mut staking_storage, block, &validator, percentage)?; + + Ok(AppResponse::default()) + } + #[allow(deprecated)] + StakingSudo::ProcessQueue {} => self.process_queue(api, storage, router, block), + } + } } /// A structure representing a default distribution keeper. @@ -1010,17 +1010,6 @@ impl Module for DistributionKeeper { } } - fn sudo( - &self, - _api: &dyn Api, - _storage: &mut dyn Storage, - _router: &dyn CosmosRouter, - _block: &BlockInfo, - _msg: Empty, - ) -> AnyResult { - bail!("Something went wrong - Distribution doesn't have sudo messages") - } - fn query( &self, _api: &dyn Api, @@ -1031,6 +1020,17 @@ impl Module for DistributionKeeper { ) -> AnyResult { bail!("Something went wrong - Distribution doesn't have query messages") } + + fn sudo( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + _msg: Empty, + ) -> AnyResult { + bail!("Something went wrong - Distribution doesn't have sudo messages") + } } #[cfg(test)] diff --git a/src/test_helpers/echo.rs b/src/test_helpers/echo.rs index 0b73a394..181f9044 100644 --- a/src/test_helpers/echo.rs +++ b/src/test_helpers/echo.rs @@ -1,7 +1,7 @@ //! Very simple echoing contract which just returns incoming string if any, //! but performing sub call of given message to test response. //! -//! Additionally it bypasses all events and attributes send to it. +//! Additionally, it bypasses all events and attributes send to it. use crate::{Contract, ContractWrapper}; use cosmwasm_std::{ diff --git a/src/test_helpers/hackatom.rs b/src/test_helpers/hackatom.rs index 34d4f1ee..95df71ba 100644 --- a/src/test_helpers/hackatom.rs +++ b/src/test_helpers/hackatom.rs @@ -16,7 +16,7 @@ pub struct InstantiateMsg { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MigrateMsg { - // just use some other string so we see there are other types + // just use some other string, so we see there are other types pub new_guy: String, } diff --git a/src/transactions.rs b/src/transactions.rs index 4e8b2645..59ac0b0f 100644 --- a/src/transactions.rs +++ b/src/transactions.rs @@ -56,23 +56,9 @@ impl<'a> Storage for StorageTransaction<'a> { } } - fn set(&mut self, key: &[u8], value: &[u8]) { - let op = Op::Set { - key: key.to_vec(), - value: value.to_vec(), - }; - self.local_state.insert(key.to_vec(), op.to_delta()); - self.rep_log.append(op); - } - - fn remove(&mut self, key: &[u8]) { - let op = Op::Delete { key: key.to_vec() }; - self.local_state.insert(key.to_vec(), op.to_delta()); - self.rep_log.append(op); - } - - /// range allows iteration over a set of keys, either forwards or backwards - /// uses standard rust range notation, and eg db.range(b"foo"..b"bar") also works reverse + /// Range allows iteration over a set of keys, either forwards or backwards + /// uses standard Rust range notation, e.g. `db.range(b"foo"‥b"bar")`, + /// works also in reverse order. fn range<'b>( &'b self, start: Option<&[u8]>, @@ -101,6 +87,21 @@ impl<'a> Storage for StorageTransaction<'a> { let merged = MergeOverlay::new(local, base, order); Box::new(merged) } + + fn set(&mut self, key: &[u8], value: &[u8]) { + let op = Op::Set { + key: key.to_vec(), + value: value.to_vec(), + }; + self.local_state.insert(key.to_vec(), op.to_delta()); + self.rep_log.append(op); + } + + fn remove(&mut self, key: &[u8]) { + let op = Op::Delete { key: key.to_vec() }; + self.local_state.insert(key.to_vec(), op.to_delta()); + self.rep_log.append(op); + } } pub struct RepLog { @@ -127,7 +128,7 @@ impl RepLog { } /// Op is the user operation, which can be stored in the RepLog. -/// Currently Set or Delete. +/// Currently: `Set` or `Delete`. enum Op { /// represents the `Set` operation for setting a key-value pair in storage Set { @@ -544,17 +545,17 @@ mod test { let mut base = MemoryStorage::new(); base.set(b"foo", b"bar"); - let mut stxn1 = StorageTransaction::new(&base); + let mut stx1 = StorageTransaction::new(&base); - assert_eq!(stxn1.get(b"foo"), Some(b"bar".to_vec())); + assert_eq!(stx1.get(b"foo"), Some(b"bar".to_vec())); - stxn1.set(b"subtx", b"works"); - assert_eq!(stxn1.get(b"subtx"), Some(b"works".to_vec())); + stx1.set(b"subtx", b"works"); + assert_eq!(stx1.get(b"subtx"), Some(b"works".to_vec())); // Can still read from base, txn is not yet committed assert_eq!(base.get(b"subtx"), None); - stxn1.prepare().commit(&mut base); + stx1.prepare().commit(&mut base); assert_eq!(base.get(b"subtx"), Some(b"works".to_vec())); } From 4236a61d76a4ef8f19fe8df2c3b3f66be3d33fe1 Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Thu, 7 Mar 2024 12:57:11 +0100 Subject: [PATCH 115/250] One more typo fixed. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jan Woźniak --- src/executor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/executor.rs b/src/executor.rs index b1ffbcee..a9cf6769 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -29,7 +29,7 @@ impl AppResponse { /// Checks if there is an Event that is a super-set of this. /// - /// It has the same type, and all compare attributes are included in it as well. + /// It has the same type, and all compared attributes are included in it as well. /// You don't need to specify them all. pub fn has_event(&self, expected: &Event) -> bool { self.events.iter().any(|ev| { From ad044c2c14a98602d6f0667316865f4c1dbc4be3 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 7 Mar 2024 13:03:46 +0100 Subject: [PATCH 116/250] Small rephrasing. --- src/app_builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app_builder.rs b/src/app_builder.rs index ca60d294..56434c17 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -294,7 +294,7 @@ where } } - /// Overwrites the default custom messages' handler. + /// Overwrites the default handler for custom messages. /// /// At this point it is needed that new custom implements some `Module` trait, but it doesn't need /// to be bound to ExecC or QueryC yet - as those may change. The cross-components validation is From de1bcb35ed61b07d4ca48d39e220d363358b29bf Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 7 Mar 2024 14:01:00 +0100 Subject: [PATCH 117/250] Added trait for Bech32 conversions. --- Cargo.lock | 13 ++++++++++--- Cargo.toml | 1 + src/addresses.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 +- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d08b4be9..2f314678 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,6 +76,12 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +[[package]] +name = "bech32" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" + [[package]] name = "block-buffer" version = "0.9.0" @@ -114,9 +120,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.88" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" [[package]] name = "cfg-if" @@ -183,7 +189,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cb9f0cb520832e993af5cbe97bc3c163bd0c3870989e99d5f1d5499e6f28a53" dependencies = [ "base64", - "bech32", + "bech32 0.9.1", "bnum", "cosmwasm-crypto", "cosmwasm-derive", @@ -247,6 +253,7 @@ name = "cw-multi-test" version = "2.0.0-rc.0" dependencies = [ "anyhow", + "bech32 0.11.0", "cosmwasm-std", "cw-storage-plus", "cw-utils", diff --git a/Cargo.toml b/Cargo.toml index 5a503526..2503e167 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ cosmwasm_2_0 = ["cosmwasm-std/cosmwasm_2_0"] [dependencies] anyhow = "1.0.80" +bech32 = "0.11.0" cosmwasm-std = { version = "2.0.0-rc.1", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "2.0.0-rc.0" cw-utils = "2.0.0-rc.0" diff --git a/src/addresses.rs b/src/addresses.rs index 97df8865..7ffefb7e 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -1,6 +1,7 @@ //! # Implementation of address generators use crate::error::AnyResult; +use cosmwasm_std::testing::MockApi; use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage}; use sha2::digest::Update; use sha2::{Digest, Sha256}; @@ -126,3 +127,41 @@ fn instantiate_address(code_id: u64, instance_id: u64) -> CanonicalAddr { pub struct SimpleAddressGenerator; impl AddressGenerator for SimpleAddressGenerator {} + +/// Defines conversions to `Bech32` compatible addresses. +pub trait IntoBech32 { + /// Converts into [Addr] containing a string compatible with `Bech32` format with default prefix. + fn into_bech32(self) -> Addr; + + /// Converts into [Addr] containing a string compatible with `Bech32` format with custom prefix. + fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr; +} + +impl IntoBech32 for &str { + fn into_bech32(self) -> Addr { + MockApi::default().addr_make(self) + } + + fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr { + MockApi::default().with_prefix(prefix).addr_make(self) + } +} + +/// Defines conversions to `Bech32m` compatible addresses. +#[allow(dead_code)] +pub trait IntoBech32m { + /// Converts into [Addr] containing a string compatible with `Bech32m` format with default prefix. + fn into_bech32m(self) -> Addr; + /// Converts into [Addr] containing a string compatible with `Bech32m` format with custom prefix. + fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr; +} + +impl IntoBech32m for &str { + fn into_bech32m(self) -> Addr { + unimplemented!() + } + + fn into_bech32m_with_prefix(self, _prefix: &'static str) -> Addr { + unimplemented!() + } +} diff --git a/src/lib.rs b/src/lib.rs index c88b17eb..6a84893e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -144,7 +144,7 @@ mod tests; mod transactions; mod wasm; -pub use crate::addresses::{AddressGenerator, SimpleAddressGenerator}; +pub use crate::addresses::{AddressGenerator, IntoBech32, SimpleAddressGenerator}; pub use crate::app::{ custom_app, next_block, no_init, App, BasicApp, CosmosRouter, Router, SudoMsg, }; From 3297a733dcb65c8629985831b5a7091889f975b2 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 7 Mar 2024 14:24:19 +0100 Subject: [PATCH 118/250] Updates. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 6a84893e..7d7c4ac7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -144,7 +144,7 @@ mod tests; mod transactions; mod wasm; -pub use crate::addresses::{AddressGenerator, IntoBech32, SimpleAddressGenerator}; +pub use crate::addresses::{AddressGenerator, IntoBech32, IntoBech32m, SimpleAddressGenerator}; pub use crate::app::{ custom_app, next_block, no_init, App, BasicApp, CosmosRouter, Router, SudoMsg, }; From 67f1dee6b9b827a5de5145cced7602bb37ad0ff8 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 8 Mar 2024 12:17:09 +0100 Subject: [PATCH 119/250] Added conversions to address. --- src/addresses.rs | 97 ++++---- src/api.rs | 412 +++++++++++++++++++++++++++++++++ src/lib.rs | 6 +- tests/test_api/mod.rs | 3 + tests/test_api/test_addr.rs | 21 ++ tests/test_api/test_bech32.rs | 117 ++++++++++ tests/test_api/test_bech32m.rs | 117 ++++++++++ 7 files changed, 733 insertions(+), 40 deletions(-) create mode 100644 src/api.rs create mode 100644 tests/test_api/test_addr.rs create mode 100644 tests/test_api/test_bech32.rs create mode 100644 tests/test_api/test_bech32m.rs diff --git a/src/addresses.rs b/src/addresses.rs index 7ffefb7e..e8d76cea 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -1,11 +1,68 @@ -//! # Implementation of address generators +//! # Implementation of address conversions and generators use crate::error::AnyResult; +use crate::{MockApiBech32, MockApiBech32m}; use cosmwasm_std::testing::MockApi; use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage}; use sha2::digest::Update; use sha2::{Digest, Sha256}; +/// Defines conversions to [Addr]. +pub trait IntoAddr { + /// Converts into [Addr]. + fn into_addr(self) -> Addr; + + /// Converts into [Addr] with custom prefix. + fn into_addr_with_prefix(self, prefix: &'static str) -> Addr; +} + +impl IntoAddr for &str { + fn into_addr(self) -> Addr { + MockApi::default().addr_make(self) + } + + fn into_addr_with_prefix(self, prefix: &'static str) -> Addr { + MockApi::default().with_prefix(prefix).addr_make(self) + } +} + +/// Defines conversions to `Bech32` compatible addresses. +pub trait IntoBech32 { + /// Converts into [Addr] containing a string compatible with `Bech32` format with default prefix. + fn into_bech32(self) -> Addr; + + /// Converts into [Addr] containing a string compatible with `Bech32` format with custom prefix. + fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr; +} + +impl IntoBech32 for &str { + fn into_bech32(self) -> Addr { + MockApiBech32::new("cosmwasm").addr_make(self) + } + + fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr { + MockApiBech32::new(prefix).addr_make(self) + } +} + +/// Defines conversions to `Bech32m` compatible addresses. +pub trait IntoBech32m { + /// Converts into [Addr] containing a string compatible with `Bech32m` format with default prefix. + fn into_bech32m(self) -> Addr; + /// Converts into [Addr] containing a string compatible with `Bech32m` format with custom prefix. + fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr; +} + +impl IntoBech32m for &str { + fn into_bech32m(self) -> Addr { + MockApiBech32m::new("cosmwasm").addr_make(self) + } + + fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr { + MockApiBech32m::new(prefix).addr_make(self) + } +} + /// Common address generator interface. /// /// The default implementation of this trait generates fully predictable @@ -127,41 +184,3 @@ fn instantiate_address(code_id: u64, instance_id: u64) -> CanonicalAddr { pub struct SimpleAddressGenerator; impl AddressGenerator for SimpleAddressGenerator {} - -/// Defines conversions to `Bech32` compatible addresses. -pub trait IntoBech32 { - /// Converts into [Addr] containing a string compatible with `Bech32` format with default prefix. - fn into_bech32(self) -> Addr; - - /// Converts into [Addr] containing a string compatible with `Bech32` format with custom prefix. - fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr; -} - -impl IntoBech32 for &str { - fn into_bech32(self) -> Addr { - MockApi::default().addr_make(self) - } - - fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr { - MockApi::default().with_prefix(prefix).addr_make(self) - } -} - -/// Defines conversions to `Bech32m` compatible addresses. -#[allow(dead_code)] -pub trait IntoBech32m { - /// Converts into [Addr] containing a string compatible with `Bech32m` format with default prefix. - fn into_bech32m(self) -> Addr; - /// Converts into [Addr] containing a string compatible with `Bech32m` format with custom prefix. - fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr; -} - -impl IntoBech32m for &str { - fn into_bech32m(self) -> Addr { - unimplemented!() - } - - fn into_bech32m_with_prefix(self, _prefix: &'static str) -> Addr { - unimplemented!() - } -} diff --git a/src/api.rs b/src/api.rs new file mode 100644 index 00000000..27e2fc33 --- /dev/null +++ b/src/api.rs @@ -0,0 +1,412 @@ +use bech32::primitives::decode::CheckedHrpstring; +use bech32::{encode, Bech32, Bech32m, Hrp}; +use cosmwasm_std::testing::MockApi; +use cosmwasm_std::{ + Addr, Api, CanonicalAddr, RecoverPubkeyError, StdError, StdResult, VerificationError, +}; +use sha2::{Digest, Sha256}; + +struct MockApiBech { + api: MockApi, + prefix: &'static str, + _phantom_data: std::marker::PhantomData, +} + +impl MockApiBech { + /// Returns `Api` implementation that uses specified prefix + /// to generate addresses in `Bech32` or `Bech32m` format. + pub fn new(prefix: &'static str) -> Self { + Self { + api: MockApi::default(), + prefix, + _phantom_data: std::marker::PhantomData, + } + } +} + +impl Api for MockApiBech { + fn addr_validate(&self, input: &str) -> StdResult { + self.addr_humanize(&self.addr_canonicalize(input)?) + } + + fn addr_canonicalize(&self, input: &str) -> StdResult { + if let Ok(s) = CheckedHrpstring::new::(input) { + if s.hrp().to_string() == self.prefix { + return Ok(s.byte_iter().collect::>().into()); + } + } + Err(StdError::generic_err("Invalid input")) + } + + fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { + let hrp = Hrp::parse(self.prefix).map_err(|e| StdError::generic_err(e.to_string()))?; + if let Ok(encoded) = encode::(hrp, canonical.as_slice()) { + Ok(Addr::unchecked(encoded)) + } else { + Err(StdError::generic_err("Invalid canonical address")) + } + } + + fn secp256k1_verify( + &self, + message_hash: &[u8], + signature: &[u8], + public_key: &[u8], + ) -> Result { + self.api + .secp256k1_verify(message_hash, signature, public_key) + } + + fn secp256k1_recover_pubkey( + &self, + message_hash: &[u8], + signature: &[u8], + recovery_param: u8, + ) -> Result, RecoverPubkeyError> { + self.api + .secp256k1_recover_pubkey(message_hash, signature, recovery_param) + } + + fn ed25519_verify( + &self, + message: &[u8], + signature: &[u8], + public_key: &[u8], + ) -> Result { + self.api.ed25519_verify(message, signature, public_key) + } + + fn ed25519_batch_verify( + &self, + messages: &[&[u8]], + signatures: &[&[u8]], + public_keys: &[&[u8]], + ) -> Result { + self.api + .ed25519_batch_verify(messages, signatures, public_keys) + } + + fn debug(&self, message: &str) { + self.api.debug(message) + } +} + +impl MockApiBech { + /// Returns an address in `Bech32` or `Bech32m` format, built from provided input string. + /// + /// # Panics + /// + /// This function panics when generating a valid address in `Bech32` or `Bech32m` + /// format is not possible, especially when prefix is too long or empty. + pub fn addr_make(&self, input: &str) -> Addr { + match Hrp::parse(self.prefix) { + Ok(hrp) => match encode::(hrp, Sha256::digest(input).as_slice()) { + Ok(address) => Addr::unchecked(address), + Err(reason) => panic!("Generating address failed with reason: {}", reason), + }, + Err(reason) => panic!("Generating address failed with reason: {}", reason), + } + } +} + +/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32] format +/// for humanizing canonical addresses. +/// +/// [Bech32]: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki +pub struct MockApiBech32(MockApiBech); + +impl MockApiBech32 { + /// Returns `Api` implementation that uses specified prefix + /// to generate addresses in `Bech32` format. + /// + /// # Example + /// + /// ``` + /// use cw_multi_test::MockApiBech32; + /// + /// let api = MockApiBech32::new("juno"); + /// let addr = api.addr_make("creator"); + /// assert_eq!(addr.as_str(), + /// "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"); + /// ``` + pub fn new(prefix: &'static str) -> Self { + Self(MockApiBech::new(prefix)) + } +} + +impl Api for MockApiBech32 { + /// Takes a human-readable address in `Bech32` format and checks if it is valid. + /// + /// If the validation succeeds, an `Addr` containing the same string as the input is returned. + /// + /// # Example + /// + /// ``` + /// use cosmwasm_std::Api; + /// use cw_multi_test::MockApiBech32; + /// + /// let api = MockApiBech32::new("juno"); + /// let addr = api.addr_make("creator"); + /// assert_eq!(api.addr_validate(addr.as_str()).unwrap().as_str(), + /// addr.as_str()); + /// ``` + fn addr_validate(&self, input: &str) -> StdResult { + self.0.addr_humanize(&self.addr_canonicalize(input)?) + } + + /// Takes a human-readable address in `Bech32` format and returns + /// a canonical binary representation of it. + /// + /// # Example + /// + /// ``` + /// use cosmwasm_std::Api; + /// use cw_multi_test::MockApiBech32; + /// + /// let api = MockApiBech32::new("juno"); + /// let addr = api.addr_make("creator"); + /// assert_eq!(api.addr_canonicalize(addr.as_str()).unwrap().to_string(), + /// "BC6BFD848EBD7819C9A82BF124D65E7F739D08E002601E23BB906AACD40A3D81"); + /// ``` + fn addr_canonicalize(&self, input: &str) -> StdResult { + self.0.addr_canonicalize(input) + } + + /// Takes a canonical address and returns a human-readable address in `Bech32` format. + /// + /// This is the inverse operation of [`addr_canonicalize`]. + /// + /// [`addr_canonicalize`]: MockApiBech32::addr_canonicalize + /// + /// # Example + /// + /// ``` + /// use cosmwasm_std::Api; + /// use cw_multi_test::MockApiBech32; + /// + /// let api = MockApiBech32::new("juno"); + /// let addr = api.addr_make("creator"); + /// let canonical_addr = api.addr_canonicalize(addr.as_str()).unwrap(); + /// assert_eq!(api.addr_humanize(&canonical_addr).unwrap().as_str(), + /// addr.as_str()); + /// ``` + fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { + self.0.addr_humanize(canonical) + } + + fn secp256k1_verify( + &self, + message_hash: &[u8], + signature: &[u8], + public_key: &[u8], + ) -> Result { + self.0.secp256k1_verify(message_hash, signature, public_key) + } + + fn secp256k1_recover_pubkey( + &self, + message_hash: &[u8], + signature: &[u8], + recovery_param: u8, + ) -> Result, RecoverPubkeyError> { + self.0 + .secp256k1_recover_pubkey(message_hash, signature, recovery_param) + } + + fn ed25519_verify( + &self, + message: &[u8], + signature: &[u8], + public_key: &[u8], + ) -> Result { + self.0.ed25519_verify(message, signature, public_key) + } + + fn ed25519_batch_verify( + &self, + messages: &[&[u8]], + signatures: &[&[u8]], + public_keys: &[&[u8]], + ) -> Result { + self.0 + .ed25519_batch_verify(messages, signatures, public_keys) + } + + fn debug(&self, message: &str) { + self.0.debug(message) + } +} + +impl MockApiBech32 { + /// Returns an address in `Bech32` format, built from provided input string. + /// + /// # Example + /// + /// ``` + /// use cw_multi_test::MockApiBech32; + /// + /// let api = MockApiBech32::new("juno"); + /// let addr = api.addr_make("creator"); + /// assert_eq!(addr.as_str(), + /// "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"); + /// ``` + /// + /// # Panics + /// + /// This function panics when generating a valid address in **Bech32** + /// format is not possible, especially when prefix is too long or empty. + pub fn addr_make(&self, input: &str) -> Addr { + self.0.addr_make(input) + } +} + +/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32m] format +/// for humanizing canonical addresses. +/// +/// [Bech32m]: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki +pub struct MockApiBech32m(MockApiBech); + +impl MockApiBech32m { + /// Returns `Api` implementation that uses specified prefix + /// to generate addresses in `Bech32m` format. + /// + /// # Example + /// + /// ``` + /// use cw_multi_test::MockApiBech32m; + /// + /// let api = MockApiBech32m::new("osmo"); + /// let addr = api.addr_make("sender"); + /// assert_eq!(addr.as_str(), + /// "osmo1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qdlmaeg"); + /// ``` + pub fn new(prefix: &'static str) -> Self { + Self(MockApiBech::new(prefix)) + } +} + +impl Api for MockApiBech32m { + /// Takes a human-readable address in `Bech32m` format and checks if it is valid. + /// + /// If the validation succeeds, an `Addr` containing the same string as the input is returned. + /// + /// # Example + /// + /// ``` + /// use cosmwasm_std::Api; + /// use cw_multi_test::MockApiBech32m; + /// + /// let api = MockApiBech32m::new("osmo"); + /// let addr = api.addr_make("sender"); + /// assert_eq!(api.addr_validate(addr.as_str()).unwrap().as_str(), + /// addr.as_str()); + /// ``` + fn addr_validate(&self, input: &str) -> StdResult { + self.0.addr_humanize(&self.addr_canonicalize(input)?) + } + + /// Takes a human-readable address in `Bech32m` format and returns + /// a canonical binary representation of it. + /// + /// # Example + /// + /// ``` + /// use cosmwasm_std::Api; + /// use cw_multi_test::MockApiBech32; + /// + /// let api = MockApiBech32::new("osmo"); + /// let addr = api.addr_make("sender"); + /// assert_eq!(api.addr_canonicalize(addr.as_str()).unwrap().to_string(), + /// "0A367B92CF0B037DFD89960EE832D56F7FC151681BB41E53690E776F5786998A"); + /// ``` + fn addr_canonicalize(&self, input: &str) -> StdResult { + self.0.addr_canonicalize(input) + } + + /// Takes a canonical address and returns a human-readable address in `Bech32m` format. + /// + /// This is the inverse operation of [`addr_canonicalize`]. + /// + /// [`addr_canonicalize`]: MockApiBech32m::addr_canonicalize + /// + /// # Example + /// + /// ``` + /// use cosmwasm_std::Api; + /// use cw_multi_test::MockApiBech32m; + /// + /// let api = MockApiBech32m::new("osmo"); + /// let addr = api.addr_make("sender"); + /// let canonical_addr = api.addr_canonicalize(addr.as_str()).unwrap(); + /// assert_eq!(api.addr_humanize(&canonical_addr).unwrap().as_str(), + /// addr.as_str()); + /// ``` + fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { + self.0.addr_humanize(canonical) + } + + fn secp256k1_verify( + &self, + message_hash: &[u8], + signature: &[u8], + public_key: &[u8], + ) -> Result { + self.0.secp256k1_verify(message_hash, signature, public_key) + } + + fn secp256k1_recover_pubkey( + &self, + message_hash: &[u8], + signature: &[u8], + recovery_param: u8, + ) -> Result, RecoverPubkeyError> { + self.0 + .secp256k1_recover_pubkey(message_hash, signature, recovery_param) + } + + fn ed25519_verify( + &self, + message: &[u8], + signature: &[u8], + public_key: &[u8], + ) -> Result { + self.0.ed25519_verify(message, signature, public_key) + } + + fn ed25519_batch_verify( + &self, + messages: &[&[u8]], + signatures: &[&[u8]], + public_keys: &[&[u8]], + ) -> Result { + self.0 + .ed25519_batch_verify(messages, signatures, public_keys) + } + + fn debug(&self, message: &str) { + self.0.debug(message) + } +} + +impl MockApiBech32m { + /// Returns an address in `Bech32m` format, built from provided input string. + /// + /// # Example + /// + /// ``` + /// use cw_multi_test::MockApiBech32m; + /// + /// let api = MockApiBech32m::new("osmo"); + /// let addr = api.addr_make("sender"); + /// assert_eq!(addr.as_str(), + /// "osmo1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qdlmaeg"); + /// ``` + /// + /// # Panics + /// + /// This function panics when generating a valid address in **Bech32** + /// format is not possible, especially when prefix is too long or empty. + pub fn addr_make(&self, input: &str) -> Addr { + self.0.addr_make(input) + } +} diff --git a/src/lib.rs b/src/lib.rs index 7d7c4ac7..d5f1225b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -125,6 +125,7 @@ #![deny(rustdoc::missing_crate_level_docs)] mod addresses; +mod api; mod app; mod app_builder; mod bank; @@ -144,7 +145,10 @@ mod tests; mod transactions; mod wasm; -pub use crate::addresses::{AddressGenerator, IntoBech32, IntoBech32m, SimpleAddressGenerator}; +pub use crate::addresses::{ + AddressGenerator, IntoAddr, IntoBech32, IntoBech32m, SimpleAddressGenerator, +}; +pub use crate::api::{MockApiBech32, MockApiBech32m}; pub use crate::app::{ custom_app, next_block, no_init, App, BasicApp, CosmosRouter, Router, SudoMsg, }; diff --git a/tests/test_api/mod.rs b/tests/test_api/mod.rs index e6be8297..d429f30f 100644 --- a/tests/test_api/mod.rs +++ b/tests/test_api/mod.rs @@ -1,6 +1,9 @@ use cosmwasm_std::Api; use hex_literal::hex; +mod test_addr; +mod test_bech32; +mod test_bech32m; mod test_prefixed; const SECP256K1_MSG_HASH: [u8; 32] = diff --git a/tests/test_api/test_addr.rs b/tests/test_api/test_addr.rs new file mode 100644 index 00000000..015f338e --- /dev/null +++ b/tests/test_api/test_addr.rs @@ -0,0 +1,21 @@ +use cosmwasm_std::testing::MockApi; +use cw_multi_test::IntoAddr; + +#[test] +fn conversion_with_default_prefix_should_work() { + assert_eq!( + MockApi::default().addr_make("creator").as_str(), + "creator".into_addr().as_str(), + ); +} + +#[test] +fn conversion_with_custom_prefix_should_work() { + assert_eq!( + MockApi::default() + .with_prefix("juno") + .addr_make("sender") + .as_str(), + "sender".into_addr_with_prefix("juno").as_str(), + ); +} diff --git a/tests/test_api/test_bech32.rs b/tests/test_api/test_bech32.rs new file mode 100644 index 00000000..4e0953fc --- /dev/null +++ b/tests/test_api/test_bech32.rs @@ -0,0 +1,117 @@ +use super::*; +use cosmwasm_std::CanonicalAddr; +use cw_multi_test::{IntoBech32, IntoBech32m, MockApiBech32, MockApiBech32m}; + +const HUMAN_ADDRESS: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"; + +#[test] +fn new_api_bech32_should_work() { + assert_eq!( + MockApiBech32::new("juno").addr_make("creator").as_str(), + HUMAN_ADDRESS + ); + assert_eq!( + "creator".into_bech32_with_prefix("juno").as_str(), + HUMAN_ADDRESS + ); +} + +#[test] +fn api_bech32_should_differ_from_bech32m() { + assert_ne!( + MockApiBech32::new("juno").addr_make("sender").as_str(), + MockApiBech32m::new("juno").addr_make("sender").as_str(), + ); + assert_ne!( + "sender".into_bech32_with_prefix("juno").as_str(), + "sender".into_bech32m_with_prefix("juno").as_str() + ); +} + +#[test] +fn address_validate_should_work() { + assert_eq!( + MockApiBech32::new("juno") + .addr_validate(HUMAN_ADDRESS) + .unwrap() + .as_str(), + HUMAN_ADDRESS + ) +} + +#[test] +fn address_validate_invalid_address() { + MockApiBech32::new("juno") + .addr_validate("creator") + .unwrap_err(); +} + +#[test] +fn addr_validate_invalid_prefix() { + MockApiBech32::new("juno") + .addr_validate(MockApiBech32m::new("osmosis").addr_make("creator").as_str()) + .unwrap_err(); +} + +#[test] +fn address_validate_invalid_variant() { + MockApiBech32::new("juno") + .addr_validate(MockApiBech32m::new("juno").addr_make("creator").as_str()) + .unwrap_err(); +} + +#[test] +fn address_canonicalize_humanize_should_work() { + let api = MockApiBech32::new("juno"); + assert_eq!( + api.addr_humanize(&api.addr_canonicalize(HUMAN_ADDRESS).unwrap()) + .unwrap() + .as_str(), + HUMAN_ADDRESS + ); +} + +#[test] +fn address_humanize_prefix_too_long() { + MockApiBech32::new( + "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", + ) + .addr_humanize(&CanonicalAddr::from([1, 2, 3, 4, 5])) + .unwrap_err(); +} + +#[test] +fn debug_should_not_panic() { + assert_debug_does_not_panic(&MockApiBech32::new("juno")); +} + +#[test] +#[should_panic( + expected = "Generating address failed with reason: hrp is too long, found 85 characters, must be <= 126" +)] +fn address_make_prefix_too_long() { + MockApiBech32::new( + "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", + ) + .addr_make("creator"); +} + +#[test] +fn secp256k1_verify_works() { + assert_secp256k1_verify_works(&MockApiBech32::new("juno")); +} + +#[test] +fn secp256k1_recover_pubkey_works() { + assert_secp256k1_recover_pubkey_works(&MockApiBech32::new("juno")); +} + +#[test] +fn ed25519_verify_works() { + assert_ed25519_verify_works(&MockApiBech32::new("juno")); +} + +#[test] +fn ed25519_batch_verify_works() { + assert_ed25519_batch_verify_works(&MockApiBech32::new("juno")); +} diff --git a/tests/test_api/test_bech32m.rs b/tests/test_api/test_bech32m.rs new file mode 100644 index 00000000..afe15609 --- /dev/null +++ b/tests/test_api/test_bech32m.rs @@ -0,0 +1,117 @@ +use super::*; +use cosmwasm_std::CanonicalAddr; +use cw_multi_test::{IntoBech32, IntoBech32m, MockApiBech32, MockApiBech32m}; + +const HUMAN_ADDRESS: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsrvt8pr"; + +#[test] +fn new_api_bech32m_should_work() { + assert_eq!( + MockApiBech32m::new("juno").addr_make("creator").as_str(), + HUMAN_ADDRESS + ); + assert_eq!( + "creator".into_bech32m_with_prefix("juno").as_str(), + HUMAN_ADDRESS + ); +} + +#[test] +fn api_bech32m_should_differ_from_bech32() { + assert_ne!( + MockApiBech32m::new("juno").addr_make("sender").as_str(), + MockApiBech32::new("juno").addr_make("sender").as_str() + ); + assert_ne!( + "sender".into_bech32m_with_prefix("juno").as_str(), + "sender".into_bech32_with_prefix("juno").as_str() + ); +} + +#[test] +fn address_validate_should_work() { + assert_eq!( + MockApiBech32m::new("juno") + .addr_validate(HUMAN_ADDRESS) + .unwrap() + .as_str(), + HUMAN_ADDRESS + ) +} + +#[test] +fn address_validate_invalid_address() { + MockApiBech32m::new("juno") + .addr_validate("creator") + .unwrap_err(); +} + +#[test] +fn addr_validate_invalid_prefix() { + MockApiBech32m::new("juno") + .addr_validate(MockApiBech32m::new("osmosis").addr_make("creator").as_str()) + .unwrap_err(); +} + +#[test] +fn address_validate_invalid_variant() { + MockApiBech32m::new("juno") + .addr_validate(MockApiBech32::new("juno").addr_make("creator").as_str()) + .unwrap_err(); +} + +#[test] +fn address_canonicalize_humanize_should_work() { + let api = MockApiBech32m::new("juno"); + assert_eq!( + api.addr_humanize(&api.addr_canonicalize(HUMAN_ADDRESS).unwrap()) + .unwrap() + .as_str(), + HUMAN_ADDRESS + ); +} + +#[test] +fn address_humanize_prefix_too_long() { + MockApiBech32m::new( + "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", + ) + .addr_humanize(&CanonicalAddr::from([1, 2, 3, 4, 5])) + .unwrap_err(); +} + +#[test] +fn debug_should_not_panic() { + assert_debug_does_not_panic(&MockApiBech32m::new("juno")); +} + +#[test] +#[should_panic( + expected = "Generating address failed with reason: hrp is too long, found 85 characters, must be <= 126" +)] +fn address_make_prefix_too_long() { + MockApiBech32m::new( + "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", + ) + .addr_make("creator"); +} + +#[test] +fn secp256k1_verify_works() { + assert_secp256k1_verify_works(&MockApiBech32m::new("juno")); +} + +#[test] +fn secp256k1_recover_pubkey_works() { + assert_secp256k1_recover_pubkey_works(&MockApiBech32m::new("juno")); +} + +#[test] +fn ed25519_verify_works() { + assert_ed25519_verify_works(&MockApiBech32m::new("juno")); +} + +#[test] +fn ed25519_batch_verify_works() { + assert_ed25519_batch_verify_works(&MockApiBech32m::new("juno")); +} From 6f80d8f6c3e543bd69f9b6e9a4bd6de1d8254a2a Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 8 Mar 2024 12:37:21 +0100 Subject: [PATCH 120/250] Added tests. --- tests/test_api/test_bech32.rs | 20 +++++++++++++------- tests/test_api/test_bech32m.rs | 20 +++++++++++++------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/tests/test_api/test_bech32.rs b/tests/test_api/test_bech32.rs index 4e0953fc..4380e444 100644 --- a/tests/test_api/test_bech32.rs +++ b/tests/test_api/test_bech32.rs @@ -2,18 +2,20 @@ use super::*; use cosmwasm_std::CanonicalAddr; use cw_multi_test::{IntoBech32, IntoBech32m, MockApiBech32, MockApiBech32m}; -const HUMAN_ADDRESS: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"; +const ADDR_JUNO: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"; +const ADDR_DEFAULT: &str = "cosmwasm1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqs8s7vcp"; #[test] fn new_api_bech32_should_work() { assert_eq!( MockApiBech32::new("juno").addr_make("creator").as_str(), - HUMAN_ADDRESS + ADDR_JUNO ); assert_eq!( "creator".into_bech32_with_prefix("juno").as_str(), - HUMAN_ADDRESS + ADDR_JUNO ); + assert_eq!("creator".into_bech32().as_str(), ADDR_DEFAULT); } #[test] @@ -26,16 +28,20 @@ fn api_bech32_should_differ_from_bech32m() { "sender".into_bech32_with_prefix("juno").as_str(), "sender".into_bech32m_with_prefix("juno").as_str() ); + assert_ne!( + "sender".into_bech32().as_str(), + "sender".into_bech32m().as_str() + ); } #[test] fn address_validate_should_work() { assert_eq!( MockApiBech32::new("juno") - .addr_validate(HUMAN_ADDRESS) + .addr_validate(ADDR_JUNO) .unwrap() .as_str(), - HUMAN_ADDRESS + ADDR_JUNO ) } @@ -64,10 +70,10 @@ fn address_validate_invalid_variant() { fn address_canonicalize_humanize_should_work() { let api = MockApiBech32::new("juno"); assert_eq!( - api.addr_humanize(&api.addr_canonicalize(HUMAN_ADDRESS).unwrap()) + api.addr_humanize(&api.addr_canonicalize(ADDR_JUNO).unwrap()) .unwrap() .as_str(), - HUMAN_ADDRESS + ADDR_JUNO ); } diff --git a/tests/test_api/test_bech32m.rs b/tests/test_api/test_bech32m.rs index afe15609..6fce3cf2 100644 --- a/tests/test_api/test_bech32m.rs +++ b/tests/test_api/test_bech32m.rs @@ -2,18 +2,20 @@ use super::*; use cosmwasm_std::CanonicalAddr; use cw_multi_test::{IntoBech32, IntoBech32m, MockApiBech32, MockApiBech32m}; -const HUMAN_ADDRESS: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsrvt8pr"; +const ADDR_JUNO: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsrvt8pr"; +const ADDR_DEFAULT: &str = "cosmwasm1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsjvwqar"; #[test] fn new_api_bech32m_should_work() { assert_eq!( MockApiBech32m::new("juno").addr_make("creator").as_str(), - HUMAN_ADDRESS + ADDR_JUNO ); assert_eq!( "creator".into_bech32m_with_prefix("juno").as_str(), - HUMAN_ADDRESS + ADDR_JUNO ); + assert_eq!("creator".into_bech32m().as_str(), ADDR_DEFAULT); } #[test] @@ -26,16 +28,20 @@ fn api_bech32m_should_differ_from_bech32() { "sender".into_bech32m_with_prefix("juno").as_str(), "sender".into_bech32_with_prefix("juno").as_str() ); + assert_ne!( + "sender".into_bech32m().as_str(), + "sender".into_bech32().as_str() + ); } #[test] fn address_validate_should_work() { assert_eq!( MockApiBech32m::new("juno") - .addr_validate(HUMAN_ADDRESS) + .addr_validate(ADDR_JUNO) .unwrap() .as_str(), - HUMAN_ADDRESS + ADDR_JUNO ) } @@ -64,10 +70,10 @@ fn address_validate_invalid_variant() { fn address_canonicalize_humanize_should_work() { let api = MockApiBech32m::new("juno"); assert_eq!( - api.addr_humanize(&api.addr_canonicalize(HUMAN_ADDRESS).unwrap()) + api.addr_humanize(&api.addr_canonicalize(ADDR_JUNO).unwrap()) .unwrap() .as_str(), - HUMAN_ADDRESS + ADDR_JUNO ); } From 05c955b1e402631db24b58c436dfecf20f8aadc9 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 8 Mar 2024 13:50:15 +0100 Subject: [PATCH 121/250] Refactoring. --- src/api.rs | 303 +-------------------------------- tests/test_api/test_bech32.rs | 7 + tests/test_api/test_bech32m.rs | 7 + 3 files changed, 19 insertions(+), 298 deletions(-) diff --git a/src/api.rs b/src/api.rs index 27e2fc33..c09d0079 100644 --- a/src/api.rs +++ b/src/api.rs @@ -6,7 +6,7 @@ use cosmwasm_std::{ }; use sha2::{Digest, Sha256}; -struct MockApiBech { +pub struct MockApiBech { api: MockApi, prefix: &'static str, _phantom_data: std::marker::PhantomData, @@ -97,13 +97,10 @@ impl MockApiBech { /// # Panics /// /// This function panics when generating a valid address in `Bech32` or `Bech32m` - /// format is not possible, especially when prefix is too long or empty. + /// format is not possible, especially when the prefix is too long or empty. pub fn addr_make(&self, input: &str) -> Addr { match Hrp::parse(self.prefix) { - Ok(hrp) => match encode::(hrp, Sha256::digest(input).as_slice()) { - Ok(address) => Addr::unchecked(address), - Err(reason) => panic!("Generating address failed with reason: {}", reason), - }, + Ok(hrp) => Addr::unchecked(encode::(hrp, Sha256::digest(input).as_slice()).unwrap()), Err(reason) => panic!("Generating address failed with reason: {}", reason), } } @@ -113,300 +110,10 @@ impl MockApiBech { /// for humanizing canonical addresses. /// /// [Bech32]: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki -pub struct MockApiBech32(MockApiBech); - -impl MockApiBech32 { - /// Returns `Api` implementation that uses specified prefix - /// to generate addresses in `Bech32` format. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(addr.as_str(), - /// "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"); - /// ``` - pub fn new(prefix: &'static str) -> Self { - Self(MockApiBech::new(prefix)) - } -} - -impl Api for MockApiBech32 { - /// Takes a human-readable address in `Bech32` format and checks if it is valid. - /// - /// If the validation succeeds, an `Addr` containing the same string as the input is returned. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(api.addr_validate(addr.as_str()).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_validate(&self, input: &str) -> StdResult { - self.0.addr_humanize(&self.addr_canonicalize(input)?) - } - - /// Takes a human-readable address in `Bech32` format and returns - /// a canonical binary representation of it. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(api.addr_canonicalize(addr.as_str()).unwrap().to_string(), - /// "BC6BFD848EBD7819C9A82BF124D65E7F739D08E002601E23BB906AACD40A3D81"); - /// ``` - fn addr_canonicalize(&self, input: &str) -> StdResult { - self.0.addr_canonicalize(input) - } - - /// Takes a canonical address and returns a human-readable address in `Bech32` format. - /// - /// This is the inverse operation of [`addr_canonicalize`]. - /// - /// [`addr_canonicalize`]: MockApiBech32::addr_canonicalize - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// let canonical_addr = api.addr_canonicalize(addr.as_str()).unwrap(); - /// assert_eq!(api.addr_humanize(&canonical_addr).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - self.0.addr_humanize(canonical) - } - - fn secp256k1_verify( - &self, - message_hash: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.0.secp256k1_verify(message_hash, signature, public_key) - } - - fn secp256k1_recover_pubkey( - &self, - message_hash: &[u8], - signature: &[u8], - recovery_param: u8, - ) -> Result, RecoverPubkeyError> { - self.0 - .secp256k1_recover_pubkey(message_hash, signature, recovery_param) - } - - fn ed25519_verify( - &self, - message: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.0.ed25519_verify(message, signature, public_key) - } - - fn ed25519_batch_verify( - &self, - messages: &[&[u8]], - signatures: &[&[u8]], - public_keys: &[&[u8]], - ) -> Result { - self.0 - .ed25519_batch_verify(messages, signatures, public_keys) - } - - fn debug(&self, message: &str) { - self.0.debug(message) - } -} - -impl MockApiBech32 { - /// Returns an address in `Bech32` format, built from provided input string. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(addr.as_str(), - /// "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"); - /// ``` - /// - /// # Panics - /// - /// This function panics when generating a valid address in **Bech32** - /// format is not possible, especially when prefix is too long or empty. - pub fn addr_make(&self, input: &str) -> Addr { - self.0.addr_make(input) - } -} +pub type MockApiBech32 = MockApiBech; /// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32m] format /// for humanizing canonical addresses. /// /// [Bech32m]: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki -pub struct MockApiBech32m(MockApiBech); - -impl MockApiBech32m { - /// Returns `Api` implementation that uses specified prefix - /// to generate addresses in `Bech32m` format. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmo"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(addr.as_str(), - /// "osmo1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qdlmaeg"); - /// ``` - pub fn new(prefix: &'static str) -> Self { - Self(MockApiBech::new(prefix)) - } -} - -impl Api for MockApiBech32m { - /// Takes a human-readable address in `Bech32m` format and checks if it is valid. - /// - /// If the validation succeeds, an `Addr` containing the same string as the input is returned. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmo"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(api.addr_validate(addr.as_str()).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_validate(&self, input: &str) -> StdResult { - self.0.addr_humanize(&self.addr_canonicalize(input)?) - } - - /// Takes a human-readable address in `Bech32m` format and returns - /// a canonical binary representation of it. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::MockApiBech32; - /// - /// let api = MockApiBech32::new("osmo"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(api.addr_canonicalize(addr.as_str()).unwrap().to_string(), - /// "0A367B92CF0B037DFD89960EE832D56F7FC151681BB41E53690E776F5786998A"); - /// ``` - fn addr_canonicalize(&self, input: &str) -> StdResult { - self.0.addr_canonicalize(input) - } - - /// Takes a canonical address and returns a human-readable address in `Bech32m` format. - /// - /// This is the inverse operation of [`addr_canonicalize`]. - /// - /// [`addr_canonicalize`]: MockApiBech32m::addr_canonicalize - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmo"); - /// let addr = api.addr_make("sender"); - /// let canonical_addr = api.addr_canonicalize(addr.as_str()).unwrap(); - /// assert_eq!(api.addr_humanize(&canonical_addr).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - self.0.addr_humanize(canonical) - } - - fn secp256k1_verify( - &self, - message_hash: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.0.secp256k1_verify(message_hash, signature, public_key) - } - - fn secp256k1_recover_pubkey( - &self, - message_hash: &[u8], - signature: &[u8], - recovery_param: u8, - ) -> Result, RecoverPubkeyError> { - self.0 - .secp256k1_recover_pubkey(message_hash, signature, recovery_param) - } - - fn ed25519_verify( - &self, - message: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.0.ed25519_verify(message, signature, public_key) - } - - fn ed25519_batch_verify( - &self, - messages: &[&[u8]], - signatures: &[&[u8]], - public_keys: &[&[u8]], - ) -> Result { - self.0 - .ed25519_batch_verify(messages, signatures, public_keys) - } - - fn debug(&self, message: &str) { - self.0.debug(message) - } -} - -impl MockApiBech32m { - /// Returns an address in `Bech32m` format, built from provided input string. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmo"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(addr.as_str(), - /// "osmo1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qdlmaeg"); - /// ``` - /// - /// # Panics - /// - /// This function panics when generating a valid address in **Bech32** - /// format is not possible, especially when prefix is too long or empty. - pub fn addr_make(&self, input: &str) -> Addr { - self.0.addr_make(input) - } -} +pub type MockApiBech32m = MockApiBech; diff --git a/tests/test_api/test_bech32.rs b/tests/test_api/test_bech32.rs index 4380e444..8bb74499 100644 --- a/tests/test_api/test_bech32.rs +++ b/tests/test_api/test_bech32.rs @@ -86,6 +86,13 @@ fn address_humanize_prefix_too_long() { .unwrap_err(); } +#[test] +fn address_humanize_canonical_too_long() { + MockApiBech32::new("juno") + .addr_humanize(&CanonicalAddr::from([1; 1024])) + .unwrap_err(); +} + #[test] fn debug_should_not_panic() { assert_debug_does_not_panic(&MockApiBech32::new("juno")); diff --git a/tests/test_api/test_bech32m.rs b/tests/test_api/test_bech32m.rs index 6fce3cf2..6a649e53 100644 --- a/tests/test_api/test_bech32m.rs +++ b/tests/test_api/test_bech32m.rs @@ -86,6 +86,13 @@ fn address_humanize_prefix_too_long() { .unwrap_err(); } +#[test] +fn address_humanize_canonical_too_long() { + MockApiBech32m::new("juno") + .addr_humanize(&CanonicalAddr::from([1; 1024])) + .unwrap_err(); +} + #[test] fn debug_should_not_panic() { assert_debug_does_not_panic(&MockApiBech32m::new("juno")); From 8cccfd81f4c0a03ded5d1905d02ae50a3fb7addb Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 8 Mar 2024 15:29:42 +0100 Subject: [PATCH 122/250] Added IntoAddr trait, refactoring. --- src/addons/addresses/mock.rs | 148 ------------- src/addons/addresses/mod.rs | 1 - src/addons/api/b32.rs | 154 ------------- src/addons/api/b32m.rs | 154 ------------- src/addons/mod.rs | 12 - src/addresses.rs | 206 +++++++++++++++++- src/{addons/api/mod.rs => api.rs} | 26 ++- src/lib.rs | 8 +- tests/mod.rs | 2 +- tests/test_addons/mod.rs | 1 - tests/{test_addons => }/test_api/mod.rs | 1 + tests/test_api/test_addr.rs | 21 ++ .../{test_addons => }/test_api/test_bech32.rs | 39 +++- .../test_api/test_bech32m.rs | 35 ++- tests/test_app/test_instantiate2.rs | 2 +- .../test_app/test_store_code_with_creator.rs | 2 +- tests/test_app_builder/test_with_api.rs | 2 +- tests/test_wasm/test_with_addr_gen.rs | 2 +- 18 files changed, 312 insertions(+), 504 deletions(-) delete mode 100644 src/addons/addresses/mock.rs delete mode 100644 src/addons/addresses/mod.rs delete mode 100644 src/addons/api/b32.rs delete mode 100644 src/addons/api/b32m.rs delete mode 100644 src/addons/mod.rs rename src/{addons/api/mod.rs => api.rs} (80%) delete mode 100644 tests/test_addons/mod.rs rename tests/{test_addons => }/test_api/mod.rs (99%) create mode 100644 tests/test_api/test_addr.rs rename tests/{test_addons => }/test_api/test_bech32.rs (66%) rename tests/{test_addons => }/test_api/test_bech32m.rs (70%) diff --git a/src/addons/addresses/mock.rs b/src/addons/addresses/mock.rs deleted file mode 100644 index ab166f95..00000000 --- a/src/addons/addresses/mock.rs +++ /dev/null @@ -1,148 +0,0 @@ -use crate::error::AnyResult; -use crate::AddressGenerator; -use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage}; -use sha2::digest::Update; -use sha2::{Digest, Sha256}; - -/// Address generator that mimics the [wasmd](https://github.com/CosmWasm/wasmd) behavior. -/// -/// [MockAddressGenerator] implements [AddressGenerator] trait in terms of -/// [`contract_address`](AddressGenerator::contract_address) and -/// [`predictable_contract_address`](AddressGenerator::predictable_contract_address) functions: -/// - `contract_address` generates non-predictable addresses for contracts, -/// using the same algorithm as `wasmd`, see: [`BuildContractAddressClassic`] for details. -/// - `predictable_contract_address` generates predictable addresses for contracts using -/// [`instantiate2_address`] function defined in `cosmwasm-std`. -/// -/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41 -/// [`instantiate2_address`]:https://github.com/CosmWasm/cosmwasm/blob/8a652d7cd8071f71139deca6be8194ed4a278b2c/packages/std/src/addresses.rs#L309-L318 -#[derive(Default)] -pub struct MockAddressGenerator; - -impl AddressGenerator for MockAddressGenerator { - /// Generates a _non-predictable_ contract address, like `wasmd` does it in real-life chain. - /// - /// Note that addresses generated by `wasmd` may change and users **should not** - /// rely on this value in any extend. - /// - /// Returns the contract address after its instantiation. - /// Address generated by this function is returned as a result - /// of processing `WasmMsg::Instantiate` message. - /// - /// **NOTES** - /// > 👉 The canonical address generated by this function is humanized using the - /// > `Api::addr_humanize` function, so the resulting value depends on used `Api` implementation. - /// > The following example uses Bech32 format for humanizing canonical addresses. - /// - /// > 👉 Do NOT use this function **directly** to generate a contract address, - /// > pass this address generator to `WasmKeeper`: - /// > `WasmKeeper::new().with_address_generator(MockAddressGenerator::default());` - /// - /// # Example - /// - /// ``` - /// # use cosmwasm_std::testing::MockStorage; - /// # use cw_multi_test::AddressGenerator; - /// # use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; - /// // use `Api` that implements Bech32 format - /// let api = MockApiBech32::new("juno"); - /// // prepare mock storage - /// let mut storage = MockStorage::default(); - /// // initialize the address generator - /// let address_generator = MockAddressGenerator::default(); - /// // generate the address - /// let addr = address_generator.contract_address(&api, &mut storage, 1, 1).unwrap(); - /// - /// assert_eq!(addr.to_string(), - /// "juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8"); - /// ``` - fn contract_address( - &self, - api: &dyn Api, - _storage: &mut dyn Storage, - code_id: u64, - instance_id: u64, - ) -> AnyResult { - let canonical_addr = instantiate_address(code_id, instance_id); - Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) - } - - /// Generates a _predictable_ contract address, like `wasmd` does it in real-life chain. - /// - /// Returns a contract address after its instantiation. - /// Address generated by this function is returned as a result - /// of processing `WasmMsg::Instantiate2` message. - /// - /// **NOTES** - /// > 👉 The canonical address generated by this function is humanized using the - /// > `Api::addr_humanize` function, so the resulting value depends on used `Api` implementation. - /// > The following example uses Bech32 format for humanizing canonical addresses. - /// - /// > 👉 Do NOT use this function **directly** to generate a contract address, - /// > pass this address generator to WasmKeeper: - /// > `WasmKeeper::new().with_address_generator(MockAddressGenerator::default());` - /// - /// # Example - /// - /// ``` - /// # use cosmwasm_std::Api; - /// # use cosmwasm_std::testing::MockStorage; - /// # use cw_multi_test::AddressGenerator; - /// # use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; - /// // use `Api` that implements Bech32 format - /// let api = MockApiBech32::new("juno"); - /// // prepare mock storage - /// let mut storage = MockStorage::default(); - /// // initialize the address generator - /// let address_generator = MockAddressGenerator::default(); - /// // checksum of the contract code base - /// let checksum = [0, 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10, - /// 11,12,13,14,15,16,17,18,19,20,21, - /// 22,23,24,25,26,27,28,29,30,31]; - /// // creator address - /// let creator = api.addr_canonicalize(api.addr_make("creator").as_str()).unwrap(); - /// // salt - /// let salt = [10,11,12]; - /// // generate the address - /// let addr = address_generator - /// .predictable_contract_address(&api, &mut storage, 1, 1, &checksum, &creator, &salt) - /// .unwrap(); - /// - /// assert_eq!(addr.to_string(), - /// "juno1sv3gjp85m3xxluxreruards8ruxk5ykys8qfljwrdj5tv8kqxuhsmlfyud"); - /// ``` - fn predictable_contract_address( - &self, - api: &dyn Api, - _storage: &mut dyn Storage, - _code_id: u64, - _instance_id: u64, - checksum: &[u8], - - creator: &CanonicalAddr, - salt: &[u8], - ) -> AnyResult { - let canonical_addr = instantiate2_address(checksum, creator, salt)?; - Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) - } -} - -/// Returns non-predictable contract address. -/// -/// Address is generated using the same algorithm as [`BuildContractAddressClassic`] -/// implementation in `wasmd`. -/// -/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41 -fn instantiate_address(code_id: u64, instance_id: u64) -> CanonicalAddr { - let mut key = Vec::::new(); - key.extend_from_slice(b"wasm\0"); - key.extend_from_slice(&code_id.to_be_bytes()); - key.extend_from_slice(&instance_id.to_be_bytes()); - let module = Sha256::digest("module".as_bytes()); - Sha256::new() - .chain(module) - .chain(key) - .finalize() - .to_vec() - .into() -} diff --git a/src/addons/addresses/mod.rs b/src/addons/addresses/mod.rs deleted file mode 100644 index 9afc1d5e..00000000 --- a/src/addons/addresses/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod mock; diff --git a/src/addons/api/b32.rs b/src/addons/api/b32.rs deleted file mode 100644 index 0837567d..00000000 --- a/src/addons/api/b32.rs +++ /dev/null @@ -1,154 +0,0 @@ -use crate::addons::api::MockApiBech; -use bech32::Bech32; -use cosmwasm_std::{Addr, Api, CanonicalAddr, RecoverPubkeyError, StdResult, VerificationError}; - -/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32] format -/// for humanizing canonical addresses. -/// -/// [Bech32]: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki -pub struct MockApiBech32(MockApiBech); - -impl MockApiBech32 { - /// Returns `Api` implementation that uses specified prefix - /// to generate addresses in `Bech32` format. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(addr.as_str(), - /// "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"); - /// ``` - pub fn new(prefix: &'static str) -> Self { - Self(MockApiBech::new(prefix)) - } -} - -impl Api for MockApiBech32 { - /// Takes a human-readable address in `Bech32` format and checks if it is valid. - /// - /// If the validation succeeds, an `Addr` containing the same string as the input is returned. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(api.addr_validate(addr.as_str()).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_validate(&self, input: &str) -> StdResult { - self.0.addr_humanize(&self.addr_canonicalize(input)?) - } - - /// Takes a human-readable address in `Bech32` format and returns - /// a canonical binary representation of it. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(api.addr_canonicalize(addr.as_str()).unwrap().to_string(), - /// "BC6BFD848EBD7819C9A82BF124D65E7F739D08E002601E23BB906AACD40A3D81"); - /// ``` - fn addr_canonicalize(&self, input: &str) -> StdResult { - self.0.addr_canonicalize(input) - } - - /// Takes a canonical address and returns a human-readable address in `Bech32` format. - /// - /// This is the inverse operation of [`addr_canonicalize`]. - /// - /// [`addr_canonicalize`]: MockApiBech32::addr_canonicalize - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// let canonical_addr = api.addr_canonicalize(addr.as_str()).unwrap(); - /// assert_eq!(api.addr_humanize(&canonical_addr).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - self.0.addr_humanize(canonical) - } - - fn secp256k1_verify( - &self, - message_hash: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.0.secp256k1_verify(message_hash, signature, public_key) - } - - fn secp256k1_recover_pubkey( - &self, - message_hash: &[u8], - signature: &[u8], - recovery_param: u8, - ) -> Result, RecoverPubkeyError> { - self.0 - .secp256k1_recover_pubkey(message_hash, signature, recovery_param) - } - - fn ed25519_verify( - &self, - message: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.0.ed25519_verify(message, signature, public_key) - } - - fn ed25519_batch_verify( - &self, - messages: &[&[u8]], - signatures: &[&[u8]], - public_keys: &[&[u8]], - ) -> Result { - self.0 - .ed25519_batch_verify(messages, signatures, public_keys) - } - - fn debug(&self, message: &str) { - self.0.debug(message) - } -} - -impl MockApiBech32 { - /// Returns an address in `Bech32` format, built from provided input string. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(addr.as_str(), - /// "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"); - /// ``` - /// - /// # Panics - /// - /// This function panics when generating a valid address in **Bech32** - /// format is not possible, especially when prefix is too long or empty. - pub fn addr_make(&self, input: &str) -> Addr { - self.0.addr_make(input) - } -} diff --git a/src/addons/api/b32m.rs b/src/addons/api/b32m.rs deleted file mode 100644 index 2c91477f..00000000 --- a/src/addons/api/b32m.rs +++ /dev/null @@ -1,154 +0,0 @@ -use crate::addons::api::MockApiBech; -use bech32::Bech32m; -use cosmwasm_std::{Addr, Api, CanonicalAddr, RecoverPubkeyError, StdResult, VerificationError}; - -/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32m] format -/// for humanizing canonical addresses. -/// -/// [Bech32m]: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki -pub struct MockApiBech32m(MockApiBech); - -impl MockApiBech32m { - /// Returns `Api` implementation that uses specified prefix - /// to generate addresses in `Bech32m` format. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::addons::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmo"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(addr.as_str(), - /// "osmo1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qdlmaeg"); - /// ``` - pub fn new(prefix: &'static str) -> Self { - Self(MockApiBech::new(prefix)) - } -} - -impl Api for MockApiBech32m { - /// Takes a human-readable address in `Bech32m` format and checks if it is valid. - /// - /// If the validation succeeds, an `Addr` containing the same string as the input is returned. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmo"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(api.addr_validate(addr.as_str()).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_validate(&self, input: &str) -> StdResult { - self.0.addr_humanize(&self.addr_canonicalize(input)?) - } - - /// Takes a human-readable address in `Bech32m` format and returns - /// a canonical binary representation of it. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("osmo"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(api.addr_canonicalize(addr.as_str()).unwrap().to_string(), - /// "0A367B92CF0B037DFD89960EE832D56F7FC151681BB41E53690E776F5786998A"); - /// ``` - fn addr_canonicalize(&self, input: &str) -> StdResult { - self.0.addr_canonicalize(input) - } - - /// Takes a canonical address and returns a human-readable address in `Bech32m` format. - /// - /// This is the inverse operation of [`addr_canonicalize`]. - /// - /// [`addr_canonicalize`]: MockApiBech32m::addr_canonicalize - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmo"); - /// let addr = api.addr_make("sender"); - /// let canonical_addr = api.addr_canonicalize(addr.as_str()).unwrap(); - /// assert_eq!(api.addr_humanize(&canonical_addr).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - self.0.addr_humanize(canonical) - } - - fn secp256k1_verify( - &self, - message_hash: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.0.secp256k1_verify(message_hash, signature, public_key) - } - - fn secp256k1_recover_pubkey( - &self, - message_hash: &[u8], - signature: &[u8], - recovery_param: u8, - ) -> Result, RecoverPubkeyError> { - self.0 - .secp256k1_recover_pubkey(message_hash, signature, recovery_param) - } - - fn ed25519_verify( - &self, - message: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.0.ed25519_verify(message, signature, public_key) - } - - fn ed25519_batch_verify( - &self, - messages: &[&[u8]], - signatures: &[&[u8]], - public_keys: &[&[u8]], - ) -> Result { - self.0 - .ed25519_batch_verify(messages, signatures, public_keys) - } - - fn debug(&self, message: &str) { - self.0.debug(message) - } -} - -impl MockApiBech32m { - /// Returns an address in `Bech32m` format, built from provided input string. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::addons::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmo"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(addr.as_str(), - /// "osmo1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qdlmaeg"); - /// ``` - /// - /// # Panics - /// - /// This function panics when generating a valid address in **Bech32** - /// format is not possible, especially when prefix is too long or empty. - pub fn addr_make(&self, input: &str) -> Addr { - self.0.addr_make(input) - } -} diff --git a/src/addons/mod.rs b/src/addons/mod.rs deleted file mode 100644 index 648c9b5f..00000000 --- a/src/addons/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! # Additional testing tools (extensions) -//! -//! **CosmWasm MultiTest** addons provide additional tools for testing smart contracts, -//! simulating complex blockchain scenarios that developers might encounter. -//! They enhance the CosmWasm environment, enabling more advanced and nuanced testing. - -mod addresses; -mod api; - -pub use addresses::mock::MockAddressGenerator; -pub use api::b32::MockApiBech32; -pub use api::b32m::MockApiBech32m; diff --git a/src/addresses.rs b/src/addresses.rs index 4b6c4f93..04263b3d 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -1,7 +1,68 @@ //! # Implementation of address generators use crate::error::AnyResult; -use cosmwasm_std::{Addr, Api, CanonicalAddr, HexBinary, Storage}; +use crate::{MockApiBech32, MockApiBech32m}; +use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, HexBinary, Storage}; +use sha2::digest::Update; +use sha2::{Digest, Sha256}; + +const DEFAULT_PREFIX: &str = "cosmwasm"; + +/// Defines conversions to [Addr]. +pub trait IntoAddr { + /// Converts into [Addr]. + fn into_addr(self) -> Addr; + + /// Converts into [Addr] with custom prefix. + fn into_addr_with_prefix(self, prefix: &'static str) -> Addr; +} + +impl IntoAddr for &str { + fn into_addr(self) -> Addr { + MockApiBech32::new(DEFAULT_PREFIX).addr_make(self) + } + + fn into_addr_with_prefix(self, prefix: &'static str) -> Addr { + MockApiBech32::new(prefix).addr_make(self) + } +} + +/// Defines conversions to `Bech32` compatible addresses. +pub trait IntoBech32 { + /// Converts into [Addr] containing a string compatible with `Bech32` format with default prefix. + fn into_bech32(self) -> Addr; + + /// Converts into [Addr] containing a string compatible with `Bech32` format with custom prefix. + fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr; +} + +impl IntoBech32 for &str { + fn into_bech32(self) -> Addr { + MockApiBech32::new(DEFAULT_PREFIX).addr_make(self) + } + + fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr { + MockApiBech32::new(prefix).addr_make(self) + } +} + +/// Defines conversions to `Bech32m` compatible addresses. +pub trait IntoBech32m { + /// Converts into [Addr] containing a string compatible with `Bech32m` format with default prefix. + fn into_bech32m(self) -> Addr; + /// Converts into [Addr] containing a string compatible with `Bech32m` format with custom prefix. + fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr; +} + +impl IntoBech32m for &str { + fn into_bech32m(self) -> Addr { + MockApiBech32m::new(DEFAULT_PREFIX).addr_make(self) + } + + fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr { + MockApiBech32m::new(prefix).addr_make(self) + } +} /// Common address generator interface. /// @@ -113,3 +174,146 @@ pub trait AddressGenerator { pub struct SimpleAddressGenerator; impl AddressGenerator for SimpleAddressGenerator {} + +/// Address generator that mimics the [wasmd](https://github.com/CosmWasm/wasmd) behavior. +/// +/// [crate::addons::MockAddressGenerator] implements [AddressGenerator] trait in terms of +/// [`contract_address`](AddressGenerator::contract_address) and +/// [`predictable_contract_address`](AddressGenerator::predictable_contract_address) functions: +/// - `contract_address` generates non-predictable addresses for contracts, +/// using the same algorithm as `wasmd`, see: [`BuildContractAddressClassic`] for details. +/// - `predictable_contract_address` generates predictable addresses for contracts using +/// [`instantiate2_address`] function defined in `cosmwasm-std`. +/// +/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41 +/// [`instantiate2_address`]:https://github.com/CosmWasm/cosmwasm/blob/8a652d7cd8071f71139deca6be8194ed4a278b2c/packages/std/src/addresses.rs#L309-L318 +#[derive(Default)] +pub struct MockAddressGenerator; + +impl AddressGenerator for MockAddressGenerator { + /// Generates a _non-predictable_ contract address, like `wasmd` does it in real-life chain. + /// + /// Note that addresses generated by `wasmd` may change and users **should not** + /// rely on this value in any extend. + /// + /// Returns the contract address after its instantiation. + /// Address generated by this function is returned as a result + /// of processing `WasmMsg::Instantiate` message. + /// + /// **NOTES** + /// > 👉 The canonical address generated by this function is humanized using the + /// > `Api::addr_humanize` function, so the resulting value depends on used `Api` implementation. + /// > The following example uses Bech32 format for humanizing canonical addresses. + /// + /// > 👉 Do NOT use this function **directly** to generate a contract address, + /// > pass this address generator to `WasmKeeper`: + /// > `WasmKeeper::new().with_address_generator(MockAddressGenerator::default());` + /// + /// # Example + /// + /// ``` + /// # use cosmwasm_std::testing::MockStorage; + /// # use cw_multi_test::AddressGenerator; + /// # use cw_multi_test::{MockAddressGenerator, MockApiBech32}; + /// // use `Api` that implements Bech32 format + /// let api = MockApiBech32::new("juno"); + /// // prepare mock storage + /// let mut storage = MockStorage::default(); + /// // initialize the address generator + /// let address_generator = MockAddressGenerator::default(); + /// // generate the address + /// let addr = address_generator.contract_address(&api, &mut storage, 1, 1).unwrap(); + /// + /// assert_eq!(addr.to_string(), + /// "juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8"); + /// ``` + fn contract_address( + &self, + api: &dyn Api, + _storage: &mut dyn Storage, + code_id: u64, + instance_id: u64, + ) -> AnyResult { + let canonical_addr = instantiate_address(code_id, instance_id); + Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) + } + + /// Generates a _predictable_ contract address, like `wasmd` does it in real-life chain. + /// + /// Returns a contract address after its instantiation. + /// Address generated by this function is returned as a result + /// of processing `WasmMsg::Instantiate2` message. + /// + /// **NOTES** + /// > 👉 The canonical address generated by this function is humanized using the + /// > `Api::addr_humanize` function, so the resulting value depends on used `Api` implementation. + /// > The following example uses Bech32 format for humanizing canonical addresses. + /// + /// > 👉 Do NOT use this function **directly** to generate a contract address, + /// > pass this address generator to WasmKeeper: + /// > `WasmKeeper::new().with_address_generator(MockAddressGenerator::default());` + /// + /// # Example + /// + /// ``` + /// # use cosmwasm_std::Api; + /// # use cosmwasm_std::testing::MockStorage; + /// # use cw_multi_test::AddressGenerator; + /// # use cw_multi_test::{MockAddressGenerator, MockApiBech32}; + /// // use `Api` that implements Bech32 format + /// let api = MockApiBech32::new("juno"); + /// // prepare mock storage + /// let mut storage = MockStorage::default(); + /// // initialize the address generator + /// let address_generator = MockAddressGenerator::default(); + /// // checksum of the contract code base + /// let checksum = [0, 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10, + /// 11,12,13,14,15,16,17,18,19,20,21, + /// 22,23,24,25,26,27,28,29,30,31]; + /// // creator address + /// let creator = api.addr_canonicalize(api.addr_make("creator").as_str()).unwrap(); + /// // salt + /// let salt = [10,11,12]; + /// // generate the address + /// let addr = address_generator + /// .predictable_contract_address(&api, &mut storage, 1, 1, &checksum, &creator, &salt) + /// .unwrap(); + /// + /// assert_eq!(addr.to_string(), + /// "juno1sv3gjp85m3xxluxreruards8ruxk5ykys8qfljwrdj5tv8kqxuhsmlfyud"); + /// ``` + fn predictable_contract_address( + &self, + api: &dyn Api, + _storage: &mut dyn Storage, + _code_id: u64, + _instance_id: u64, + checksum: &[u8], + + creator: &CanonicalAddr, + salt: &[u8], + ) -> AnyResult { + let canonical_addr = instantiate2_address(checksum, creator, salt)?; + Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) + } +} + +/// Returns non-predictable contract address. +/// +/// Address is generated using the same algorithm as [`BuildContractAddressClassic`] +/// implementation in `wasmd`. +/// +/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41 +fn instantiate_address(code_id: u64, instance_id: u64) -> CanonicalAddr { + let mut key = Vec::::new(); + key.extend_from_slice(b"wasm\0"); + key.extend_from_slice(&code_id.to_be_bytes()); + key.extend_from_slice(&instance_id.to_be_bytes()); + let module = Sha256::digest("module".as_bytes()); + Sha256::new() + .chain(module) + .chain(key) + .finalize() + .to_vec() + .into() +} diff --git a/src/addons/api/mod.rs b/src/api.rs similarity index 80% rename from src/addons/api/mod.rs rename to src/api.rs index 1e16c5ab..c09d0079 100644 --- a/src/addons/api/mod.rs +++ b/src/api.rs @@ -1,15 +1,12 @@ use bech32::primitives::decode::CheckedHrpstring; -use bech32::{encode, Hrp}; +use bech32::{encode, Bech32, Bech32m, Hrp}; use cosmwasm_std::testing::MockApi; use cosmwasm_std::{ Addr, Api, CanonicalAddr, RecoverPubkeyError, StdError, StdResult, VerificationError, }; use sha2::{Digest, Sha256}; -pub mod b32; -pub mod b32m; - -struct MockApiBech { +pub struct MockApiBech { api: MockApi, prefix: &'static str, _phantom_data: std::marker::PhantomData, @@ -100,14 +97,23 @@ impl MockApiBech { /// # Panics /// /// This function panics when generating a valid address in `Bech32` or `Bech32m` - /// format is not possible, especially when prefix is too long or empty. + /// format is not possible, especially when the prefix is too long or empty. pub fn addr_make(&self, input: &str) -> Addr { match Hrp::parse(self.prefix) { - Ok(hrp) => match encode::(hrp, Sha256::digest(input).as_slice()) { - Ok(address) => Addr::unchecked(address), - Err(reason) => panic!("Generating address failed with reason: {}", reason), - }, + Ok(hrp) => Addr::unchecked(encode::(hrp, Sha256::digest(input).as_slice()).unwrap()), Err(reason) => panic!("Generating address failed with reason: {}", reason), } } } + +/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32] format +/// for humanizing canonical addresses. +/// +/// [Bech32]: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki +pub type MockApiBech32 = MockApiBech; + +/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32m] format +/// for humanizing canonical addresses. +/// +/// [Bech32m]: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki +pub type MockApiBech32m = MockApiBech; diff --git a/src/lib.rs b/src/lib.rs index 9a6becda..c88382ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -124,8 +124,8 @@ #![deny(rustdoc::broken_intra_doc_links)] #![deny(rustdoc::missing_crate_level_docs)] -pub mod addons; mod addresses; +mod api; mod app; mod app_builder; mod bank; @@ -145,7 +145,11 @@ mod tests; mod transactions; mod wasm; -pub use crate::addresses::{AddressGenerator, SimpleAddressGenerator}; +pub use crate::addresses::{ + AddressGenerator, IntoAddr, IntoBech32, IntoBech32m, MockAddressGenerator, + SimpleAddressGenerator, +}; +pub use crate::api::{MockApiBech32, MockApiBech32m}; pub use crate::app::{ custom_app, next_block, no_init, App, BasicApp, CosmosRouter, Router, SudoMsg, }; diff --git a/tests/mod.rs b/tests/mod.rs index d14c1479..f5370608 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -3,7 +3,7 @@ use cw_storage_plus::Item; use serde::{Deserialize, Serialize}; -mod test_addons; +mod test_api; mod test_app; mod test_app_builder; mod test_module; diff --git a/tests/test_addons/mod.rs b/tests/test_addons/mod.rs deleted file mode 100644 index 0ce9c88e..00000000 --- a/tests/test_addons/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod test_api; diff --git a/tests/test_addons/test_api/mod.rs b/tests/test_api/mod.rs similarity index 99% rename from tests/test_addons/test_api/mod.rs rename to tests/test_api/mod.rs index d049acc5..e50ddd4e 100644 --- a/tests/test_addons/test_api/mod.rs +++ b/tests/test_api/mod.rs @@ -1,6 +1,7 @@ use cosmwasm_std::Api; use hex_literal::hex; +mod test_addr; mod test_bech32; mod test_bech32m; diff --git a/tests/test_api/test_addr.rs b/tests/test_api/test_addr.rs new file mode 100644 index 00000000..015f338e --- /dev/null +++ b/tests/test_api/test_addr.rs @@ -0,0 +1,21 @@ +use cosmwasm_std::testing::MockApi; +use cw_multi_test::IntoAddr; + +#[test] +fn conversion_with_default_prefix_should_work() { + assert_eq!( + MockApi::default().addr_make("creator").as_str(), + "creator".into_addr().as_str(), + ); +} + +#[test] +fn conversion_with_custom_prefix_should_work() { + assert_eq!( + MockApi::default() + .with_prefix("juno") + .addr_make("sender") + .as_str(), + "sender".into_addr_with_prefix("juno").as_str(), + ); +} diff --git a/tests/test_addons/test_api/test_bech32.rs b/tests/test_api/test_bech32.rs similarity index 66% rename from tests/test_addons/test_api/test_bech32.rs rename to tests/test_api/test_bech32.rs index 68448488..8bb74499 100644 --- a/tests/test_addons/test_api/test_bech32.rs +++ b/tests/test_api/test_bech32.rs @@ -1,22 +1,36 @@ use super::*; use cosmwasm_std::CanonicalAddr; -use cw_multi_test::addons::{MockApiBech32, MockApiBech32m}; +use cw_multi_test::{IntoBech32, IntoBech32m, MockApiBech32, MockApiBech32m}; -const HUMAN_ADDRESS: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"; +const ADDR_JUNO: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"; +const ADDR_DEFAULT: &str = "cosmwasm1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqs8s7vcp"; #[test] fn new_api_bech32_should_work() { assert_eq!( MockApiBech32::new("juno").addr_make("creator").as_str(), - HUMAN_ADDRESS + ADDR_JUNO ); + assert_eq!( + "creator".into_bech32_with_prefix("juno").as_str(), + ADDR_JUNO + ); + assert_eq!("creator".into_bech32().as_str(), ADDR_DEFAULT); } #[test] fn api_bech32_should_differ_from_bech32m() { assert_ne!( - MockApiBech32::new("juno").addr_make("creator").as_str(), - MockApiBech32m::new("juno").addr_make("creator").as_str(), + MockApiBech32::new("juno").addr_make("sender").as_str(), + MockApiBech32m::new("juno").addr_make("sender").as_str(), + ); + assert_ne!( + "sender".into_bech32_with_prefix("juno").as_str(), + "sender".into_bech32m_with_prefix("juno").as_str() + ); + assert_ne!( + "sender".into_bech32().as_str(), + "sender".into_bech32m().as_str() ); } @@ -24,10 +38,10 @@ fn api_bech32_should_differ_from_bech32m() { fn address_validate_should_work() { assert_eq!( MockApiBech32::new("juno") - .addr_validate(HUMAN_ADDRESS) + .addr_validate(ADDR_JUNO) .unwrap() .as_str(), - HUMAN_ADDRESS + ADDR_JUNO ) } @@ -56,10 +70,10 @@ fn address_validate_invalid_variant() { fn address_canonicalize_humanize_should_work() { let api = MockApiBech32::new("juno"); assert_eq!( - api.addr_humanize(&api.addr_canonicalize(HUMAN_ADDRESS).unwrap()) + api.addr_humanize(&api.addr_canonicalize(ADDR_JUNO).unwrap()) .unwrap() .as_str(), - HUMAN_ADDRESS + ADDR_JUNO ); } @@ -72,6 +86,13 @@ fn address_humanize_prefix_too_long() { .unwrap_err(); } +#[test] +fn address_humanize_canonical_too_long() { + MockApiBech32::new("juno") + .addr_humanize(&CanonicalAddr::from([1; 1024])) + .unwrap_err(); +} + #[test] fn debug_should_not_panic() { assert_debug_does_not_panic(&MockApiBech32::new("juno")); diff --git a/tests/test_addons/test_api/test_bech32m.rs b/tests/test_api/test_bech32m.rs similarity index 70% rename from tests/test_addons/test_api/test_bech32m.rs rename to tests/test_api/test_bech32m.rs index ffb1d48e..6a649e53 100644 --- a/tests/test_addons/test_api/test_bech32m.rs +++ b/tests/test_api/test_bech32m.rs @@ -1,15 +1,21 @@ use super::*; use cosmwasm_std::CanonicalAddr; -use cw_multi_test::addons::{MockApiBech32, MockApiBech32m}; +use cw_multi_test::{IntoBech32, IntoBech32m, MockApiBech32, MockApiBech32m}; -const HUMAN_ADDRESS: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsrvt8pr"; +const ADDR_JUNO: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsrvt8pr"; +const ADDR_DEFAULT: &str = "cosmwasm1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsjvwqar"; #[test] fn new_api_bech32m_should_work() { assert_eq!( MockApiBech32m::new("juno").addr_make("creator").as_str(), - HUMAN_ADDRESS + ADDR_JUNO ); + assert_eq!( + "creator".into_bech32m_with_prefix("juno").as_str(), + ADDR_JUNO + ); + assert_eq!("creator".into_bech32m().as_str(), ADDR_DEFAULT); } #[test] @@ -18,16 +24,24 @@ fn api_bech32m_should_differ_from_bech32() { MockApiBech32m::new("juno").addr_make("sender").as_str(), MockApiBech32::new("juno").addr_make("sender").as_str() ); + assert_ne!( + "sender".into_bech32m_with_prefix("juno").as_str(), + "sender".into_bech32_with_prefix("juno").as_str() + ); + assert_ne!( + "sender".into_bech32m().as_str(), + "sender".into_bech32().as_str() + ); } #[test] fn address_validate_should_work() { assert_eq!( MockApiBech32m::new("juno") - .addr_validate(HUMAN_ADDRESS) + .addr_validate(ADDR_JUNO) .unwrap() .as_str(), - HUMAN_ADDRESS + ADDR_JUNO ) } @@ -56,10 +70,10 @@ fn address_validate_invalid_variant() { fn address_canonicalize_humanize_should_work() { let api = MockApiBech32m::new("juno"); assert_eq!( - api.addr_humanize(&api.addr_canonicalize(HUMAN_ADDRESS).unwrap()) + api.addr_humanize(&api.addr_canonicalize(ADDR_JUNO).unwrap()) .unwrap() .as_str(), - HUMAN_ADDRESS + ADDR_JUNO ); } @@ -72,6 +86,13 @@ fn address_humanize_prefix_too_long() { .unwrap_err(); } +#[test] +fn address_humanize_canonical_too_long() { + MockApiBech32m::new("juno") + .addr_humanize(&CanonicalAddr::from([1; 1024])) + .unwrap_err(); +} + #[test] fn debug_should_not_panic() { assert_debug_does_not_panic(&MockApiBech32m::new("juno")); diff --git a/tests/test_app/test_instantiate2.rs b/tests/test_app/test_instantiate2.rs index cec92ad6..8f82667b 100644 --- a/tests/test_app/test_instantiate2.rs +++ b/tests/test_app/test_instantiate2.rs @@ -2,8 +2,8 @@ use crate::test_contracts::counter; use cosmwasm_std::{instantiate2_address, to_json_binary, Api, Empty, WasmMsg}; -use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; use cw_multi_test::{no_init, AppBuilder, Executor, WasmKeeper}; +use cw_multi_test::{MockAddressGenerator, MockApiBech32}; use cw_utils::parse_instantiate_response_data; #[test] diff --git a/tests/test_app/test_store_code_with_creator.rs b/tests/test_app/test_store_code_with_creator.rs index 9cdc590c..5f70a1e4 100644 --- a/tests/test_app/test_store_code_with_creator.rs +++ b/tests/test_app/test_store_code_with_creator.rs @@ -1,8 +1,8 @@ #![cfg(feature = "cosmwasm_1_2")] use crate::test_contracts::counter; -use cw_multi_test::addons::{MockApiBech32, MockApiBech32m}; use cw_multi_test::{no_init, AppBuilder}; +use cw_multi_test::{MockApiBech32, MockApiBech32m}; #[test] fn store_code_with_custom_creator_address_should_work() { diff --git a/tests/test_app_builder/test_with_api.rs b/tests/test_app_builder/test_with_api.rs index c96184d4..a61861c3 100644 --- a/tests/test_app_builder/test_with_api.rs +++ b/tests/test_app_builder/test_with_api.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{Addr, Api, CanonicalAddr, HexBinary}; -use cw_multi_test::addons::MockApiBech32; +use cw_multi_test::MockApiBech32; use cw_multi_test::{no_init, AppBuilder}; #[test] diff --git a/tests/test_wasm/test_with_addr_gen.rs b/tests/test_wasm/test_with_addr_gen.rs index 619f2e56..ddabf3d9 100644 --- a/tests/test_wasm/test_with_addr_gen.rs +++ b/tests/test_wasm/test_with_addr_gen.rs @@ -1,8 +1,8 @@ use cosmwasm_std::{Addr, Api, Empty, Storage}; -use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; use cw_multi_test::error::AnyResult; use cw_multi_test::{no_init, AddressGenerator, AppBuilder, Executor, WasmKeeper}; +use cw_multi_test::{MockAddressGenerator, MockApiBech32}; use crate::test_contracts; From 0d4a83c3778ef572f56c1f9edceeb39812eb42a8 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 8 Mar 2024 15:53:30 +0100 Subject: [PATCH 123/250] Refactoring. --- src/wasm.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/wasm.rs b/src/wasm.rs index 2117d294..a4466d78 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -27,7 +27,9 @@ const CONTRACTS: Map<&Addr, ContractData> = Map::new("contracts"); /// Wasm module namespace. const NAMESPACE_WASM: &[u8] = b"wasm"; -/// See +/// Contract [address namespace]. +/// +/// [address namespace]: https://github.com/CosmWasm/wasmd/blob/96e2b91144c9a371683555f3c696f882583cc6a2/x/wasm/types/events.go#L59 const CONTRACT_ATTR: &str = "_contract_address"; /// A structure representing a privileged message. @@ -1151,17 +1153,14 @@ where } } -// TODO: replace with code in utils - #[derive(Clone, PartialEq, Message)] struct InstantiateResponse { #[prost(string, tag = "1")] - pub address: ::prost::alloc::string::String, + pub address: String, #[prost(bytes, tag = "2")] - pub data: ::prost::alloc::vec::Vec, + pub data: Vec, } -// TODO: encode helpers in utils fn instantiate_response(data: Option, contact_address: &Addr) -> Binary { let data = data.unwrap_or_default().to_vec(); let init_data = InstantiateResponse { @@ -1177,7 +1176,7 @@ fn instantiate_response(data: Option, contact_address: &Addr) -> Binary #[derive(Clone, PartialEq, Message)] struct ExecuteResponse { #[prost(bytes, tag = "1")] - pub data: ::prost::alloc::vec::Vec, + pub data: Vec, } // empty return if no data present in original From 7298c41f099449ebedbf20cebf138c280049eda8 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 8 Mar 2024 16:15:44 +0100 Subject: [PATCH 124/250] Refactored wasm trait. --- src/app.rs | 14 ++--- src/wasm.rs | 77 +++++++++++++----------- tests/test_app_builder/test_with_api.rs | 14 ++--- tests/test_app_builder/test_with_wasm.rs | 25 ++++---- 4 files changed, 65 insertions(+), 65 deletions(-) diff --git a/src/app.rs b/src/app.rs index ff1925c7..b0bbd440 100644 --- a/src/app.rs +++ b/src/app.rs @@ -425,7 +425,10 @@ where contract_addr: U, msg: &T, ) -> AnyResult { - let msg = to_json_binary(msg)?; + let msg = WasmSudo { + contract_addr: contract_addr.into(), + msg: to_json_binary(msg)?, + }; let Self { block, @@ -435,9 +438,7 @@ where } = self; transactional(&mut *storage, |write_cache, _| { - router - .wasm - .sudo(&*api, contract_addr.into(), write_cache, router, block, msg) + router.wasm.sudo(&*api, write_cache, router, block, msg) }) } @@ -662,10 +663,7 @@ where msg: SudoMsg, ) -> AnyResult { match msg { - SudoMsg::Wasm(msg) => { - self.wasm - .sudo(api, msg.contract_addr, storage, self, block, msg.msg) - } + SudoMsg::Wasm(msg) => self.wasm.sudo(api, storage, self, block, msg), SudoMsg::Bank(msg) => self.bank.sudo(api, storage, self, block, msg), SudoMsg::Staking(msg) => self.staking.sudo(api, storage, self, block, msg), SudoMsg::Custom(_) => unimplemented!(), diff --git a/src/wasm.rs b/src/wasm.rs index 1431b2ba..17cd34af 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -82,16 +82,6 @@ struct CodeData { /// This trait is crucial for testing smart contracts written in languages that compile to WebAssembly, /// which is common in the Cosmos and CosmWasm ecosystems. pub trait Wasm { - /// Handles all `WasmQuery` requests. - fn query( - &self, - api: &dyn Api, - storage: &dyn Storage, - querier: &dyn Querier, - block: &BlockInfo, - request: WasmQuery, - ) -> AnyResult; - /// Handles all `WasmMsg` messages. fn execute( &self, @@ -103,15 +93,24 @@ pub trait Wasm { msg: WasmMsg, ) -> AnyResult; + /// Handles all `WasmQuery` requests. + fn query( + &self, + api: &dyn Api, + storage: &dyn Storage, + querier: &dyn Querier, + block: &BlockInfo, + request: WasmQuery, + ) -> AnyResult; + /// Handles all sudo messages, this is an admin interface and can not be called via `CosmosMsg`. fn sudo( &self, api: &dyn Api, - contract_addr: Addr, storage: &mut dyn Storage, router: &dyn CosmosRouter, block: &BlockInfo, - msg: Binary, + msg: WasmSudo, ) -> AnyResult; /// Stores the contract's code and returns an identifier of the stored contract's code. @@ -169,6 +168,22 @@ where ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { + fn execute( + &self, + api: &dyn Api, + storage: &mut dyn Storage, + router: &dyn CosmosRouter, + block: &BlockInfo, + sender: Addr, + msg: WasmMsg, + ) -> AnyResult { + self.execute_wasm(api, storage, router, block, sender.clone(), msg.clone()) + .context(format!( + "Error executing WasmMsg:\n sender: {}\n {:?}", + sender, msg + )) + } + fn query( &self, api: &dyn Api, @@ -208,36 +223,25 @@ where } } - fn execute( - &self, - api: &dyn Api, - storage: &mut dyn Storage, - router: &dyn CosmosRouter, - block: &BlockInfo, - sender: Addr, - msg: WasmMsg, - ) -> AnyResult { - self.execute_wasm(api, storage, router, block, sender.clone(), msg.clone()) - .context(format!( - "Error executing WasmMsg:\n sender: {}\n {:?}", - sender, msg - )) - } - fn sudo( &self, api: &dyn Api, - contract: Addr, storage: &mut dyn Storage, router: &dyn CosmosRouter, block: &BlockInfo, - msg: Binary, + msg: WasmSudo, ) -> AnyResult { - let custom_event = Event::new("sudo").add_attribute(CONTRACT_ATTR, &contract); - - let res = self.call_sudo(contract.clone(), api, storage, router, block, msg.to_vec())?; - let (res, msgs) = self.build_app_response(&contract, custom_event, res); - self.process_response(api, router, storage, block, contract, res, msgs) + let custom_event = Event::new("sudo").add_attribute(CONTRACT_ATTR, &msg.contract_addr); + let res = self.call_sudo( + msg.contract_addr.clone(), + api, + storage, + router, + block, + msg.msg.to_vec(), + )?; + let (res, msgs) = self.build_app_response(&msg.contract_addr, custom_event, res); + self.process_response(api, router, storage, block, msg.contract_addr, res, msgs) } /// Stores the contract's code in the in-memory lookup table. @@ -445,6 +449,7 @@ where /// use cosmwasm_std::{Addr, Api, Storage}; /// use cw_multi_test::{AddressGenerator, AppBuilder, no_init, WasmKeeper}; /// use cw_multi_test::error::AnyResult; + /// # use cosmwasm_std::testing::MockApi; /// /// struct CustomAddressGenerator; /// @@ -457,7 +462,7 @@ where /// instance_id: u64, /// ) -> AnyResult { /// // here implement your address generation logic - /// # Ok(Addr::unchecked("test_address")) + /// # Ok(MockApi::default().addr_make("test_address")) /// } /// } /// diff --git a/tests/test_app_builder/test_with_api.rs b/tests/test_app_builder/test_with_api.rs index c96184d4..5fd27bec 100644 --- a/tests/test_app_builder/test_with_api.rs +++ b/tests/test_app_builder/test_with_api.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Addr, Api, CanonicalAddr, HexBinary}; +use cosmwasm_std::{Api, CanonicalAddr, HexBinary}; use cw_multi_test::addons::MockApiBech32; use cw_multi_test::{no_init, AppBuilder}; @@ -15,10 +15,7 @@ fn building_app_with_custom_api_should_work() { .build(no_init); // check address validation function - assert_eq!( - app.api().addr_validate(human).unwrap(), - Addr::unchecked(human) - ); + assert_eq!(app.api().addr_validate(human).unwrap().as_str(), human); // check if address can be canonicalized assert_eq!( @@ -30,10 +27,11 @@ fn building_app_with_custom_api_should_work() { assert_eq!( app.api() .addr_humanize(&app.api().addr_canonicalize(human).unwrap()) - .unwrap(), - Addr::unchecked(human) + .unwrap() + .as_str(), + human ); // check extension function for creating Bech32 encoded addresses - assert_eq!(app.api().addr_make("creator"), Addr::unchecked(human)); + assert_eq!(app.api().addr_make("creator").as_str(), human); } diff --git a/tests/test_app_builder/test_with_wasm.rs b/tests/test_app_builder/test_with_wasm.rs index 364a32bd..8424a1b7 100644 --- a/tests/test_app_builder/test_with_wasm.rs +++ b/tests/test_app_builder/test_with_wasm.rs @@ -25,17 +25,6 @@ static WASM_RAW: Lazy> = Lazy::new(|| vec![(vec![154u8], vec![155u8] type MyWasmKeeper = MyKeeper; impl Wasm for MyWasmKeeper { - fn query( - &self, - _api: &dyn Api, - _storage: &dyn Storage, - _querier: &dyn Querier, - _block: &BlockInfo, - _request: WasmQuery, - ) -> AnyResult { - bail!(self.2); - } - fn execute( &self, _api: &dyn Api, @@ -48,14 +37,24 @@ impl Wasm for MyWasmKeeper { bail!(self.1); } + fn query( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + _request: WasmQuery, + ) -> AnyResult { + bail!(self.2); + } + fn sudo( &self, _api: &dyn Api, - _contract_addr: Addr, _storage: &mut dyn Storage, _router: &dyn CosmosRouter, _block: &BlockInfo, - _msg: Binary, + _msg: WasmSudo, ) -> AnyResult { bail!(self.3); } From c884f6e036efbd84ef7b794bac80da07e8d1b5c5 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 8 Mar 2024 16:18:49 +0100 Subject: [PATCH 125/250] Refactored WasmSudo struct. --- src/app.rs | 2 +- src/tests/test_app.rs | 2 +- src/wasm.rs | 6 +++--- tests/test_app_builder/test_with_wasm.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app.rs b/src/app.rs index b0bbd440..0083c69a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -427,7 +427,7 @@ where ) -> AnyResult { let msg = WasmSudo { contract_addr: contract_addr.into(), - msg: to_json_binary(msg)?, + message: to_json_binary(msg)?, }; let Self { diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 95a0c82c..1da7a99e 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -564,7 +564,7 @@ fn sudo_works() { let msg = payout::SudoMsg { set_count: 49 }; let sudo_msg = WasmSudo { contract_addr: payout_addr.clone(), - msg: to_json_binary(&msg).unwrap(), + message: to_json_binary(&msg).unwrap(), }; app.sudo(sudo_msg.into()).unwrap(); diff --git a/src/wasm.rs b/src/wasm.rs index 17cd34af..32f62053 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -39,7 +39,7 @@ pub struct WasmSudo { /// Address of a contract the privileged action will be sent to. pub contract_addr: Addr, /// Message representing privileged action to be executed by contract `sudo` entry-point. - pub msg: Binary, + pub message: Binary, } impl WasmSudo { @@ -47,7 +47,7 @@ impl WasmSudo { pub fn new(contract_addr: &Addr, msg: &T) -> StdResult { Ok(WasmSudo { contract_addr: contract_addr.clone(), - msg: to_json_binary(msg)?, + message: to_json_binary(msg)?, }) } } @@ -238,7 +238,7 @@ where storage, router, block, - msg.msg.to_vec(), + msg.message.to_vec(), )?; let (res, msgs) = self.build_app_response(&msg.contract_addr, custom_event, res); self.process_response(api, router, storage, block, msg.contract_addr, res, msgs) diff --git a/tests/test_app_builder/test_with_wasm.rs b/tests/test_app_builder/test_with_wasm.rs index 8424a1b7..9708d796 100644 --- a/tests/test_app_builder/test_with_wasm.rs +++ b/tests/test_app_builder/test_with_wasm.rs @@ -139,7 +139,7 @@ fn building_app_with_custom_wasm_should_work() { app.sudo( WasmSudo { contract_addr, - msg: Default::default() + message: Default::default() } .into() ) From e3132f1fec115fd5710af114a5229acbf41b0bd7 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 8 Mar 2024 18:32:59 +0100 Subject: [PATCH 126/250] Updates. --- src/addresses.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/addresses.rs b/src/addresses.rs index e8d76cea..2747f1d6 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -7,7 +7,8 @@ use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage}; use sha2::digest::Update; use sha2::{Digest, Sha256}; -/// Defines conversions to [Addr]. +/// Defines conversions to [Addr], this conversion is format agnostic +/// and is aligned with the format generated by `cosmwasm-std::testing::MockApi`. pub trait IntoAddr { /// Converts into [Addr]. fn into_addr(self) -> Addr; From f312483475516242d86e3cef81f89246aa27fe3b Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 8 Mar 2024 18:48:39 +0100 Subject: [PATCH 127/250] Applied changes after review. --- src/addresses.rs | 7 +++++-- tests/test_api/test_bech32.rs | 24 ++++++++++++++++-------- tests/test_api/test_bech32m.rs | 24 ++++++++++++++++-------- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/addresses.rs b/src/addresses.rs index 04263b3d..b934abf2 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -8,7 +8,10 @@ use sha2::{Digest, Sha256}; const DEFAULT_PREFIX: &str = "cosmwasm"; -/// Defines conversions to [Addr]. +/// Defines conversions to [Addr], this conversion is format agnostic +/// and should be aligned with the format generated by [MockApi]. +/// +/// [MockApi]: https://github.com/CosmWasm/cosmwasm/blob/9a239838baba50f4f47230da306f39a8bb4ea697/packages/std/src/testing/mock.rs#L251-L257 pub trait IntoAddr { /// Converts into [Addr]. fn into_addr(self) -> Addr; @@ -177,7 +180,7 @@ impl AddressGenerator for SimpleAddressGenerator {} /// Address generator that mimics the [wasmd](https://github.com/CosmWasm/wasmd) behavior. /// -/// [crate::addons::MockAddressGenerator] implements [AddressGenerator] trait in terms of +/// [MockAddressGenerator] implements [AddressGenerator] trait in terms of /// [`contract_address`](AddressGenerator::contract_address) and /// [`predictable_contract_address`](AddressGenerator::predictable_contract_address) functions: /// - `contract_address` generates non-predictable addresses for contracts, diff --git a/tests/test_api/test_bech32.rs b/tests/test_api/test_bech32.rs index 8bb74499..35e86234 100644 --- a/tests/test_api/test_bech32.rs +++ b/tests/test_api/test_bech32.rs @@ -79,18 +79,26 @@ fn address_canonicalize_humanize_should_work() { #[test] fn address_humanize_prefix_too_long() { - MockApiBech32::new( - "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", - ) - .addr_humanize(&CanonicalAddr::from([1, 2, 3, 4, 5])) - .unwrap_err(); + assert_eq!( + "Generic error: hrp is too long, found 85 characters, must be <= 126", + MockApiBech32::new( + "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", + ) + .addr_humanize(&CanonicalAddr::from([1, 2, 3, 4, 5])) + .unwrap_err() + .to_string() + ); } #[test] fn address_humanize_canonical_too_long() { - MockApiBech32::new("juno") - .addr_humanize(&CanonicalAddr::from([1; 1024])) - .unwrap_err(); + assert_eq!( + "Generic error: Invalid canonical address", + MockApiBech32::new("juno") + .addr_humanize(&CanonicalAddr::from([1; 1024])) + .unwrap_err() + .to_string() + ); } #[test] diff --git a/tests/test_api/test_bech32m.rs b/tests/test_api/test_bech32m.rs index 6a649e53..61af0177 100644 --- a/tests/test_api/test_bech32m.rs +++ b/tests/test_api/test_bech32m.rs @@ -79,18 +79,26 @@ fn address_canonicalize_humanize_should_work() { #[test] fn address_humanize_prefix_too_long() { - MockApiBech32m::new( - "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", - ) - .addr_humanize(&CanonicalAddr::from([1, 2, 3, 4, 5])) - .unwrap_err(); + assert_eq!( + "Generic error: hrp is too long, found 85 characters, must be <= 126", + MockApiBech32m::new( + "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", + ) + .addr_humanize(&CanonicalAddr::from([1, 2, 3, 4, 5])) + .unwrap_err() + .to_string() + ); } #[test] fn address_humanize_canonical_too_long() { - MockApiBech32m::new("juno") - .addr_humanize(&CanonicalAddr::from([1; 1024])) - .unwrap_err(); + assert_eq!( + "Generic error: Invalid canonical address", + MockApiBech32m::new("juno") + .addr_humanize(&CanonicalAddr::from([1; 1024])) + .unwrap_err() + .to_string() + ); } #[test] From e2e3ae3fc7927f753dca51092d54cc58adb22dd7 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 11 Mar 2024 09:46:43 +0100 Subject: [PATCH 128/250] Upgraded dependencies. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2503e167..ac90d618 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ derivative = "2.2.0" itertools = "0.12.1" prost = "0.12.3" schemars = "0.8.16" -serde = "1.0.196" +serde = "1.0.197" sha2 = "0.10.8" thiserror = "1.0.57" From ba613809e50669a766c27e8464ed31b5bf1f58df Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 11 Mar 2024 10:06:58 +0100 Subject: [PATCH 129/250] Bumped version. --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f314678..32f288fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -250,7 +250,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "2.0.0-rc.0" +version = "2.0.0-rc.1" dependencies = [ "anyhow", "bech32 0.11.0", diff --git a/Cargo.toml b/Cargo.toml index ac90d618..dffbe43d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "2.0.0-rc.0" +version = "2.0.0-rc.1" authors = ["Ethan Frey "] description = "Testing tools for multi-contract interactions" repository = "https://github.com/CosmWasm/cw-multi-test" From 1d4d2e574e402b27921bdb90237b021a841df461 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 11 Mar 2024 10:17:47 +0100 Subject: [PATCH 130/250] Prepared version 1.0.0-rc.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac06bd85..ce270385 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -251,7 +251,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "0.20.0" +version = "1.0.0-rc.0" dependencies = [ "anyhow", "bech32 0.11.0", diff --git a/Cargo.toml b/Cargo.toml index 3d0304e8..9c0ed699 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "0.20.0" +version = "1.0.0-rc.0" authors = ["Ethan Frey "] edition = "2021" description = "Testing tools for multi-contract interactions" From d061e2b9ac466a5452421732733a1436c67e3170 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 11 Mar 2024 10:28:54 +0100 Subject: [PATCH 131/250] Bumped version. --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ce270385..f07fafcb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -251,7 +251,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "1.0.0-rc.0" +version = "1.0.0-rc.1" dependencies = [ "anyhow", "bech32 0.11.0", diff --git a/Cargo.toml b/Cargo.toml index 9c0ed699..ca06df48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "1.0.0-rc.0" +version = "1.0.0-rc.1" authors = ["Ethan Frey "] edition = "2021" description = "Testing tools for multi-contract interactions" From d95f7a3aa7b85023438792d4635a0b206a8135ee Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Tue, 12 Mar 2024 09:47:32 +0100 Subject: [PATCH 132/250] Remove `Addr::unchecked` where possible (#141) * Refactoring. * Updates. * Updates. * Updates. * Updates. * Updates. * Updates. * Replaced Addr::unchecked where possible. * Reverted address for stajing module. * Fixed clippy warnings. --- src/addresses.rs | 8 +- src/bank.rs | 16 +- src/staking.rs | 54 +++--- src/tests/test_app.rs | 182 ++++++++++-------- src/tests/test_custom_handler.rs | 4 +- src/wasm.rs | 131 +++++++------ tests/test_app_builder/test_with_bank.rs | 6 +- .../test_with_distribution.rs | 6 +- tests/test_app_builder/test_with_gov.rs | 4 +- tests/test_app_builder/test_with_ibc.rs | 4 +- tests/test_app_builder/test_with_staking.rs | 6 +- tests/test_app_builder/test_with_stargate.rs | 8 +- tests/test_app_builder/test_with_storage.rs | 5 +- tests/test_app_builder/test_with_wasm.rs | 4 +- tests/test_module/test_accepting_module.rs | 4 +- tests/test_module/test_failing_module.rs | 6 +- tests/test_wasm/test_with_addr_gen.rs | 10 +- tests/test_wasm/test_with_checksum_gen.rs | 4 +- 18 files changed, 246 insertions(+), 216 deletions(-) diff --git a/src/addresses.rs b/src/addresses.rs index b934abf2..03411e7e 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -96,16 +96,16 @@ pub trait AddressGenerator { /// let my_address_generator = MyAddressGenerator{}; /// /// let addr = my_address_generator.contract_address(&api, &mut storage, 100, 0).unwrap(); - /// assert_eq!(addr.to_string(),"contract0"); + /// assert_eq!(addr.as_str(), "contract0"); /// /// let addr = my_address_generator.contract_address(&api, &mut storage, 100, 1).unwrap(); - /// assert_eq!(addr.to_string(),"contract1"); + /// assert_eq!(addr.as_str(), "contract1"); /// /// let addr = my_address_generator.contract_address(&api, &mut storage, 200, 5).unwrap(); - /// assert_eq!(addr.to_string(),"contract5"); + /// assert_eq!(addr.as_str(), "contract5"); /// /// let addr = my_address_generator.contract_address(&api, &mut storage, 200, 6).unwrap(); - /// assert_eq!(addr.to_string(),"contract6"); + /// assert_eq!(addr.as_str(), "contract6"); /// ``` fn contract_address( &self, diff --git a/src/bank.rs b/src/bank.rs index 860f12ac..5b94259a 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -319,8 +319,8 @@ mod test { let querier: MockQuerier = MockQuerier::new(&[]); let router = MockRouter::default(); - let owner = Addr::unchecked("owner"); - let rcpt = Addr::unchecked("receiver"); + let owner = api.addr_make("owner"); + let rcpt = api.addr_make("receiver"); let init_funds = vec![coin(100, "eth"), coin(20, "btc")]; let norm = vec![coin(20, "btc"), coin(100, "eth")]; @@ -419,8 +419,8 @@ mod test { let block = mock_env().block; let router = MockRouter::default(); - let owner = Addr::unchecked("owner"); - let rcpt = Addr::unchecked("receiver"); + let owner = api.addr_make("owner"); + let rcpt = api.addr_make("receiver"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let rcpt_funds = vec![coin(5, "btc")]; @@ -472,8 +472,8 @@ mod test { let block = mock_env().block; let router = MockRouter::default(); - let owner = Addr::unchecked("owner"); - let rcpt = Addr::unchecked("recipient"); + let owner = api.addr_make("owner"); + let rcpt = api.addr_make("recipient"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; // set money @@ -583,8 +583,8 @@ mod test { let block = mock_env().block; let router = MockRouter::default(); - let owner = Addr::unchecked("owner"); - let rcpt = Addr::unchecked("recipient"); + let owner = api.addr_make("owner"); + let rcpt = api.addr_make("recipient"); let init_funds = vec![coin(5000, "atom"), coin(100, "eth")]; // set money diff --git a/src/staking.rs b/src/staking.rs index a78d2999..894fc84a 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1170,12 +1170,12 @@ mod test { let stake = StakeKeeper::new(); let block = mock_env().block; - let delegator = Addr::unchecked("delegator"); - let validator = api.addr_validate("testvaloper1").unwrap(); + let delegator = api.addr_make("delegator"); + let validator = api.addr_make("testvaloper1"); // add validator let valoper1 = Validator { - address: "testvaloper1".to_string(), + address: validator.to_string(), commission: Decimal::percent(10), max_commission: Decimal::percent(20), max_change_rate: Decimal::percent(1), @@ -1205,7 +1205,7 @@ mod test { &router, &block, StakingSudo::Slash { - validator: "testvaloper1".to_string(), + validator: validator.to_string(), percentage: Decimal::percent(50), }, ) @@ -1230,7 +1230,7 @@ mod test { &router, &block, StakingSudo::Slash { - validator: "testvaloper1".to_string(), + validator: validator.to_string(), percentage: Decimal::percent(100), }, ) @@ -1250,7 +1250,7 @@ mod test { setup_test_env(Decimal::percent(10), Decimal::percent(10)); let stake = &router.staking; let distr = &router.distribution; - let delegator = Addr::unchecked("delegator"); + let delegator = api.addr_make("delegator"); let mut staking_storage = prefixed(&mut store, NAMESPACE_STAKING); // stake 200 tokens @@ -1313,8 +1313,8 @@ mod test { let stake = &router.staking; let distr = &router.distribution; let bank = &router.bank; - let delegator1 = Addr::unchecked("delegator1"); - let delegator2 = Addr::unchecked("delegator2"); + let delegator1 = api.addr_make("delegator1"); + let delegator2 = api.addr_make("delegator2"); let mut staking_storage = prefixed(&mut store, NAMESPACE_STAKING); @@ -1559,8 +1559,8 @@ mod test { let (mut test_env, validator1) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator1 = Addr::unchecked("delegator1"); - let reward_receiver = Addr::unchecked("rewardreceiver"); + let delegator1 = test_env.api.addr_make("delegator1"); + let reward_receiver = test_env.api.addr_make("rewardreceiver"); // fund delegator1 account test_env @@ -1570,7 +1570,7 @@ mod test { .unwrap(); // add second validator - let validator2 = Addr::unchecked("validator2"); + let validator2 = test_env.api.addr_make("validator2"); test_env .router .staking @@ -1697,8 +1697,8 @@ mod test { let (mut test_env, validator) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator = Addr::unchecked("delegator"); - let reward_receiver = Addr::unchecked("rewardreceiver"); + let delegator = test_env.api.addr_make("delegator"); + let reward_receiver = test_env.api.addr_make("rewardreceiver"); test_env .router @@ -1777,7 +1777,7 @@ mod test { let (mut test_env, validator1) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator1 = Addr::unchecked("delegator1"); + let delegator1 = test_env.api.addr_make("delegator1"); // fund delegator1 account test_env @@ -1811,7 +1811,7 @@ mod test { assert_eq!(e.to_string(), "invalid shares amount"); // add second validator - let validator2 = Addr::unchecked("validator2"); + let validator2 = test_env.api.addr_make("validator2"); test_env .router .staking @@ -1862,7 +1862,7 @@ mod test { let (mut test_env, validator) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator1 = Addr::unchecked("delegator1"); + let delegator1 = test_env.api.addr_make("delegator1"); // fund delegator1 account test_env @@ -1893,7 +1893,7 @@ mod test { let (mut test_env, _) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator1 = Addr::unchecked("delegator1"); + let delegator1 = test_env.api.addr_make("delegator1"); // fund delegator1 account test_env @@ -1925,8 +1925,8 @@ mod test { let (mut test_env, _) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator = Addr::unchecked("delegator1"); - let validator = "testvaloper2"; + let delegator = test_env.api.addr_make("delegator1"); + let validator = test_env.api.addr_make("testvaloper2"); // init balances test_env @@ -1965,7 +1965,7 @@ mod test { let (mut test_env, validator) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator = Addr::unchecked("delegator1"); + let delegator = test_env.api.addr_make("delegator1"); // delegate 0 let err = execute_stake( @@ -1997,8 +1997,8 @@ mod test { // run all staking queries let (mut test_env, validator1) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator1 = Addr::unchecked("delegator1"); - let delegator2 = Addr::unchecked("delegator2"); + let delegator1 = test_env.api.addr_make("delegator1"); + let delegator2 = test_env.api.addr_make("delegator2"); // init balances test_env @@ -2156,8 +2156,8 @@ mod test { // run all staking queries let (mut test_env, validator) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator1 = Addr::unchecked("delegator1"); - let delegator2 = Addr::unchecked("delegator2"); + let delegator1 = test_env.api.addr_make("delegator1"); + let delegator2 = test_env.api.addr_make("delegator2"); // init balances test_env @@ -2285,7 +2285,7 @@ mod test { fn partial_unbonding_reduces_stake() { let (mut test_env, validator) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator = Addr::unchecked("delegator1"); + let delegator = test_env.api.addr_make("delegator1"); // init balance test_env @@ -2409,7 +2409,7 @@ mod test { // run all staking queries let (mut test_env, validator) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); - let delegator = Addr::unchecked("delegator"); + let delegator = test_env.api.addr_make("delegator"); // init balance test_env @@ -2498,7 +2498,7 @@ mod test { fn rewards_initial_wait() { let (mut test_env, validator) = TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::zero())); - let delegator = Addr::unchecked("delegator"); + let delegator = test_env.api.addr_make("delegator"); // init balance test_env diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 1da7a99e..e94e05b5 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -4,11 +4,11 @@ use crate::test_helpers::echo::EXECUTE_REPLY_BASE_ID; use crate::test_helpers::{caller, echo, error, hackatom, payout, reflect, CustomHelperMsg}; use crate::transactions::{transactional, StorageTransaction}; use crate::wasm::ContractData; -use crate::AppBuilder; use crate::{ custom_app, next_block, no_init, App, AppResponse, Bank, CosmosRouter, Distribution, Executor, Module, Router, Staking, Wasm, WasmSudo, }; +use crate::{AppBuilder, IntoAddr}; use cosmwasm_std::testing::{mock_env, MockQuerier}; use cosmwasm_std::{ coin, coins, from_json, to_json_binary, Addr, AllBalanceResponse, Api, Attribute, BankMsg, @@ -105,8 +105,8 @@ fn update_block() { #[test] fn multi_level_bank_cache() { // set personal balance - let owner = Addr::unchecked("owner"); - let rcpt = Addr::unchecked("recipient"); + let owner = "owner".into_addr(); + let recipient = "recipient".into_addr(); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let mut app = App::new(|router, _, storage| { @@ -119,7 +119,7 @@ fn multi_level_bank_cache() { // cache 1 - send some tokens let mut cache = StorageTransaction::new(app.storage()); let msg = BankMsg::Send { - to_address: rcpt.clone().into(), + to_address: recipient.clone().into(), amount: coins(25, "eth"), }; app.router() @@ -133,15 +133,15 @@ fn multi_level_bank_cache() { .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, &recipient); assert_eq!(coins(25, "eth"), cached_rcpt); - let router_rcpt = query_app(&app, &rcpt); + let router_rcpt = query_app(&app, &recipient); assert_eq!(router_rcpt, vec![]); // now, second level cache transactional(&mut cache, |cache2, read| { let msg = BankMsg::Send { - to_address: rcpt.clone().into(), + to_address: recipient.clone().into(), amount: coins(12, "eth"), }; app.router() @@ -149,9 +149,9 @@ fn multi_level_bank_cache() { .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, &recipient); 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, &recipient); assert_eq!(coins(37, "eth"), cached2_rcpt); Ok(()) }) @@ -160,7 +160,7 @@ fn multi_level_bank_cache() { // apply first to router cache.prepare().commit(app.storage_mut()); - let committed = query_app(&app, &rcpt); + let committed = query_app(&app, &recipient); assert_eq!(coins(37, "eth"), committed); } @@ -187,8 +187,8 @@ fn duplicate_contract_code() { #[test] fn send_tokens() { - let owner = Addr::unchecked("owner"); - let rcpt = Addr::unchecked("receiver"); + let owner = "owner".into_addr(); + let recipient = "receiver".into_addr(); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let rcpt_funds = vec![coin(5, "btc")]; @@ -200,29 +200,29 @@ fn send_tokens() { .unwrap(); router .bank - .init_balance(storage, &rcpt, rcpt_funds) + .init_balance(storage, &recipient, rcpt_funds) .unwrap(); }); // send both tokens let to_send = vec![coin(30, "eth"), coin(5, "btc")]; let msg: CosmosMsg = BankMsg::Send { - to_address: rcpt.clone().into(), + to_address: recipient.clone().into(), amount: to_send, } .into(); app.execute(owner.clone(), msg.clone()).unwrap(); let rich = get_balance(&app, &owner); assert_eq!(vec![coin(15, "btc"), coin(70, "eth")], rich); - let poor = get_balance(&app, &rcpt); + let poor = get_balance(&app, &recipient); assert_eq!(vec![coin(10, "btc"), coin(30, "eth")], poor); // can send from other account (but funds will be deducted from sender) - app.execute(rcpt.clone(), msg).unwrap(); + app.execute(recipient.clone(), msg).unwrap(); // cannot send too much let msg = BankMsg::Send { - to_address: rcpt.into(), + to_address: recipient.into(), amount: coins(20, "btc"), } .into(); @@ -235,7 +235,7 @@ fn send_tokens() { #[test] fn simple_contract() { // set personal balance - let owner = Addr::unchecked("owner"); + let owner = "owner".into_addr(); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let mut app = App::new(|router, _, storage| { @@ -282,7 +282,7 @@ fn simple_contract() { assert_eq!(funds, coins(23, "eth")); // create empty account - let random = Addr::unchecked("random"); + let random = app.api().addr_make("random"); let funds = get_balance(&app, &random); assert_eq!(funds, vec![]); @@ -306,7 +306,7 @@ fn simple_contract() { // then the transfer event let expected_transfer = Event::new("transfer") - .add_attribute("recipient", "random") + .add_attribute("recipient", random.to_string()) .add_attribute("sender", &contract_addr) .add_attribute("amount", "5eth"); assert_eq!(&expected_transfer, &res.events[2]); @@ -322,7 +322,7 @@ fn simple_contract() { #[test] fn reflect_success() { // set personal balance - let owner = Addr::unchecked("owner"); + let owner = "owner".into_addr(); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let mut app = custom_app::(|router, _, storage| { @@ -376,7 +376,12 @@ fn reflect_success() { messages: vec![msg], }; let res = app - .execute_contract(Addr::unchecked("random"), reflect_addr.clone(), &msgs, &[]) + .execute_contract( + app.api().addr_make("random"), + reflect_addr.clone(), + &msgs, + &[], + ) .unwrap(); // ensure the attributes were relayed from the sub-message @@ -428,7 +433,7 @@ fn reflect_success() { #[test] fn reflect_error() { // set personal balance - let owner = Addr::unchecked("owner"); + let owner = "owner".into_addr(); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let mut app = custom_app::(|router, _, storage| { @@ -455,7 +460,7 @@ fn reflect_error() { // reflect has 40 eth let funds = get_balance(&app, &reflect_addr); assert_eq!(funds, coins(40, "eth")); - let random = Addr::unchecked("random"); + let random = app.api().addr_make("random"); // sending 7 eth works let msg = SubMsg::new(BankMsg::Send { @@ -523,7 +528,7 @@ fn reflect_error() { #[test] fn sudo_works() { - let owner = Addr::unchecked("owner"); + let owner = "owner".into_addr(); let init_funds = vec![coin(100, "eth")]; let mut app = App::new(|router, _, storage| { @@ -578,8 +583,8 @@ fn sudo_works() { #[test] fn reflect_sub_message_reply_works() { // set personal balance - let owner = Addr::unchecked("owner"); - let random = Addr::unchecked("random"); + let owner = "owner".into_addr(); + let random = "random".into_addr(); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let mut app = custom_app::(|router, _, storage| { @@ -673,12 +678,13 @@ fn send_update_admin_works() { // update admin succeeds if admin // update admin fails if not (new) admin // check admin set properly - let owner = Addr::unchecked("owner"); - let owner2 = Addr::unchecked("owner2"); - let beneficiary = Addr::unchecked("beneficiary"); let mut app = App::default(); + let owner = app.api().addr_make("owner"); + let owner2 = app.api().addr_make("owner2"); + let beneficiary = app.api().addr_make("beneficiary"); + // create a hackatom contract with some funds let code_id = app.store_code(hackatom::contract()); @@ -737,8 +743,8 @@ fn sent_wasm_migration_works() { // migrate fails if not admin // migrate succeeds if admin // check beneficiary updated - let owner = Addr::unchecked("owner"); - let beneficiary = Addr::unchecked("beneficiary"); + let owner = "owner".into_addr(); + let beneficiary = "beneficiary".into_addr(); let init_funds = coins(30, "btc"); let mut app = App::new(|router, _, storage| { @@ -775,7 +781,7 @@ fn sent_wasm_migration_works() { assert_eq!(state.beneficiary, beneficiary); // migrate fails if not admin - let random = Addr::unchecked("random"); + let random = app.api().addr_make("random"); let migrate_msg = hackatom::MigrateMsg { new_guy: random.to_string(), }; @@ -805,8 +811,8 @@ fn sent_funds_properly_visible_on_execution() { // additional 20btc. Then beneficiary balance is checked - expected 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 owner = Addr::unchecked("owner"); - let beneficiary = Addr::unchecked("beneficiary"); + let owner = "owner".into_addr(); + let beneficiary = "beneficiary".into_addr(); let init_funds = coins(30, "btc"); let mut app = App::new(|router, _, storage| { @@ -906,6 +912,17 @@ mod custom_handler { Ok(AppResponse::default()) } + fn query( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + _request: Self::QueryT, + ) -> AnyResult { + bail!("query not implemented for CustomHandler") + } + fn sudo( &self, _api: &dyn Api, @@ -920,17 +937,6 @@ mod custom_handler { { bail!("sudo not implemented for CustomHandler") } - - fn query( - &self, - _api: &dyn Api, - _storage: &dyn Storage, - _querier: &dyn Querier, - _block: &BlockInfo, - _request: Self::QueryT, - ) -> AnyResult { - bail!("query not implemented for CustomHandler") - } } impl CustomHandler { @@ -976,7 +982,7 @@ mod custom_handler { lucky_winner: winner.clone(), runner_up: second.clone(), }); - app.execute(Addr::unchecked("anyone"), msg).unwrap(); + app.execute(app.api().addr_make("anyone"), msg).unwrap(); // see if coins were properly added let big_win = app.wrap().query_balance(&winner, denom).unwrap(); @@ -1033,7 +1039,7 @@ mod reply_data_overwrite { fn no_submsg() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1060,7 +1066,7 @@ mod reply_data_overwrite { fn single_submsg() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1093,7 +1099,7 @@ mod reply_data_overwrite { fn single_submsg_no_reply() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1121,7 +1127,7 @@ mod reply_data_overwrite { fn single_no_submsg_data() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1149,7 +1155,7 @@ mod reply_data_overwrite { fn single_no_top_level_data() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1180,7 +1186,7 @@ mod reply_data_overwrite { #[test] fn single_submsg_reply_returns_none() { // set personal balance - let owner = Addr::unchecked("owner"); + let owner = "owner".into_addr(); let init_funds = coins(100, "tgd"); let mut app = custom_app::(|router, _, storage| { @@ -1204,8 +1210,7 @@ mod reply_data_overwrite { .instantiate_contract(echo_id, owner.clone(), &Empty {}, &[], "Echo", None) .unwrap(); - // reflect will call echo - // echo will set the data + // reflect will call echo and then echo will set the data // top-level app will not display the data let echo_msg = echo::Message:: { data: Some("my echo".into()), @@ -1237,7 +1242,7 @@ mod reply_data_overwrite { fn multiple_submsg() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1280,7 +1285,7 @@ mod reply_data_overwrite { fn multiple_submsg_no_reply() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1313,7 +1318,7 @@ mod reply_data_overwrite { fn multiple_submsg_mixed() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1351,7 +1356,7 @@ mod reply_data_overwrite { fn nested_submsg() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1404,7 +1409,7 @@ mod response_validation { fn empty_attribute_key() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1435,7 +1440,7 @@ mod response_validation { fn empty_attribute_value() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1466,7 +1471,7 @@ mod response_validation { fn empty_event_attribute_key() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1496,7 +1501,7 @@ mod response_validation { fn empty_event_attribute_value() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1526,7 +1531,7 @@ mod response_validation { fn too_short_event_type() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1558,12 +1563,14 @@ mod contract_instantiation { fn instantiate2_works() { use super::*; - // prepare application and actors + // prepare the application let mut app = App::default(); - let sender = Addr::unchecked("sender"); + + let sender_addr = app.api().addr_make("sender"); + let creator_addr = app.api().addr_make("creator"); // store contract's code - let code_id = app.store_code_with_creator(Addr::unchecked("creator"), echo::contract()); + let code_id = app.store_code_with_creator(creator_addr, echo::contract()); // initialize the contract let init_msg = to_json_binary(&Empty {}).unwrap(); @@ -1576,7 +1583,7 @@ mod contract_instantiation { label: "label".into(), salt: salt.clone().into(), }; - let res = app.execute(sender, msg.into()).unwrap(); + let res = app.execute(sender_addr.clone(), msg.into()).unwrap(); // assert a proper instantiate result let parsed = parse_instantiate_response_data(res.data.unwrap().as_slice()).unwrap(); @@ -1585,12 +1592,12 @@ mod contract_instantiation { // assert contract's address is exactly the predicted one, // in default address generator, this is like `contract` + salt in hex assert_eq!( - parsed.contract_address, + parsed.contract_address.as_str(), format!( "contract{}{}", - app.api().addr_canonicalize("sender").unwrap(), + app.api().addr_canonicalize(sender_addr.as_str()).unwrap(), salt.to_hex() - ), + ) ); } } @@ -1602,10 +1609,11 @@ mod wasm_queries { fn query_existing_code_info() { use super::*; let mut app = App::default(); - let code_id = app.store_code_with_creator(Addr::unchecked("creator"), echo::contract()); + let creator_addr = app.api().addr_make("creator"); + let code_id = app.store_code_with_creator(creator_addr.clone(), echo::contract()); let code_info_response = app.wrap().query_wasm_code_info(code_id).unwrap(); assert_eq!(code_id, code_info_response.code_id); - assert_eq!("creator", code_info_response.creator); + assert_eq!(creator_addr.as_str(), code_info_response.creator.as_str()); assert!(!code_info_response.checksum.is_empty()); } @@ -1675,7 +1683,7 @@ mod protobuf_wrapped_data { #[test] fn instantiate_wrapped_properly() { // set personal balance - let owner = Addr::unchecked("owner"); + let owner = "owner".into_addr(); let init_funds = vec![coin(20, "btc")]; let mut app = custom_app::(|router, _, storage| { @@ -1712,9 +1720,10 @@ mod protobuf_wrapped_data { #[test] fn instantiate_with_data_works() { - let owner = Addr::unchecked("owner"); let mut app = BasicApp::new(no_init); + let owner = app.api().addr_make("owner"); + // set up echo contract let code_id = app.store_code(echo::contract()); @@ -1741,9 +1750,10 @@ mod protobuf_wrapped_data { #[test] fn instantiate_with_reply_works() { - let owner = Addr::unchecked("owner"); let mut app = BasicApp::new(no_init); + let owner = app.api().addr_make("owner"); + // set up echo contract let code_id = app.store_code(echo::contract()); @@ -1793,9 +1803,10 @@ mod protobuf_wrapped_data { #[test] fn execute_wrapped_properly() { - let owner = Addr::unchecked("owner"); let mut app = BasicApp::new(no_init); + let owner = app.api().addr_make("owner"); + // set up reflect contract let code_id = app.store_code(echo::contract()); @@ -1819,9 +1830,10 @@ mod errors { #[test] fn simple_instantiation() { - let owner = Addr::unchecked("owner"); let mut app = App::default(); + let owner = app.api().addr_make("owner"); + // set up contract let code_id = app.store_code(error::contract(false)); @@ -1845,9 +1857,10 @@ mod errors { #[test] fn simple_call() { - let owner = Addr::unchecked("owner"); let mut app = App::default(); + let owner = app.api().addr_make("owner"); + // set up contract let code_id = app.store_code(error::contract(true)); @@ -1858,7 +1871,7 @@ mod errors { // execute should error let err = app - .execute_contract(Addr::unchecked("random"), contract_addr, &msg, &[]) + .execute_contract(app.api().addr_make("random"), contract_addr, &msg, &[]) .unwrap_err(); // we should be able to retrieve the original error by downcasting @@ -1876,9 +1889,10 @@ mod errors { #[test] fn nested_call() { - let owner = Addr::unchecked("owner"); let mut app = App::default(); + let owner = app.api().addr_make("owner"); + let error_code_id = app.store_code(error::contract(true)); let caller_code_id = app.store_code(caller::contract()); @@ -1898,7 +1912,7 @@ mod errors { funds: vec![], }; let err = app - .execute_contract(Addr::unchecked("random"), caller_addr, &msg, &[]) + .execute_contract(app.api().addr_make("random"), caller_addr, &msg, &[]) .unwrap_err(); // we can downcast to get the original error @@ -1916,8 +1930,8 @@ mod errors { #[test] fn double_nested_call() { - let owner = Addr::unchecked("owner"); let mut app = App::default(); + let owner = app.api().addr_make("owner"); let error_code_id = app.store_code(error::contract(true)); let caller_code_id = app.store_code(caller::contract()); @@ -1946,7 +1960,7 @@ mod errors { funds: vec![], }; let err = app - .execute_contract(Addr::unchecked("random"), caller_addr1, &msg, &[]) + .execute_contract(app.api().addr_make("random"), caller_addr1, &msg, &[]) .unwrap_err(); // uncomment to have the test fail and see how the error stringifies diff --git a/src/tests/test_custom_handler.rs b/src/tests/test_custom_handler.rs index 36168264..ae339897 100644 --- a/src/tests/test_custom_handler.rs +++ b/src/tests/test_custom_handler.rs @@ -2,7 +2,7 @@ use crate::custom_handler::CachingCustomHandler; use crate::test_helpers::CustomHelperMsg; use crate::{App, Module}; use cosmwasm_std::testing::MockStorage; -use cosmwasm_std::{Addr, Empty}; +use cosmwasm_std::Empty; ///Custom handlers in CosmWasm allow developers to incorporate their own unique logic into tests. ///This feature is valuable for tailoring the testing environment to reflect specific @@ -22,7 +22,7 @@ fn custom_handler_works() { &mut storage, app.router(), &app.block_info(), - Addr::unchecked("sender"), + app.api().addr_make("sender"), CustomHelperMsg::SetAge { age: 32 }, ); diff --git a/src/wasm.rs b/src/wasm.rs index 32f62053..39623fc3 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1287,7 +1287,12 @@ mod test { let mut wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), error::contract(false)); + + let creator_addr = api.addr_make("creator"); + let user_addr = api.addr_make("foobar"); + let admin_addr = api.addr_make("admin"); + + let code_id = wasm_keeper.store_code(creator_addr, error::contract(false)); transactional(&mut wasm_storage, |cache, _| { // cannot register contract with unregistered codeId @@ -1295,8 +1300,8 @@ mod test { &api, cache, code_id + 1, - Addr::unchecked("foobar"), - Addr::unchecked("admin"), + user_addr.clone(), + admin_addr.clone(), "label".to_owned(), 1000, None, @@ -1310,8 +1315,8 @@ mod test { &api, cache, code_id, - Addr::unchecked("foobar"), - Addr::unchecked("admin"), + user_addr.clone(), + admin_addr.clone(), "label".to_owned(), 1000, None, @@ -1328,8 +1333,8 @@ mod test { contract_data, ContractData { code_id, - creator: Addr::unchecked("foobar"), - admin: Some(Addr::unchecked("admin")), + creator: user_addr, + admin: Some(admin_addr), label: "label".to_owned(), created: 1000, } @@ -1360,7 +1365,7 @@ mod test { // and the error for calling an unregistered contract let info = mock_info("foobar", &[]); wasm_keeper.call_instantiate( - Addr::unchecked("unregistered"), + api.addr_make("unregistered"), &api, cache, &mock_router(), @@ -1381,19 +1386,19 @@ mod test { let mut wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); + let code_id = wasm_keeper.store_code(api.addr_make("buzz"), payout::contract()); assert_eq!(1, code_id); - let creator = "foobar"; - let admin = "admin"; + let creator = api.addr_make("foobar"); + let admin = api.addr_make("admin"); let contract_addr = wasm_keeper .register_contract( &api, &mut wasm_storage, code_id, - Addr::unchecked(creator), - Addr::unchecked(admin), + creator.clone(), + admin.clone(), "label".to_owned(), 1000, None, @@ -1421,10 +1426,11 @@ mod test { #[cfg(feature = "cosmwasm_1_2")] fn query_code_info() { let api = MockApi::default(); + let creator = api.addr_make("creator"); let wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); + let code_id = wasm_keeper.store_code(creator.clone(), payout::contract()); let querier: MockQuerier = MockQuerier::new(&[]); let query = WasmQuery::CodeInfo { code_id }; let code_info = wasm_keeper @@ -1432,7 +1438,7 @@ mod test { .unwrap(); let actual: cosmwasm_std::CodeInfoResponse = from_json(code_info).unwrap(); assert_eq!(code_id, actual.code_id); - assert_eq!("creator", actual.creator); + assert_eq!(creator.as_str(), actual.creator); assert!(!actual.checksum.is_empty()); } @@ -1440,11 +1446,12 @@ mod test { #[cfg(feature = "cosmwasm_1_2")] fn different_contracts_must_have_different_checksum() { let api = MockApi::default(); + let creator = api.addr_make("creator"); let wasm_storage = MockStorage::new(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id_payout = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); - let code_id_caller = wasm_keeper.store_code(Addr::unchecked("creator"), caller::contract()); + let code_id_payout = wasm_keeper.store_code(creator.clone(), payout::contract()); + let code_id_caller = wasm_keeper.store_code(creator, caller::contract()); let querier: MockQuerier = MockQuerier::new(&[]); let query_payout = WasmQuery::CodeInfo { code_id: code_id_payout, @@ -1488,7 +1495,7 @@ mod test { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); + let code_id = wasm_keeper.store_code(api.addr_make("buzz"), payout::contract()); let mut wasm_storage = MockStorage::new(); @@ -1497,8 +1504,8 @@ mod test { &api, &mut wasm_storage, code_id, - Addr::unchecked("foobar"), - Addr::unchecked("admin"), + api.addr_make("foobar"), + api.addr_make("admin"), "label".to_owned(), 1000, None, @@ -1541,7 +1548,7 @@ mod test { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); + let code_id = wasm_keeper.store_code(api.addr_make("buzz"), payout::contract()); let mut wasm_storage = MockStorage::new(); let mut cache = StorageTransaction::new(&wasm_storage); @@ -1551,7 +1558,7 @@ mod test { &api, &mut cache, code_id, - Addr::unchecked("foobar"), + api.addr_make("foobar"), None, "label".to_owned(), 1000, @@ -1654,7 +1661,7 @@ mod test { let api = MockApi::default(); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract()); + let code_id = wasm_keeper.store_code(api.addr_make("buzz"), payout::contract()); let mut wasm_storage = MockStorage::new(); @@ -1667,7 +1674,7 @@ mod test { &api, cache, code_id, - Addr::unchecked("foobar"), + api.addr_make("foobar"), None, "".to_string(), 1000, @@ -1708,7 +1715,7 @@ mod test { &api, cache, code_id, - Addr::unchecked("foobar"), + api.addr_make("foobar"), None, "".to_owned(), 1000, @@ -1744,7 +1751,7 @@ mod test { &api, cache2, code_id, - Addr::unchecked("foobar"), + api.addr_make("foobar"), None, "".to_owned(), 1000, @@ -1822,23 +1829,25 @@ mod test { #[test] fn update_clear_admin_works() { let api = MockApi::default(); + let creator_addr = api.addr_make("creator"); + let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), caller::contract()); + let code_id = wasm_keeper.store_code(creator_addr.clone(), caller::contract()); let mut wasm_storage = MockStorage::new(); - let admin: Addr = Addr::unchecked("admin"); - let new_admin: Addr = Addr::unchecked("new_admin"); - let normal_user: Addr = Addr::unchecked("normal_user"); + let admin_addr = api.addr_make("admin"); + let new_admin_addr = api.addr_make("new_admin"); + let user_addr = api.addr_make("normal_user"); let contract_addr = wasm_keeper .register_contract( &api, &mut wasm_storage, code_id, - Addr::unchecked("creator"), - admin.clone(), + creator_addr, + admin_addr.clone(), "label".to_owned(), 1000, None, @@ -1865,7 +1874,7 @@ mod test { &wasm_storage, &wasm_keeper, &contract_addr, - Some(admin.clone()), + Some(admin_addr.clone()), ); // non-admin should not be allowed to become admin on their own @@ -1875,10 +1884,10 @@ mod test { &mut wasm_storage, &mock_router(), &block, - normal_user.clone(), + user_addr.clone(), WasmMsg::UpdateAdmin { contract_addr: contract_addr.to_string(), - admin: normal_user.to_string(), + admin: user_addr.to_string(), }, ) .unwrap_err(); @@ -1888,7 +1897,7 @@ mod test { &wasm_storage, &wasm_keeper, &contract_addr, - Some(admin.clone()), + Some(admin_addr.clone()), ); // admin should be allowed to transfer administration permissions @@ -1898,10 +1907,10 @@ mod test { &mut wasm_storage, &mock_router(), &block, - admin, + admin_addr, WasmMsg::UpdateAdmin { contract_addr: contract_addr.to_string(), - admin: new_admin.to_string(), + admin: new_admin_addr.to_string(), }, ) .unwrap(); @@ -1912,7 +1921,7 @@ mod test { &wasm_storage, &wasm_keeper, &contract_addr, - Some(new_admin.clone()), + Some(new_admin_addr.clone()), ); // new_admin should now be able to clear to admin @@ -1922,7 +1931,7 @@ mod test { &mut wasm_storage, &mock_router(), &block, - new_admin, + new_admin_addr, WasmMsg::ClearAdmin { contract_addr: contract_addr.to_string(), }, @@ -1937,8 +1946,14 @@ mod test { #[test] fn uses_simple_address_generator_by_default() { let api = MockApi::default(); + + let creator_addr = api.addr_make("creator"); + let admin_addr = api.addr_make("admin"); + let user_1_addr = api.addr_make("foobar"); + let user_2_addr = api.addr_make("boobaz"); + let mut wasm_keeper = wasm_keeper(); - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); + let code_id = wasm_keeper.store_code(creator_addr.clone(), payout::contract()); let mut wasm_storage = MockStorage::new(); @@ -1947,8 +1962,8 @@ mod test { &api, &mut wasm_storage, code_id, - Addr::unchecked("foobar"), - Addr::unchecked("admin"), + user_1_addr.clone(), + admin_addr.clone(), "label".to_owned(), 1000, None, @@ -1967,8 +1982,8 @@ mod test { &api, &mut wasm_storage, code_id, - Addr::unchecked("foobar"), - Addr::unchecked("admin"), + user_1_addr.clone(), + admin_addr.clone(), "label".to_owned(), 1000, Binary::from(salt.clone()), @@ -1976,16 +1991,16 @@ mod test { .unwrap(); assert_eq!( - contract_addr, + contract_addr.as_str(), format!( "contract{}{}", - api.addr_canonicalize("foobar").unwrap(), + api.addr_canonicalize(user_1_addr.as_str()).unwrap(), salt.to_hex() ), "default address generator returned incorrect address" ); - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); + let code_id = wasm_keeper.store_code(creator_addr, payout::contract()); assert_eq!(2, code_id); let contract_addr = wasm_keeper @@ -1993,8 +2008,8 @@ mod test { &api, &mut wasm_storage, code_id, - Addr::unchecked("boobaz"), - Addr::unchecked("admin"), + user_2_addr.clone(), + admin_addr, "label".to_owned(), 1000, Binary::from(salt.clone()), @@ -2005,7 +2020,7 @@ mod test { contract_addr, format!( "contract{}{}", - api.addr_canonicalize("boobaz").unwrap(), + api.addr_canonicalize(user_2_addr.as_str()).unwrap(), salt.to_hex() ), "default address generator returned incorrect address" @@ -2045,14 +2060,14 @@ mod test { #[test] fn can_use_custom_address_generator() { let api = MockApi::default(); - let expected_addr = Addr::unchecked("address"); - let expected_predictable_addr = Addr::unchecked("predictable_address"); + let expected_addr = api.addr_make("address"); + let expected_predictable_addr = api.addr_make("predictable_address"); let mut wasm_keeper: WasmKeeper = WasmKeeper::new().with_address_generator(TestAddressGenerator { address: expected_addr.clone(), predictable_address: expected_predictable_addr.clone(), }); - let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract()); + let code_id = wasm_keeper.store_code(api.addr_make("creator"), payout::contract()); let mut wasm_storage = MockStorage::new(); @@ -2061,8 +2076,8 @@ mod test { &api, &mut wasm_storage, code_id, - Addr::unchecked("foobar"), - Addr::unchecked("admin"), + api.addr_make("foobar"), + api.addr_make("admin"), "label".to_owned(), 1000, None, @@ -2079,8 +2094,8 @@ mod test { &api, &mut wasm_storage, code_id, - Addr::unchecked("foobar"), - Addr::unchecked("admin"), + api.addr_make("foobar"), + api.addr_make("admin"), "label".to_owned(), 1000, Binary::from(HexBinary::from_hex("23A74B8C").unwrap()), diff --git a/tests/test_app_builder/test_with_bank.rs b/tests/test_app_builder/test_with_bank.rs index fa9f1758..d0ca406d 100644 --- a/tests/test_app_builder/test_with_bank.rs +++ b/tests/test_app_builder/test_with_bank.rs @@ -1,5 +1,5 @@ use crate::test_app_builder::MyKeeper; -use cosmwasm_std::{coins, Addr, BankMsg, BankQuery}; +use cosmwasm_std::{coins, BankMsg, BankQuery}; use cw_multi_test::{no_init, AppBuilder, Bank, BankSudo, Executor}; type MyBankKeeper = MyKeeper; @@ -20,14 +20,14 @@ fn building_app_with_custom_bank_should_work() { let mut app = app_builder.with_bank(bank_keeper).build(no_init); // prepare additional input data - let recipient = Addr::unchecked("recipient"); + let recipient = app.api().addr_make("recipient"); let denom = "eth"; // executing bank message should return an error defined in custom keeper assert_eq!( EXECUTE_MSG, app.execute( - Addr::unchecked("sender"), + app.api().addr_make("sender"), BankMsg::Send { to_address: recipient.clone().into(), amount: coins(1, denom), diff --git a/tests/test_app_builder/test_with_distribution.rs b/tests/test_app_builder/test_with_distribution.rs index 23139ec7..45b2e350 100644 --- a/tests/test_app_builder/test_with_distribution.rs +++ b/tests/test_app_builder/test_with_distribution.rs @@ -1,5 +1,5 @@ use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; -use cosmwasm_std::{Addr, DistributionMsg, Empty}; +use cosmwasm_std::{DistributionMsg, Empty}; use cw_multi_test::{no_init, AppBuilder, Distribution, Executor}; type MyDistributionKeeper = MyKeeper; @@ -21,13 +21,13 @@ fn building_app_with_custom_distribution_should_work() { .build(no_init); // prepare additional input data - let recipient = Addr::unchecked("recipient"); + let recipient = app.api().addr_make("recipient"); // executing distribution message should return an error defined in custom keeper assert_eq!( EXECUTE_MSG, app.execute( - Addr::unchecked("sender"), + app.api().addr_make("sender"), DistributionMsg::SetWithdrawAddress { address: recipient.into(), } diff --git a/tests/test_app_builder/test_with_gov.rs b/tests/test_app_builder/test_with_gov.rs index 7f47095a..0499cf88 100644 --- a/tests/test_app_builder/test_with_gov.rs +++ b/tests/test_app_builder/test_with_gov.rs @@ -1,5 +1,5 @@ use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; -use cosmwasm_std::{Addr, Empty, GovMsg, VoteOption}; +use cosmwasm_std::{Empty, GovMsg, VoteOption}; use cw_multi_test::{no_init, AppBuilder, Executor, Gov}; type MyGovKeeper = MyKeeper; @@ -21,7 +21,7 @@ fn building_app_with_custom_gov_should_work() { assert_eq!( EXECUTE_MSG, app.execute( - Addr::unchecked("sender"), + app.api().addr_make("sender"), GovMsg::Vote { proposal_id: 1, vote: VoteOption::Yes, diff --git a/tests/test_app_builder/test_with_ibc.rs b/tests/test_app_builder/test_with_ibc.rs index 431570e0..d5297c63 100644 --- a/tests/test_app_builder/test_with_ibc.rs +++ b/tests/test_app_builder/test_with_ibc.rs @@ -1,5 +1,5 @@ use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; -use cosmwasm_std::{Addr, Empty, IbcMsg, IbcQuery, QueryRequest}; +use cosmwasm_std::{Empty, IbcMsg, IbcQuery, QueryRequest}; use cw_multi_test::{no_init, AppBuilder, Executor, Ibc}; type MyIbcKeeper = MyKeeper; @@ -22,7 +22,7 @@ fn building_app_with_custom_ibc_should_work() { assert_eq!( EXECUTE_MSG, app.execute( - Addr::unchecked("sender"), + app.api().addr_make("sender"), IbcMsg::CloseChannel { channel_id: "my-channel".to_string() } diff --git a/tests/test_app_builder/test_with_staking.rs b/tests/test_app_builder/test_with_staking.rs index 798b42d5..6cd1e7d7 100644 --- a/tests/test_app_builder/test_with_staking.rs +++ b/tests/test_app_builder/test_with_staking.rs @@ -1,5 +1,5 @@ use crate::test_app_builder::MyKeeper; -use cosmwasm_std::{Addr, Api, BlockInfo, Coin, CustomQuery, StakingMsg, StakingQuery, Storage}; +use cosmwasm_std::{Api, BlockInfo, Coin, CustomQuery, StakingMsg, StakingQuery, Storage}; use cw_multi_test::error::AnyResult; use cw_multi_test::{ no_init, AppBuilder, AppResponse, CosmosRouter, Executor, Staking, StakingSudo, @@ -34,13 +34,13 @@ fn building_app_with_custom_staking_should_work() { let mut app = app_builder.with_staking(stake_keeper).build(no_init); // prepare additional input data - let validator = Addr::unchecked("recipient"); + let validator = app.api().addr_make("recipient"); // executing staking message should return an error defined in custom keeper assert_eq!( EXECUTE_MSG, app.execute( - Addr::unchecked("sender"), + app.api().addr_make("sender"), StakingMsg::Delegate { validator: validator.clone().into(), amount: Coin::new(1, "eth"), diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index c068abb7..723a8b62 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -1,5 +1,5 @@ use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; -use cosmwasm_std::{to_json_vec, Addr, CosmosMsg, Empty, QueryRequest}; +use cosmwasm_std::{to_json_vec, CosmosMsg, Empty, QueryRequest}; use cw_multi_test::{ no_init, AppBuilder, Executor, Stargate, StargateAcceptingModule, StargateFailingModule, StargateMsg, StargateQuery, @@ -25,7 +25,7 @@ fn building_app_with_custom_stargate_should_work() { // an error defined in custom stargate keeper assert_eq!( app.execute( - Addr::unchecked("sender"), + app.api().addr_make("sender"), CosmosMsg::Stargate { type_url: "test".to_string(), value: Default::default() @@ -59,7 +59,7 @@ fn building_app_with_accepting_stargate_should_work() { .build(no_init); app.execute( - Addr::unchecked("sender"), + app.api().addr_make("sender"), CosmosMsg::Stargate { type_url: "test".to_string(), value: Default::default(), @@ -84,7 +84,7 @@ fn building_app_with_failing_stargate_should_work() { .build(no_init); app.execute( - Addr::unchecked("sender"), + app.api().addr_make("sender"), CosmosMsg::Stargate { type_url: "test".to_string(), value: Default::default(), diff --git a/tests/test_app_builder/test_with_storage.rs b/tests/test_app_builder/test_with_storage.rs index b6106d7f..003a5b79 100644 --- a/tests/test_app_builder/test_with_storage.rs +++ b/tests/test_app_builder/test_with_storage.rs @@ -1,5 +1,5 @@ use crate::{test_contracts, CounterQueryMsg, CounterResponseMsg}; -use cosmwasm_std::{to_json_binary, Addr, Empty, Order, Record, Storage, WasmMsg}; +use cosmwasm_std::{to_json_binary, Empty, Order, Record, Storage, WasmMsg}; use cw_multi_test::{no_init, AppBuilder, Executor}; use std::collections::BTreeMap; use std::iter; @@ -34,7 +34,6 @@ impl Storage for MyStorage { #[test] fn building_app_with_custom_storage_should_work() { // prepare additional test input data - let owner = Addr::unchecked("owner"); let msg = to_json_binary(&Empty {}).unwrap(); let admin = None; let funds = vec![]; @@ -46,6 +45,8 @@ fn building_app_with_custom_storage_should_work() { .with_storage(MyStorage::default()) .build(no_init); + let owner = app.api().addr_make("owner"); + // store a contract code let code_id = app.store_code(test_contracts::counter::contract()); diff --git a/tests/test_app_builder/test_with_wasm.rs b/tests/test_app_builder/test_with_wasm.rs index 9708d796..8ee508a6 100644 --- a/tests/test_app_builder/test_with_wasm.rs +++ b/tests/test_app_builder/test_with_wasm.rs @@ -95,7 +95,7 @@ fn building_app_with_custom_wasm_should_work() { let mut app = app_builder.with_wasm(wasm_keeper).build(no_init); // prepare additional input data - let contract_addr = Addr::unchecked("contract"); + let contract_addr = app.api().addr_make("contract"); // calling store_code should return value defined in custom keeper assert_eq!(CODE_ID, app.store_code(test_contracts::counter::contract())); @@ -119,7 +119,7 @@ fn building_app_with_custom_wasm_should_work() { assert_eq!( EXECUTE_MSG, app.execute( - Addr::unchecked("sender"), + app.api().addr_make("sender"), WasmMsg::Instantiate { admin: None, code_id: 0, diff --git a/tests/test_module/test_accepting_module.rs b/tests/test_module/test_accepting_module.rs index 1952b412..47a04d08 100644 --- a/tests/test_module/test_accepting_module.rs +++ b/tests/test_module/test_accepting_module.rs @@ -1,5 +1,5 @@ use cosmwasm_std::testing::MockStorage; -use cosmwasm_std::{Addr, Binary, Empty}; +use cosmwasm_std::{Binary, Empty}; use cw_multi_test::{AcceptingModule, App, AppResponse, Module}; /// Utility function for comparing responses. @@ -20,7 +20,7 @@ fn assert_results(accepting_module: AcceptingModule) { &mut storage, app.router(), &app.block_info(), - Addr::unchecked("sender"), + app.api().addr_make("sender"), Empty {}, ) .unwrap(), diff --git a/tests/test_module/test_failing_module.rs b/tests/test_module/test_failing_module.rs index 64c5a2ca..fa074312 100644 --- a/tests/test_module/test_failing_module.rs +++ b/tests/test_module/test_failing_module.rs @@ -1,5 +1,5 @@ use cosmwasm_std::testing::MockStorage; -use cosmwasm_std::{Addr, Empty}; +use cosmwasm_std::Empty; use cw_multi_test::{App, FailingModule, Module}; /// Utility function for asserting outputs returned from failing module. @@ -7,14 +7,14 @@ fn assert_results(failing_module: FailingModule) { let app = App::default(); let mut storage = MockStorage::default(); assert_eq!( - r#"Unexpected exec msg Empty from Addr("sender")"#, + r#"Unexpected exec msg Empty from Addr("cosmwasm1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qlm3aqg")"#, failing_module .execute( app.api(), &mut storage, app.router(), &app.block_info(), - Addr::unchecked("sender"), + app.api().addr_make("sender"), Empty {} ) .unwrap_err() diff --git a/tests/test_wasm/test_with_addr_gen.rs b/tests/test_wasm/test_with_addr_gen.rs index ddabf3d9..418aa6d6 100644 --- a/tests/test_wasm/test_with_addr_gen.rs +++ b/tests/test_wasm/test_with_addr_gen.rs @@ -1,7 +1,7 @@ use cosmwasm_std::{Addr, Api, Empty, Storage}; use cw_multi_test::error::AnyResult; -use cw_multi_test::{no_init, AddressGenerator, AppBuilder, Executor, WasmKeeper}; +use cw_multi_test::{no_init, AddressGenerator, AppBuilder, Executor, IntoAddr, WasmKeeper}; use cw_multi_test::{MockAddressGenerator, MockApiBech32}; use crate::test_contracts; @@ -20,7 +20,7 @@ fn contract_address_should_work() { // store contract's code let code_id = app.store_code_with_creator( - Addr::unchecked("creator"), + app.api().addr_make("creator"), test_contracts::counter::contract(), ); @@ -60,7 +60,7 @@ fn custom_address_generator_should_work() { _code_id: u64, _instance_id: u64, ) -> AnyResult { - Ok(Addr::unchecked("test_address")) + Ok("test_address".into_addr()) } } @@ -75,7 +75,7 @@ fn custom_address_generator_should_work() { let contract_addr = app .instantiate_contract( code_id, - Addr::unchecked("owner"), + app.api().addr_make("owner"), &Empty {}, &[], "Counter", @@ -84,7 +84,7 @@ fn custom_address_generator_should_work() { .unwrap(); // make sure that contract address equals to "test_address" generated by custom address generator - assert_eq!(contract_addr.as_str(), "test_address"); + assert_eq!(contract_addr.as_str(), "test_address".into_addr().as_str()); } #[test] diff --git a/tests/test_wasm/test_with_checksum_gen.rs b/tests/test_wasm/test_with_checksum_gen.rs index 89b7d600..64e89138 100644 --- a/tests/test_wasm/test_with_checksum_gen.rs +++ b/tests/test_wasm/test_with_checksum_gen.rs @@ -11,7 +11,7 @@ fn default_checksum_generator_should_work() { // store contract's code let code_id = app.store_code_with_creator( - Addr::unchecked("creator"), + app.api().addr_make("creator"), test_contracts::counter::contract(), ); @@ -44,7 +44,7 @@ fn custom_checksum_generator_should_work() { // store contract's code let code_id = app.store_code_with_creator( - Addr::unchecked("creator"), + app.api().addr_make("creator"), test_contracts::counter::contract(), ); From d8e34107eff43f340139380dd237b249b54d8934 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 10:03:30 +0100 Subject: [PATCH 133/250] Upgraded dependencies. --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f07fafcb..6bca0ef6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" dependencies = [ "backtrace", ] @@ -590,9 +590,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -841,18 +841,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index ca06df48..93e8ae4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ cosmwasm_1_3 = ["cosmwasm_1_2", "cosmwasm-std/cosmwasm_1_3"] cosmwasm_1_4 = ["cosmwasm_1_3", "cosmwasm-std/cosmwasm_1_4"] [dependencies] -anyhow = "1.0.80" +anyhow = "1.0.81" bech32 = "0.11.0" cosmwasm-std = { version = "1.5.3", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "1.2.0" @@ -28,7 +28,7 @@ prost = "0.12.3" schemars = "0.8.16" serde = "1.0.197" sha2 = "0.10.8" -thiserror = "1.0.57" +thiserror = "1.0.58" [dev-dependencies] hex = "0.4.3" From 59980fdd3c6ffebea0ec740d21952459b7f37c46 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 10:09:04 +0100 Subject: [PATCH 134/250] Upgraded dependencies. --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 32f288fa..d40da6ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" dependencies = [ "backtrace", ] @@ -572,9 +572,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -817,18 +817,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index dffbe43d..41c9f351 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ backtrace = ["anyhow/backtrace"] cosmwasm_2_0 = ["cosmwasm-std/cosmwasm_2_0"] [dependencies] -anyhow = "1.0.80" +anyhow = "1.0.81" bech32 = "0.11.0" cosmwasm-std = { version = "2.0.0-rc.1", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "2.0.0-rc.0" @@ -25,7 +25,7 @@ prost = "0.12.3" schemars = "0.8.16" serde = "1.0.197" sha2 = "0.10.8" -thiserror = "1.0.57" +thiserror = "1.0.58" [dev-dependencies] hex = "0.4.3" From 38782178ec2e256ab88ac6a3a5f84ee0b8e221d7 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 10:18:11 +0100 Subject: [PATCH 135/250] Refatored addresses. --- src/addresses.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/addresses.rs b/src/addresses.rs index 2747f1d6..479ceec6 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -7,8 +7,12 @@ use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage}; use sha2::digest::Update; use sha2::{Digest, Sha256}; +const DEFAULT_PREFIX: &str = "cosmwasm"; + /// Defines conversions to [Addr], this conversion is format agnostic -/// and is aligned with the format generated by `cosmwasm-std::testing::MockApi`. +/// and should be aligned with the format generated by [MockApi]. +/// +/// [MockApi]: https://github.com/CosmWasm/cosmwasm/blob/9a239838baba50f4f47230da306f39a8bb4ea697/packages/std/src/testing/mock.rs#L251-L257 pub trait IntoAddr { /// Converts into [Addr]. fn into_addr(self) -> Addr; @@ -38,7 +42,7 @@ pub trait IntoBech32 { impl IntoBech32 for &str { fn into_bech32(self) -> Addr { - MockApiBech32::new("cosmwasm").addr_make(self) + MockApiBech32::new(DEFAULT_PREFIX).addr_make(self) } fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr { @@ -56,7 +60,7 @@ pub trait IntoBech32m { impl IntoBech32m for &str { fn into_bech32m(self) -> Addr { - MockApiBech32m::new("cosmwasm").addr_make(self) + MockApiBech32m::new(DEFAULT_PREFIX).addr_make(self) } fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr { From 8f88c9016c9db6cd883873f35faec808896be1fe Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 10:20:38 +0100 Subject: [PATCH 136/250] Updated documentation. --- src/addresses.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/addresses.rs b/src/addresses.rs index 479ceec6..51838c6d 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -22,10 +22,12 @@ pub trait IntoAddr { } impl IntoAddr for &str { + /// Converts [&str] into [Addr]. fn into_addr(self) -> Addr { MockApi::default().addr_make(self) } + /// Converts [&str] into [Addr] with custom prefix. fn into_addr_with_prefix(self, prefix: &'static str) -> Addr { MockApi::default().with_prefix(prefix).addr_make(self) } @@ -41,10 +43,12 @@ pub trait IntoBech32 { } impl IntoBech32 for &str { + /// Converts [&str] into [Addr] containing a string compatible with `Bech32` format with default prefix. fn into_bech32(self) -> Addr { MockApiBech32::new(DEFAULT_PREFIX).addr_make(self) } + /// Converts [&str] into [Addr] containing a string compatible with `Bech32` format with custom prefix. fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr { MockApiBech32::new(prefix).addr_make(self) } @@ -59,10 +63,12 @@ pub trait IntoBech32m { } impl IntoBech32m for &str { + /// Converts [&str] into [Addr] containing a string compatible with `Bech32m` format with default prefix. fn into_bech32m(self) -> Addr { MockApiBech32m::new(DEFAULT_PREFIX).addr_make(self) } + /// Converts [&str] into [Addr] containing a string compatible with `Bech32m` format with custom prefix. fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr { MockApiBech32m::new(prefix).addr_make(self) } From 73d20bbc9619248a69c0a25888cc74c92e1c725e Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 10:26:29 +0100 Subject: [PATCH 137/250] Upgraded dependencies. --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac06bd85..53dd10f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" dependencies = [ "backtrace", ] @@ -590,9 +590,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -841,18 +841,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 3d0304e8..faaedc52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ cosmwasm_1_3 = ["cosmwasm_1_2", "cosmwasm-std/cosmwasm_1_3"] cosmwasm_1_4 = ["cosmwasm_1_3", "cosmwasm-std/cosmwasm_1_4"] [dependencies] -anyhow = "1.0.80" +anyhow = "1.0.81" bech32 = "0.11.0" cosmwasm-std = { version = "1.5.3", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "1.2.0" @@ -28,7 +28,7 @@ prost = "0.12.3" schemars = "0.8.16" serde = "1.0.197" sha2 = "0.10.8" -thiserror = "1.0.57" +thiserror = "1.0.58" [dev-dependencies] hex = "0.4.3" From e05b099ae340080a491762b12bd73d4f6b561cff Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 10:30:53 +0100 Subject: [PATCH 138/250] Refactored store_code function. --- src/app.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app.rs b/src/app.rs index 0083c69a..1d716718 100644 --- a/src/app.rs +++ b/src/app.rs @@ -256,8 +256,9 @@ where /// so it can later be used to instantiate a contract. pub fn store_code(&mut self, code: Box>) -> u64 { self.init_modules(|router, _, _| { - let creator = MockApi::default().addr_make("creator"); - router.wasm.store_code(creator, code) + router + .wasm + .store_code(MockApi::default().addr_make("creator"), code) }) } From a4157d260ff950923decd3cfb75199f6e51948f4 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 10:36:14 +0100 Subject: [PATCH 139/250] Refactored store_code function. --- src/app.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/app.rs b/src/app.rs index 5bfba9e9..09d2ba5c 100644 --- a/src/app.rs +++ b/src/app.rs @@ -255,18 +255,21 @@ where /// 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 { - let creator_addr = MockApi::default().addr_make("creator"); - self.init_modules(|router, _, _| router.wasm.store_code(creator_addr, code)) + self.init_modules(|router, _, _| { + router + .wasm + .store_code(MockApi::default().addr_make("creator"), code) + }) } /// Registers contract code (like [store_code](Self::store_code)), /// but takes the address of the code creator as an additional argument. pub fn store_code_with_creator( &mut self, - creator_addr: Addr, + creator: Addr, code: Box>, ) -> u64 { - self.init_modules(|router, _, _| router.wasm.store_code(creator_addr, code)) + self.init_modules(|router, _, _| router.wasm.store_code(creator, code)) } /// Duplicates the contract code identified by `code_id` and returns From 5f266b55cbdbd74e2cd6516316f7f7a6daba8443 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 11:01:37 +0100 Subject: [PATCH 140/250] Implemented store_code_with_id function. --- src/app.rs | 11 +++ src/error.rs | 20 ++++- src/tests/test_error.rs | 5 +- src/wasm.rs | 106 +++++++++++++++++------ tests/test_app_builder/test_with_wasm.rs | 31 ++++--- 5 files changed, 132 insertions(+), 41 deletions(-) diff --git a/src/app.rs b/src/app.rs index 09d2ba5c..75666a3f 100644 --- a/src/app.rs +++ b/src/app.rs @@ -272,6 +272,17 @@ where self.init_modules(|router, _, _| router.wasm.store_code(creator, code)) } + /// Registers contract code (like [store_code_with_creator](Self::store_code_with_creator)), + /// but takes the code identifier as an additional argument. + pub fn store_code_with_id( + &mut self, + creator: Addr, + code_id: u64, + code: Box>, + ) -> AnyResult { + self.init_modules(|router, _, _| router.wasm.store_code_with_id(creator, code_id, code)) + } + /// Duplicates the contract code identified by `code_id` and returns /// the identifier of the newly created copy of the contract code. /// diff --git a/src/error.rs b/src/error.rs index 013e0aed..fce588b2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -39,6 +39,14 @@ pub enum Error { #[error("code id {0}: no such code")] UnregisteredCodeId(u64), + /// Error variant for reporting duplicated contract code identifier. + #[error("duplicated code id {0}")] + DuplicatedCodeId(u64), + + /// Error variant for reporting a situation when no more contract code identifiers are available. + #[error("no more code identifiers available")] + NoMoreCodeIdAvailable, + /// Error variant for reporting duplicated contract addresses. #[error("Contract with this address already exists: {0}")] DuplicatedContractAddress(String), @@ -76,7 +84,7 @@ impl Error { } /// Creates an instance of the [Error](Self) for invalid contract code identifier. - pub fn invalid_contract_code_id() -> Self { + pub fn invalid_code_id() -> Self { Self::InvalidCodeId } @@ -85,6 +93,16 @@ impl Error { Self::UnregisteredCodeId(code_id) } + /// Creates an instance of the [Error](Self) for duplicated contract code identifier. + pub fn duplicated_code_id(code_id: u64) -> Self { + Self::DuplicatedCodeId(code_id) + } + + /// Creates an instance of the [Error](Self) for exhausted contract code identifiers. + pub fn no_more_code_id_available() -> Self { + Self::NoMoreCodeIdAvailable + } + /// Creates an instance of the [Error](Self) for duplicated contract addresses. pub fn duplicated_contract_address(address: impl Into) -> Self { Self::DuplicatedContractAddress(address.into()) diff --git a/src/tests/test_error.rs b/src/tests/test_error.rs index eb113e72..91292f4e 100644 --- a/src/tests/test_error.rs +++ b/src/tests/test_error.rs @@ -35,10 +35,7 @@ fn instantiating_error_should_work() { }) .to_string() ); - assert_eq!( - "code id: invalid", - Error::invalid_contract_code_id().to_string() - ); + assert_eq!("code id: invalid", Error::invalid_code_id().to_string()); assert_eq!( "code id 53: no such code", Error::unregistered_code_id(53).to_string() diff --git a/src/wasm.rs b/src/wasm.rs index a4466d78..ac499fee 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -19,6 +19,7 @@ use schemars::JsonSchema; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use std::borrow::Borrow; +use std::collections::BTreeMap; use std::fmt::Debug; /// Contract state kept in storage, separate from the contracts themselves (contract code). @@ -37,7 +38,7 @@ const CONTRACT_ATTR: &str = "_contract_address"; pub struct WasmSudo { /// Address of a contract the privileged action will be sent to. pub contract_addr: Addr, - /// Message representing privileged action to be executed by contract's `sudo` entry-point. + /// Message representing privileged action to be executed by contract `sudo` entry-point. pub message: Binary, } @@ -73,8 +74,8 @@ struct CodeData { creator: Addr, /// Checksum of the contract's code base. checksum: Checksum, - /// Identifier of the code base where the contract code is stored in memory. - code_base_id: usize, + /// Identifier of the _source_ code of the contract stored in wasm keeper. + source_id: usize, } /// Acts as the interface for interacting with WebAssembly (Wasm) modules. @@ -115,6 +116,15 @@ pub trait Wasm { /// Stores the contract's code and returns an identifier of the stored contract's code. fn store_code(&mut self, creator: Addr, code: Box>) -> u64; + /// Stores the contract's code under specified identifier, + /// returns the same code identifier when successful. + fn store_code_with_id( + &mut self, + creator: Addr, + code_id: u64, + code: Box>, + ) -> AnyResult; + /// Duplicates the contract's code with specified identifier /// and returns an identifier of the copy of the contract's code. fn duplicate_code(&mut self, code_id: u64) -> AnyResult; @@ -131,7 +141,7 @@ pub struct WasmKeeper { /// Contract codes that stand for wasm code in real-life blockchain. code_base: Vec>>, /// Code data with code base identifier and additional attributes. - code_data: Vec, + code_data: BTreeMap, /// Contract's address generator. address_generator: Box, /// Contract's code checksum generator. @@ -145,7 +155,7 @@ impl Default for WasmKeeper { fn default() -> Self { Self { code_base: Vec::default(), - code_data: Vec::default(), + code_data: BTreeMap::default(), address_generator: Box::new(SimpleAddressGenerator), checksum_generator: Box::new(SimpleChecksumGenerator), _p: std::marker::PhantomData, @@ -240,28 +250,45 @@ where /// Stores the contract's code in the in-memory lookup table. /// Returns an identifier of the stored contract code. fn store_code(&mut self, creator: Addr, code: Box>) -> u64 { - let code_base_id = self.code_base.len(); - self.code_base.push(code); - let code_id = (self.code_data.len() + 1) as u64; - let checksum = self.checksum_generator.checksum(&creator, code_id); - self.code_data.push(CodeData { - creator, - checksum, - code_base_id, - }); - code_id + let code_id = self + .next_code_id() + .unwrap_or_else(|| panic!("{}", Error::NoMoreCodeIdAvailable)); + self.save_code(code_id, creator, code) + } + + /// Stores the contract's code in the in-memory lookup table. + /// Returns an identifier of the stored contract code. + fn store_code_with_id( + &mut self, + creator: Addr, + code_id: u64, + code: Box>, + ) -> AnyResult { + // validate provided contract code identifier + if self.code_data.contains_key(&code_id) { + bail!(Error::duplicated_code_id(code_id)); + } else if code_id == 0 { + bail!(Error::invalid_code_id()); + } + Ok(self.save_code(code_id, creator, code)) } /// Duplicates the contract's code with specified identifier. /// Returns an identifier of the copy of the contract's code. fn duplicate_code(&mut self, code_id: u64) -> AnyResult { let code_data = self.code_data(code_id)?; - self.code_data.push(CodeData { - creator: code_data.creator.clone(), - checksum: code_data.checksum, - code_base_id: code_data.code_base_id, - }); - Ok(code_id + 1) + let new_code_id = self + .next_code_id() + .ok_or_else(Error::no_more_code_id_available)?; + self.code_data.insert( + new_code_id, + CodeData { + creator: code_data.creator.clone(), + checksum: code_data.checksum, + source_id: code_data.source_id, + }, + ); + Ok(new_code_id) } /// Returns `ContractData` for the contract with specified address. @@ -282,17 +309,17 @@ impl WasmKeeper { /// Returns a handler to code of the contract with specified code id. pub fn contract_code(&self, code_id: u64) -> AnyResult<&dyn Contract> { let code_data = self.code_data(code_id)?; - Ok(self.code_base[code_data.code_base_id].borrow()) + Ok(self.code_base[code_data.source_id].borrow()) } /// Returns code data of the contract with specified code id. fn code_data(&self, code_id: u64) -> AnyResult<&CodeData> { if code_id < 1 { - bail!(Error::invalid_contract_code_id()); + bail!(Error::invalid_code_id()); } Ok(self .code_data - .get((code_id - 1) as usize) + .get(&code_id) .ok_or_else(|| Error::unregistered_code_id(code_id))?) } @@ -364,6 +391,35 @@ impl WasmKeeper { Ok(response) } + + fn save_code( + &mut self, + code_id: u64, + creator: Addr, + code: Box>, + ) -> u64 { + // prepare the next identifier for the contract 'source' code + let source_id = self.code_base.len(); + // calculate the checksum of the contract 'source' code based on code_id + let checksum = self.checksum_generator.checksum(&creator, code_id); + // store the 'source' code of the contract + self.code_base.push(code); + // store the additional code attributes like creator address and checksum + self.code_data.insert( + code_id, + CodeData { + creator, + checksum, + source_id, + }, + ); + code_id + } + + /// Returns the next code identifier. + fn next_code_id(&self) -> Option { + self.code_data.keys().last().unwrap_or(&0u64).checked_add(1) + } } impl WasmKeeper @@ -432,7 +488,7 @@ where /// # Example /// /// ``` - /// use cosmwasm_std::{Addr, Checksum, HexBinary}; + /// use cosmwasm_std::{Addr, Checksum}; /// use cw_multi_test::{AppBuilder, ChecksumGenerator, no_init, WasmKeeper}; /// /// struct MyChecksumGenerator; diff --git a/tests/test_app_builder/test_with_wasm.rs b/tests/test_app_builder/test_with_wasm.rs index 72dbcd1c..390c8684 100644 --- a/tests/test_app_builder/test_with_wasm.rs +++ b/tests/test_app_builder/test_with_wasm.rs @@ -25,17 +25,6 @@ static WASM_RAW: Lazy> = Lazy::new(|| vec![(vec![154u8], vec![155u8] type MyWasmKeeper = MyKeeper; impl Wasm for MyWasmKeeper { - fn query( - &self, - _api: &dyn Api, - _storage: &dyn Storage, - _querier: &dyn Querier, - _block: &BlockInfo, - _request: WasmQuery, - ) -> AnyResult { - bail!(self.2); - } - fn execute( &self, _api: &dyn Api, @@ -48,6 +37,17 @@ impl Wasm for MyWasmKeeper { bail!(self.1); } + fn query( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + _request: WasmQuery, + ) -> AnyResult { + bail!(self.2); + } + fn sudo( &self, _api: &dyn Api, @@ -63,6 +63,15 @@ impl Wasm for MyWasmKeeper { CODE_ID } + fn store_code_with_id( + &mut self, + _creator: Addr, + code_id: u64, + _code: Box>, + ) -> AnyResult { + Ok(code_id) + } + fn duplicate_code(&mut self, _code_id: u64) -> AnyResult { bail!(DUPLICATE_CODE_MSG); } From 233f550bb7f0beab93aea2e5edda0d55a5fec8d7 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 11:07:51 +0100 Subject: [PATCH 141/250] Refactored store_code test. --- tests/test_app/test_store_code.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_app/test_store_code.rs b/tests/test_app/test_store_code.rs index 76ef3290..5a7204e0 100644 --- a/tests/test_app/test_store_code.rs +++ b/tests/test_app/test_store_code.rs @@ -30,6 +30,6 @@ fn store_code_generates_default_address_for_creator() { // address of the creator should be the default one assert_eq!( MockApi::default().addr_make("creator").as_str(), - code_info_response.creator + code_info_response.creator.as_str() ); } From 77c51425955878cd9889d02061e967a7ab40ccc7 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 11:09:29 +0100 Subject: [PATCH 142/250] Added tests. --- tests/test_app/mod.rs | 3 + tests/test_app/test_store_code.rs | 33 +++++++++ .../test_app/test_store_code_with_creator.rs | 32 +++++++++ tests/test_app/test_store_code_with_id.rs | 67 +++++++++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 tests/test_app/test_store_code.rs create mode 100644 tests/test_app/test_store_code_with_creator.rs create mode 100644 tests/test_app/test_store_code_with_id.rs diff --git a/tests/test_app/mod.rs b/tests/test_app/mod.rs index 340885be..3bcc0d98 100644 --- a/tests/test_app/mod.rs +++ b/tests/test_app/mod.rs @@ -1 +1,4 @@ mod test_instantiate2; +mod test_store_code; +mod test_store_code_with_creator; +mod test_store_code_with_id; diff --git a/tests/test_app/test_store_code.rs b/tests/test_app/test_store_code.rs new file mode 100644 index 00000000..765d0c2f --- /dev/null +++ b/tests/test_app/test_store_code.rs @@ -0,0 +1,33 @@ +use crate::test_contracts::counter; +use cosmwasm_std::testing::MockApi; +use cw_multi_test::App; + +#[test] +fn storing_code_assigns_consecutive_identifiers() { + // prepare the application + let mut app = App::default(); + + // storing contract's code assigns consecutive code identifiers + for i in 1..=10 { + assert_eq!(i, app.store_code(counter::contract())); + } +} + +#[test] +fn store_code_generates_default_address_for_creator() { + // prepare the application + let mut app = App::default(); + + // store contract's code + let code_id = app.store_code(counter::contract()); + assert_eq!(1, code_id); + + // retrieve contract code info + let code_info_response = app.wrap().query_wasm_code_info(code_id).unwrap(); + + // address of the creator should be the default one + assert_eq!( + MockApi::default().addr_make("creator").as_str(), + code_info_response.creator.as_str() + ); +} diff --git a/tests/test_app/test_store_code_with_creator.rs b/tests/test_app/test_store_code_with_creator.rs new file mode 100644 index 00000000..73d469dc --- /dev/null +++ b/tests/test_app/test_store_code_with_creator.rs @@ -0,0 +1,32 @@ +use crate::test_contracts::counter; +use cw_multi_test::{no_init, AppBuilder}; +use cw_multi_test::{MockApiBech32, MockApiBech32m}; + +#[test] +fn store_code_with_custom_creator_address_should_work() { + // prepare the application + let mut app = AppBuilder::default() + .with_api(MockApiBech32m::new("juno")) + .build(no_init); + + let creator = app.api().addr_make("zeus"); + + // store contract's code + let code_id = app.store_code_with_creator(creator, counter::contract()); + assert_eq!(1, code_id); + + // retrieve contract code info + let code_info_response = app.wrap().query_wasm_code_info(code_id).unwrap(); + + // address of the creator should be the custom one in Bech32m format + assert_eq!( + MockApiBech32m::new("juno").addr_make("zeus"), + code_info_response.creator + ); + + // address of the creator should be the custom one but not in Bech32 format + assert_ne!( + MockApiBech32::new("juno").addr_make("zeus"), + code_info_response.creator + ); +} diff --git a/tests/test_app/test_store_code_with_id.rs b/tests/test_app/test_store_code_with_id.rs new file mode 100644 index 00000000..382764b3 --- /dev/null +++ b/tests/test_app/test_store_code_with_id.rs @@ -0,0 +1,67 @@ +use crate::test_contracts::counter; +use cw_multi_test::App; + +#[test] +fn storing_code_with_custom_identifier_should_work() { + let mut app = App::default(); + let creator = app.api().addr_make("prometheus"); + assert_eq!( + 10, + app.store_code_with_id(creator.clone(), 10, counter::contract()) + .unwrap() + ); + assert_eq!( + u64::MAX, + app.store_code_with_id(creator, u64::MAX, counter::contract()) + .unwrap() + ); +} + +#[test] +fn zero_code_id_is_not_allowed() { + let mut app = App::default(); + let creator = app.api().addr_make("prometheus"); + app.store_code_with_id(creator, 0, counter::contract()) + .unwrap_err(); +} + +#[test] +fn storing_code_with_consecutive_identifiers() { + let mut app = App::default(); + let creator = app.api().addr_make("prometheus"); + assert_eq!( + 11, + app.store_code_with_id(creator, 11, counter::contract()) + .unwrap() + ); + for i in 12..=20 { + assert_eq!(i, app.store_code(counter::contract())); + } +} + +#[test] +fn storing_with_the_same_id_is_not_allowed() { + let mut app = App::default(); + let creator = app.api().addr_make("prometheus"); + let code_id = 2056; + assert_eq!( + code_id, + app.store_code_with_id(creator.clone(), code_id, counter::contract()) + .unwrap() + ); + app.store_code_with_id(creator, code_id, counter::contract()) + .unwrap_err(); +} + +#[test] +#[should_panic(expected = "no more code identifiers available")] +fn no_more_identifiers_available() { + let mut app = App::default(); + let creator = app.api().addr_make("prometheus"); + assert_eq!( + u64::MAX, + app.store_code_with_id(creator, u64::MAX, counter::contract()) + .unwrap() + ); + app.store_code(counter::contract()); +} From e32ddb70fcd3a3de12dc8be0eac34f8bcbc694ca Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 11:19:20 +0100 Subject: [PATCH 143/250] Refactored bank module. --- src/bank.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bank.rs b/src/bank.rs index 5b94259a..f3a22c13 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -229,7 +229,7 @@ impl Module for BankKeeper { BankQuery::AllBalances { address } => { let address = api.addr_validate(&address)?; let amount = self.get_balance(&bank_storage, &address)?; - let res = AllBalanceResponse { amount }; + let res = AllBalanceResponse::new(amount); to_json_binary(&res).map_err(Into::into) } BankQuery::Balance { address, denom } => { @@ -239,7 +239,7 @@ impl Module for BankKeeper { .into_iter() .find(|c| c.denom == denom) .unwrap_or_else(|| coin(0, denom)); - let res = BalanceResponse { amount }; + let res = BalanceResponse::new(amount); to_json_binary(&res).map_err(Into::into) } #[cfg(feature = "cosmwasm_1_1")] From 4059fa36b50dda5f15d634b6677d1e6c1785e6f7 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 11:34:28 +0100 Subject: [PATCH 144/250] Fixed doc comment. --- src/executor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/executor.rs b/src/executor.rs index a9cf6769..37131d95 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -53,7 +53,7 @@ impl AppResponse { } } -/// They have the same shape, SubMsgExecutionResponse is what is returned in reply. +/// They have the same shape, SubMsgResponse is what is returned in reply. /// This is just to make some test cases easier. impl From for AppResponse { fn from(reply: SubMsgResponse) -> Self { From 9b936156757d7732676e99e31a7a5d76567152f1 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 11:35:52 +0100 Subject: [PATCH 145/250] Refactored executor. --- src/executor.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/executor.rs b/src/executor.rs index 6aed234a..fa06122d 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -29,7 +29,7 @@ impl AppResponse { /// Checks if there is an Event that is a super-set of this. /// - /// It has the same type, and all compare.attributes are included in it as well. + /// It has the same type, and all compared attributes are included in it as well. /// You don't need to specify them all. pub fn has_event(&self, expected: &Event) -> bool { self.events.iter().any(|ev| { @@ -53,12 +53,13 @@ impl AppResponse { } } -/// They have the same shape, SubMsgExecutionResponse is what is returned in reply. +/// They have the same shape, SubMsgResponse is what is returned in reply. /// This is just to make some test cases easier. impl From for AppResponse { + #[allow(deprecated)] fn from(reply: SubMsgResponse) -> Self { AppResponse { - data: None, + data: reply.data, events: reply.events, } } From 3667efb33b7ff26474df245e0cd97afc38c88c85 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 11:54:34 +0100 Subject: [PATCH 146/250] Refactored staking module. --- src/staking.rs | 62 +++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 894fc84a..663e8a98 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -256,7 +256,7 @@ impl StakeKeeper { Ok(Coin { denom: staking_info.bonded_denom, - amount: Uint128::new(1) * delegator_rewards, // multiplying by 1 to convert Decimal to Uint128 + amount: Uint128::new(1).mul_floor(delegator_rewards), // multiplying by 1 to convert Decimal to Uint128 }) } @@ -362,7 +362,7 @@ impl StakeKeeper { Ok(shares.map(|shares| { Coin { denom: staking_info.bonded_denom, - amount: Uint128::new(1) * shares.stake, // multiplying by 1 to convert Decimal to Uint128 + amount: Uint128::new(1).mul_floor(shares.stake), // multiplying by 1 to convert Decimal to Uint128 } })) } @@ -482,7 +482,7 @@ impl StakeKeeper { .unwrap(); let remaining_percentage = Decimal::one() - percentage; - validator_info.stake = validator_info.stake * remaining_percentage; + validator_info.stake = validator_info.stake.mul_floor(remaining_percentage); // if the stake is completely gone, we clear all stakers and reinitialize the validator if validator_info.stake.is_zero() { @@ -515,7 +515,7 @@ impl StakeKeeper { .iter_mut() .filter(|ub| &ub.validator == validator) .for_each(|ub| { - ub.amount = ub.amount * remaining_percentage; + ub.amount = ub.amount.mul_floor(remaining_percentage); }); UNBONDING_QUEUE.save(staking_storage, &unbonding_queue)?; @@ -757,9 +757,9 @@ impl Module for StakeKeeper { ) -> AnyResult { let staking_storage = prefixed_read(storage, NAMESPACE_STAKING); match request { - StakingQuery::BondedDenom {} => Ok(to_json_binary(&BondedDenomResponse { - denom: Self::get_staking_info(&staking_storage)?.bonded_denom, - })?), + StakingQuery::BondedDenom {} => Ok(to_json_binary(&BondedDenomResponse::new( + Self::get_staking_info(&staking_storage)?.bonded_denom, + ))?), StakingQuery::AllDelegations { delegator } => { let delegator = api.addr_validate(&delegator)?; let validators = self.get_validators(&staking_storage)?; @@ -784,9 +784,7 @@ impl Module for StakeKeeper { }) .collect(); - Ok(to_json_binary(&AllDelegationsResponse { - delegations: res?, - })?) + Ok(to_json_binary(&AllDelegationsResponse::new(res?))?) } StakingQuery::Delegation { delegator, @@ -814,38 +812,36 @@ impl Module for StakeKeeper { let staking_info = Self::get_staking_info(&staking_storage)?; let amount = coin( - (shares.stake * Uint128::new(1)).u128(), + Uint128::new(1).mul_floor(shares.stake).u128(), staking_info.bonded_denom, ); let full_delegation_response = if amount.amount.is_zero() { // no delegation - DelegationResponse { delegation: None } + DelegationResponse::new(None) } else { - DelegationResponse { - delegation: Some(FullDelegation { - delegator, - validator, - amount: amount.clone(), - can_redelegate: amount, // TODO: not implemented right now - accumulated_rewards: if reward.amount.is_zero() { - vec![] - } else { - vec![reward] - }, - }), - } + DelegationResponse::new(Some(FullDelegation { + delegator, + validator, + amount: amount.clone(), + can_redelegate: amount, // TODO: not implemented right now + accumulated_rewards: if reward.amount.is_zero() { + vec![] + } else { + vec![reward] + }, + })) }; let res = to_json_binary(&full_delegation_response)?; Ok(res) } - StakingQuery::AllValidators {} => Ok(to_json_binary(&AllValidatorsResponse { - validators: self.get_validators(&staking_storage)?, - })?), - StakingQuery::Validator { address } => Ok(to_json_binary(&ValidatorResponse { - validator: self.get_validator(&staking_storage, &Addr::unchecked(address))?, - })?), + StakingQuery::AllValidators {} => Ok(to_json_binary(&AllValidatorsResponse::new( + self.get_validators(&staking_storage)?, + ))?), + StakingQuery::Validator { address } => Ok(to_json_binary(&ValidatorResponse::new( + self.get_validator(&staking_storage, &Addr::unchecked(address))?, + ))?), q => bail!("Unsupported staking sudo message: {:?}", q), } } @@ -866,9 +862,7 @@ impl Module for StakeKeeper { let mut staking_storage = prefixed(storage, NAMESPACE_STAKING); let validator = api.addr_validate(&validator)?; self.validate_percentage(percentage)?; - self.slash(api, &mut staking_storage, block, &validator, percentage)?; - Ok(AppResponse::default()) } #[allow(deprecated)] @@ -906,7 +900,7 @@ impl DistributionKeeper { // load updated rewards for delegator let mut shares = STAKES.load(&staking_storage, (delegator, validator))?; - let rewards = Uint128::new(1) * shares.rewards; // convert to Uint128 + let rewards = Uint128::new(1).mul_floor(shares.rewards); // convert to Uint128 // remove rewards from delegator shares.rewards = Decimal::zero(); From 6a2e767bee1db1e4a4d33c4e1481450668cbf8ee Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 11:55:00 +0100 Subject: [PATCH 147/250] Refactored staking module. --- src/staking.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index ff887ccc..67da31a4 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -998,17 +998,6 @@ impl Module for DistributionKeeper { } } - fn sudo( - &self, - _api: &dyn Api, - _storage: &mut dyn Storage, - _router: &dyn CosmosRouter, - _block: &BlockInfo, - _msg: Empty, - ) -> AnyResult { - bail!("Something went wrong - Distribution doesn't have sudo messages") - } - fn query( &self, _api: &dyn Api, @@ -1019,6 +1008,17 @@ impl Module for DistributionKeeper { ) -> AnyResult { bail!("Something went wrong - Distribution doesn't have query messages") } + + fn sudo( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + _msg: Empty, + ) -> AnyResult { + bail!("Something went wrong - Distribution doesn't have sudo messages") + } } #[cfg(test)] From 87de1692bb694a09e78fa3a277ed46e304530636 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 12 Mar 2024 19:34:06 +0100 Subject: [PATCH 148/250] Upgraded dependencies. --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d40da6ac..f9a0f645 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -138,9 +138,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-crypto" -version = "2.0.0-rc.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5188089c28996a446b882b61abb74dc5b90f1a4cfe26e4584a722c5f75ed4f43" +checksum = "3e5fd9485d4f1f4330547a8a5aaf0958c68b4d620975ded2c15f2ed5c49e8e74" dependencies = [ "digest 0.10.7", "ed25519-zebra", @@ -151,18 +151,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "2.0.0-rc.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7436a7247ddcb6125dd55566687e566e7e67b8cbf27f2f9916f4bfb731f9bf4b" +checksum = "d692944045feabbf46c75e8f072024bb885a7742025e40d46913296fe9fbbd06" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "2.0.0-rc.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7877c1debbe8dc6e8026de081c39d357579d5baa5c79d76e4428c1b26013bd38" +checksum = "a67c099aba9e334bbc1fc8037fe8e7ba91d06b215d9ffa7af91893c44aa420c6" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -173,9 +173,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.0.0-rc.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa51536f0c56ac14971576cff2ef4bde35d21eafcb619e16d6e89417d41e85ed" +checksum = "8a2bb09168f6e86bf583361fdb0a0fed2625652e9edcfce731cb55ef4cb8de3d" dependencies = [ "proc-macro2", "quote", @@ -184,9 +184,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "2.0.0-rc.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cb9f0cb520832e993af5cbe97bc3c163bd0c3870989e99d5f1d5499e6f28a53" +checksum = "464f484b3f289935a41e374560c66c59a8f881aefc74742558e42008f1b0b7f3" dependencies = [ "base64", "bech32 0.9.1", diff --git a/Cargo.toml b/Cargo.toml index 41c9f351..5c8775e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ cosmwasm_2_0 = ["cosmwasm-std/cosmwasm_2_0"] [dependencies] anyhow = "1.0.81" bech32 = "0.11.0" -cosmwasm-std = { version = "2.0.0-rc.1", features = ["iterator", "staking", "stargate"] } +cosmwasm-std = { version = "2.0.0", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "2.0.0-rc.0" cw-utils = "2.0.0-rc.0" derivative = "2.2.0" From 53195015b928d02e305ca7a395e83e88ae8ddc41 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 15 Mar 2024 10:24:21 +0100 Subject: [PATCH 149/250] Fixed contract wrapper. --- src/contracts.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/contracts.rs b/src/contracts.rs index 6d7afb21..2e8edab0 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -186,7 +186,7 @@ where /// Populates [ContractWrapper] with contract's `sudo` entry-point and `Empty` as a custom message. pub fn with_sudo_empty( self, - sudo_fn: PermissionedFn, + sudo_fn: PermissionedFn, ) -> ContractWrapper where T4A: DeserializeOwned + 'static, @@ -223,7 +223,7 @@ where /// Populates [ContractWrapper] with contract's `reply` entry-point and `Empty` as a custom message. pub fn with_reply_empty( self, - reply_fn: ReplyFn, + reply_fn: ReplyFn, ) -> ContractWrapper where E5A: Display + Debug + Send + Sync + 'static, @@ -260,7 +260,7 @@ where /// Populates [ContractWrapper] with contract's `migrate` entry-point and `Empty` as a custom message. pub fn with_migrate_empty( self, - migrate_fn: PermissionedFn, + migrate_fn: PermissionedFn, ) -> ContractWrapper where T6A: DeserializeOwned + 'static, @@ -331,7 +331,7 @@ where } fn customize_permissioned_fn( - raw_fn: PermissionedFn, + raw_fn: PermissionedFn, ) -> PermissionedClosure where T: DeserializeOwned + 'static, @@ -339,7 +339,8 @@ where C: CustomMsg + 'static, Q: CustomQuery + DeserializeOwned + 'static, { - let customized = move |deps: DepsMut, env: Env, msg: T| -> Result, E> { + let customized = move |mut deps: DepsMut, env: Env, msg: T| -> Result, E> { + let deps = decustomize_deps_mut(&mut deps); raw_fn(deps, env, msg).map(customize_response::) }; Box::new(customized) From a18a2b64054480d05bdff51a2869b4106286cbc4 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 15 Mar 2024 10:48:32 +0100 Subject: [PATCH 150/250] Fixed contract wrapper. --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- src/contracts.rs | 11 ++++++----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9a0f645..5197e0d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -271,9 +271,9 @@ dependencies = [ [[package]] name = "cw-storage-plus" -version = "2.0.0-rc.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8950902b662b249447c86ddf35b70f83603aedfb5e388434f53fb4aba6a1378" +checksum = "f13360e9007f51998d42b1bc6b7fa0141f74feae61ed5fd1e5b0a89eec7b5de1" dependencies = [ "cosmwasm-std", "schemars", diff --git a/Cargo.toml b/Cargo.toml index 5c8775e2..4d4932a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ cosmwasm_2_0 = ["cosmwasm-std/cosmwasm_2_0"] anyhow = "1.0.81" bech32 = "0.11.0" cosmwasm-std = { version = "2.0.0", features = ["iterator", "staking", "stargate"] } -cw-storage-plus = "2.0.0-rc.0" +cw-storage-plus = "2.0.0" cw-utils = "2.0.0-rc.0" derivative = "2.2.0" itertools = "0.12.1" diff --git a/src/contracts.rs b/src/contracts.rs index 0a0acc49..653246e7 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -186,7 +186,7 @@ where /// Populates [ContractWrapper] with contract's `sudo` entry-point and `Empty` as a custom message. pub fn with_sudo_empty( self, - sudo_fn: PermissionedFn, + sudo_fn: PermissionedFn, ) -> ContractWrapper where T4A: DeserializeOwned + 'static, @@ -223,7 +223,7 @@ where /// Populates [ContractWrapper] with contract's `reply` entry-point and `Empty` as a custom message. pub fn with_reply_empty( self, - reply_fn: ReplyFn, + reply_fn: ReplyFn, ) -> ContractWrapper where E5A: Display + Debug + Send + Sync + 'static, @@ -260,7 +260,7 @@ where /// Populates [ContractWrapper] with contract's `migrate` entry-point and `Empty` as a custom message. pub fn with_migrate_empty( self, - migrate_fn: PermissionedFn, + migrate_fn: PermissionedFn, ) -> ContractWrapper where T6A: DeserializeOwned + 'static, @@ -331,7 +331,7 @@ where } fn customize_permissioned_fn( - raw_fn: PermissionedFn, + raw_fn: PermissionedFn, ) -> PermissionedClosure where T: DeserializeOwned + 'static, @@ -339,7 +339,8 @@ where C: CustomMsg + 'static, Q: CustomQuery + DeserializeOwned + 'static, { - let customized = move |deps: DepsMut, env: Env, msg: T| -> Result, E> { + let customized = move |mut deps: DepsMut, env: Env, msg: T| -> Result, E> { + let deps = decustomize_deps_mut(&mut deps); raw_fn(deps, env, msg).map(customize_response::) }; Box::new(customized) From 22fcb2f2fe8e0df7ebfe355addbd5fa6a9ad12da Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 15 Mar 2024 10:51:35 +0100 Subject: [PATCH 151/250] Bumped version to 2.0.0-rc.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5197e0d1..1186f73c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -250,7 +250,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "2.0.0-rc.1" +version = "2.0.0-rc.2" dependencies = [ "anyhow", "bech32 0.11.0", diff --git a/Cargo.toml b/Cargo.toml index 4d4932a5..7f4ed519 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "2.0.0-rc.1" +version = "2.0.0-rc.2" authors = ["Ethan Frey "] description = "Testing tools for multi-contract interactions" repository = "https://github.com/CosmWasm/cw-multi-test" From be98efb07b13691d59759e381217a2308341c50c Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 15 Mar 2024 10:53:05 +0100 Subject: [PATCH 152/250] Bumped version to 1.0.0-rc.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6bca0ef6..203a637d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -251,7 +251,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "1.0.0-rc.1" +version = "1.0.0-rc.2" dependencies = [ "anyhow", "bech32 0.11.0", diff --git a/Cargo.toml b/Cargo.toml index 93e8ae4e..9371e3bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "1.0.0-rc.1" +version = "1.0.0-rc.2" authors = ["Ethan Frey "] edition = "2021" description = "Testing tools for multi-contract interactions" From 6edcc60a9a8683ae54842a40867c70eb90327fbd Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 15 Mar 2024 13:33:54 +0100 Subject: [PATCH 153/250] Refactored contract wrapper. --- src/contracts.rs | 196 +++++++++++++++++++++++------------------------ 1 file changed, 97 insertions(+), 99 deletions(-) diff --git a/src/contracts.rs b/src/contracts.rs index 2e8edab0..993348af 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -6,81 +6,73 @@ use cosmwasm_std::{ QuerierWrapper, Reply, Response, SubMsg, }; use serde::de::DeserializeOwned; -use std::error::Error; use std::fmt::{Debug, Display}; use std::ops::Deref; -/// Serves as the primary interface for interacting with contracts. -/// -/// It includes methods for executing, querying, and managing contract states, -/// making it a fundamental trait for testing contracts. -pub trait Contract +/// This trait serves as a primary interface for interacting with contracts. +#[rustfmt::skip] +pub trait Contract where - T: CustomMsg, + C: CustomMsg, Q: CustomQuery, { /// Evaluates contract's `execute` entry-point. - fn execute( - &self, - deps: DepsMut, - env: Env, - info: MessageInfo, - msg: Vec, - ) -> AnyResult>; + fn execute(&self, deps: DepsMut, env: Env, info: MessageInfo, msg: Vec) -> AnyResult>; /// Evaluates contract's `instantiate` entry-point. - fn instantiate( - &self, - deps: DepsMut, - env: Env, - info: MessageInfo, - msg: Vec, - ) -> AnyResult>; + fn instantiate(&self, deps: DepsMut, env: Env, info: MessageInfo, msg: Vec) -> AnyResult>; /// Evaluates contract's `query` entry-point. fn query(&self, deps: Deps, env: Env, msg: Vec) -> AnyResult; /// Evaluates contract's `sudo` entry-point. - fn sudo(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult>; + fn sudo(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult>; /// Evaluates contract's `reply` entry-point. - fn reply(&self, deps: DepsMut, env: Env, msg: Reply) -> AnyResult>; + fn reply(&self, deps: DepsMut, env: Env, msg: Reply) -> AnyResult>; /// Evaluates contract's `migrate` entry-point. - fn migrate(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult>; + fn migrate(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult>; } -type ContractFn = - fn(deps: DepsMut, env: Env, info: MessageInfo, msg: T) -> Result, E>; -type PermissionedFn = fn(deps: DepsMut, env: Env, msg: T) -> Result, E>; -type ReplyFn = fn(deps: DepsMut, env: Env, msg: Reply) -> Result, E>; -type QueryFn = fn(deps: Deps, env: Env, msg: T) -> Result; +#[rustfmt::skip] +mod closures { + use super::*; + + // function types + pub type ContractFn = fn(deps: DepsMut, env: Env, info: MessageInfo, msg: T) -> Result, E>; + pub type PermissionedFn = fn(deps: DepsMut, env: Env, msg: T) -> Result, E>; + pub type ReplyFn = fn(deps: DepsMut, env: Env, msg: Reply) -> Result, E>; + pub type QueryFn = fn(deps: Deps, env: Env, msg: T) -> Result; + + // closure types + pub type ContractClosure = Box, Env, MessageInfo, T) -> Result, E>>; + pub type PermissionedClosure = Box, Env, T) -> Result, E>>; + pub type ReplyClosure = Box, Env, Reply) -> Result, E>>; + pub type QueryClosure = Box, Env, T) -> Result>; +} -type ContractClosure = - Box, Env, MessageInfo, T) -> Result, E>>; -type PermissionedClosure = Box, Env, T) -> Result, E>>; -type ReplyClosure = Box, Env, Reply) -> Result, E>>; -type QueryClosure = Box, Env, T) -> Result>; +use closures::*; /// Standardizes interactions with contracts in CosmWasm tests, especially useful for contracts that /// do not possess extensive privileges. It simplifies and unifies the way developers interact with /// different contracts. pub struct ContractWrapper< - T1, - T2, - T3, - E1, - E2, - E3, - C = Empty, - Q = Empty, - T4 = Empty, - E4 = AnyError, - E5 = AnyError, - T6 = Empty, - E6 = AnyError, + T1, // Type of message passed to `execute` entry-point. + T2, // Type of message passed to `instantiate` entry-point. + T3, // Type of message passed to `query` entry-point. + E1, // Type of error returned from `execute` entry-point. + E2, // Type of error returned from `instantiate` entry-point. + E3, // Type of error returned from `query` entry-point. + C = Empty, // Type of custom message returned from all entry-points except `query`. + Q = Empty, // Type of custom query in querier passed as deps/deps_mut to all entry-points. + T4 = Empty, // Type of message passed to `sudo` entry-point. + E4 = AnyError, // Type of error returned from `sudo` entry-point. + E5 = AnyError, // Type of error returned from `reply` entry-point. + T6 = Empty, // Type of message passed to `migrate` entry-point. + E6 = AnyError, // Type of error returned from `migrate` entry-point. > where - T1: DeserializeOwned + Debug, + T1: DeserializeOwned, T2: DeserializeOwned, T3: DeserializeOwned, T4: DeserializeOwned, @@ -104,7 +96,7 @@ pub struct ContractWrapper< impl ContractWrapper where - T1: DeserializeOwned + Debug + 'static, + T1: DeserializeOwned + 'static, T2: DeserializeOwned + 'static, T3: DeserializeOwned + 'static, E1: Display + Debug + Send + Sync + 'static, @@ -137,9 +129,9 @@ where query_fn: QueryFn, ) -> Self { Self { - execute_fn: customize_fn(execute_fn), - instantiate_fn: customize_fn(instantiate_fn), - query_fn: customize_query(query_fn), + execute_fn: customize_contract_fn(execute_fn), + instantiate_fn: customize_contract_fn(instantiate_fn), + query_fn: customize_query_fn(query_fn), sudo_fn: None, reply_fn: None, migrate_fn: None, @@ -150,7 +142,7 @@ where impl ContractWrapper where - T1: DeserializeOwned + Debug + 'static, + T1: DeserializeOwned + 'static, T2: DeserializeOwned + 'static, T3: DeserializeOwned + 'static, T4: DeserializeOwned + 'static, @@ -277,35 +269,56 @@ where } } -fn customize_fn(raw_fn: ContractFn) -> ContractClosure +fn customize_contract_fn( + raw_fn: ContractFn, +) -> ContractClosure where T: DeserializeOwned + 'static, E: Display + Debug + Send + Sync + 'static, C: CustomMsg + 'static, Q: CustomQuery + DeserializeOwned + 'static, { - let customized = move |mut deps: DepsMut, - env: Env, - info: MessageInfo, - msg: T| - -> Result, E> { - let deps = decustomize_deps_mut(&mut deps); - raw_fn(deps, env, info, msg).map(customize_response::) - }; - Box::new(customized) + Box::new( + move |mut deps: DepsMut, + env: Env, + info: MessageInfo, + msg: T| + -> Result, E> { + let deps = decustomize_deps_mut(&mut deps); + raw_fn(deps, env, info, msg).map(customize_response::) + }, + ) +} + +fn customize_query_fn(raw_fn: QueryFn) -> QueryClosure +where + T: DeserializeOwned + 'static, + E: Display + Debug + Send + Sync + 'static, + Q: CustomQuery + DeserializeOwned + 'static, +{ + Box::new( + move |deps: Deps, env: Env, msg: T| -> Result { + let deps = decustomize_deps(&deps); + raw_fn(deps, env, msg) + }, + ) } -fn customize_query(raw_fn: QueryFn) -> QueryClosure +fn customize_permissioned_fn( + raw_fn: PermissionedFn, +) -> PermissionedClosure where T: DeserializeOwned + 'static, E: Display + Debug + Send + Sync + 'static, + C: CustomMsg + 'static, Q: CustomQuery + DeserializeOwned + 'static, { - let customized = move |deps: Deps, env: Env, msg: T| -> Result { - let deps = decustomize_deps(&deps); - raw_fn(deps, env, msg) - }; - Box::new(customized) + Box::new( + move |mut deps: DepsMut, env: Env, msg: T| -> Result, E> { + let deps = decustomize_deps_mut(&mut deps); + raw_fn(deps, env, msg).map(customize_response::) + }, + ) } fn decustomize_deps_mut<'a, Q>(deps: &'a mut DepsMut) -> DepsMut<'a, Empty> @@ -330,22 +343,6 @@ where } } -fn customize_permissioned_fn( - raw_fn: PermissionedFn, -) -> PermissionedClosure -where - T: DeserializeOwned + 'static, - E: Display + Debug + Send + Sync + 'static, - C: CustomMsg + 'static, - Q: CustomQuery + DeserializeOwned + 'static, -{ - let customized = move |mut deps: DepsMut, env: Env, msg: T| -> Result, E> { - let deps = decustomize_deps_mut(&mut deps); - raw_fn(deps, env, msg).map(customize_response::) - }; - Box::new(customized) -} - fn customize_response(resp: Response) -> Response where C: CustomMsg, @@ -382,14 +379,14 @@ where impl Contract for ContractWrapper where - T1: DeserializeOwned + Debug + Clone, - T2: DeserializeOwned + Debug + Clone, - T3: DeserializeOwned + Debug + Clone, + T1: DeserializeOwned, + T2: DeserializeOwned, + T3: DeserializeOwned, T4: DeserializeOwned, T6: DeserializeOwned, - E1: Display + Debug + Send + Sync + Error + 'static, - E2: Display + Debug + Send + Sync + Error + 'static, - E3: Display + Debug + Send + Sync + Error + 'static, + E1: Display + Debug + Send + Sync + 'static, + E2: Display + Debug + Send + Sync + 'static, + E3: Display + Debug + Send + Sync + 'static, E4: Display + Debug + Send + Sync + 'static, E5: Display + Debug + Send + Sync + 'static, E6: Display + Debug + Send + Sync + 'static, @@ -404,7 +401,7 @@ where msg: Vec, ) -> AnyResult> { let msg: T1 = from_json(msg)?; - (self.execute_fn)(deps, env, info, msg).map_err(|err| anyhow!(err)) + (self.execute_fn)(deps, env, info, msg).map_err(|err: E1| anyhow!(err)) } fn instantiate( @@ -415,36 +412,37 @@ where msg: Vec, ) -> AnyResult> { let msg: T2 = from_json(msg)?; - (self.instantiate_fn)(deps, env, info, msg).map_err(|err| anyhow!(err)) + (self.instantiate_fn)(deps, env, info, msg).map_err(|err: E2| anyhow!(err)) } fn query(&self, deps: Deps, env: Env, msg: Vec) -> AnyResult { let msg: T3 = from_json(msg)?; - (self.query_fn)(deps, env, msg).map_err(|err| anyhow!(err)) + (self.query_fn)(deps, env, msg).map_err(|err: E3| anyhow!(err)) } // this returns an error if the contract doesn't implement sudo fn sudo(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult> { - let msg = from_json(msg)?; + let msg: T4 = from_json(msg)?; match &self.sudo_fn { - Some(sudo) => sudo(deps, env, msg).map_err(|err| anyhow!(err)), + Some(sudo) => sudo(deps, env, msg).map_err(|err: E4| anyhow!(err)), None => bail!("sudo not implemented for contract"), } } // this returns an error if the contract doesn't implement reply fn reply(&self, deps: DepsMut, env: Env, reply_data: Reply) -> AnyResult> { + let msg: Reply = reply_data; match &self.reply_fn { - Some(reply) => reply(deps, env, reply_data).map_err(|err| anyhow!(err)), + Some(reply) => reply(deps, env, msg).map_err(|err: E5| anyhow!(err)), None => bail!("reply not implemented for contract"), } } // this returns an error if the contract doesn't implement migrate fn migrate(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult> { - let msg = from_json(msg)?; + let msg: T6 = from_json(msg)?; match &self.migrate_fn { - Some(migrate) => migrate(deps, env, msg).map_err(|err| anyhow!(err)), + Some(migrate) => migrate(deps, env, msg).map_err(|err: E6| anyhow!(err)), None => bail!("migrate not implemented for contract"), } } From c211af8aac5c8e86b5d57e0f81433d0c2bb5b0b6 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 15 Mar 2024 13:48:43 +0100 Subject: [PATCH 154/250] Documented entry point functions. --- src/contracts.rs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/contracts.rs b/src/contracts.rs index 993348af..679ded98 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -393,6 +393,9 @@ where C: CustomMsg, Q: CustomQuery + DeserializeOwned, { + /// Calls [execute] on wrapped [Contract] trait implementor. + /// + /// [execute]: Contract::execute fn execute( &self, deps: DepsMut, @@ -404,6 +407,9 @@ where (self.execute_fn)(deps, env, info, msg).map_err(|err: E1| anyhow!(err)) } + /// Calls [instantiate] on wrapped [Contract] trait implementor. + /// + /// [instantiate]: Contract::instantiate fn instantiate( &self, deps: DepsMut, @@ -415,35 +421,47 @@ where (self.instantiate_fn)(deps, env, info, msg).map_err(|err: E2| anyhow!(err)) } + /// Calls [query] on wrapped [Contract] trait implementor. + /// + /// [query]: Contract::query fn query(&self, deps: Deps, env: Env, msg: Vec) -> AnyResult { let msg: T3 = from_json(msg)?; (self.query_fn)(deps, env, msg).map_err(|err: E3| anyhow!(err)) } - // this returns an error if the contract doesn't implement sudo + /// Calls [sudo] on wrapped [Contract] trait implementor. + /// Returns an error when the contract does not implement [sudo]. + /// + /// [sudo]: Contract::sudo fn sudo(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult> { let msg: T4 = from_json(msg)?; match &self.sudo_fn { Some(sudo) => sudo(deps, env, msg).map_err(|err: E4| anyhow!(err)), - None => bail!("sudo not implemented for contract"), + None => bail!("sudo is not implemented for contract"), } } - // this returns an error if the contract doesn't implement reply + /// Calls [reply] on wrapped [Contract] trait implementor. + /// Returns an error when the contract does not implement [reply]. + /// + /// [reply]: Contract::reply fn reply(&self, deps: DepsMut, env: Env, reply_data: Reply) -> AnyResult> { let msg: Reply = reply_data; match &self.reply_fn { Some(reply) => reply(deps, env, msg).map_err(|err: E5| anyhow!(err)), - None => bail!("reply not implemented for contract"), + None => bail!("reply is not implemented for contract"), } } - // this returns an error if the contract doesn't implement migrate + /// Calls [migrate] on wrapped [Contract] trait implementor. + /// Returns an error when the contract does not implement [migrate]. + /// + /// [migrate]: Contract::migrate fn migrate(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult> { let msg: T6 = from_json(msg)?; match &self.migrate_fn { Some(migrate) => migrate(deps, env, msg).map_err(|err: E6| anyhow!(err)), - None => bail!("migrate not implemented for contract"), + None => bail!("migrate is not implemented for contract"), } } } From 0d401d767434476f09ee34b11fd0431f58f5282d Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 15 Mar 2024 15:46:34 +0100 Subject: [PATCH 155/250] Added source code documentation. --- src/contracts.rs | 197 +++++++++++++++++++++++++++++++---------------- 1 file changed, 131 insertions(+), 66 deletions(-) diff --git a/src/contracts.rs b/src/contracts.rs index 679ded98..d1c4863a 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -1,4 +1,4 @@ -#![allow(clippy::type_complexity)] +//! # Implementation of the contract trait and contract wrapper use crate::error::{anyhow, bail, AnyError, AnyResult}; use cosmwasm_std::{ @@ -54,37 +54,101 @@ mod closures { use closures::*; -/// Standardizes interactions with contracts in CosmWasm tests, especially useful for contracts that -/// do not possess extensive privileges. It simplifies and unifies the way developers interact with -/// different contracts. +/// This structure wraps the [Contract] trait implementor +/// and provides generic access to the contract's entry-points. +/// +/// List of generic types used in [ContractWrapper]: +/// - **T1** type of message passed to [execute] entry-point. +/// - **T2** type of message passed to [instantiate] entry-point. +/// - **T3** type of message passed to [query] entry-point. +/// - **T4** type of message passed to [sudo] entry-point. +/// - instead of **~~T5~~**, always the `Reply` type is used in [reply] entry-point. +/// - **T6** type of message passed to [migrate] entry-point. +/// - **E1** type of error returned from [execute] entry-point. +/// - **E2** type of error returned from [instantiate] entry-point. +/// - **E3** type of error returned from [query] entry-point. +/// - **E4** type of error returned from [sudo] entry-point. +/// - **E5** type of error returned from [reply] entry-point. +/// - **E6** type of error returned from [migrate] entry-point. +/// - **C** type of custom message returned from all entry-points except [query]. +/// - **Q** type of custom query in `Querier` passed as 'Deps' or 'DepsMut' to all entry-points. +/// +/// The following table summarizes the purpose of all generic types used in [ContractWrapper]. +/// ```text +/// ┌─────────────┬────────────────┬─────────────────────┬─────────┬─────────┬───────┬───────┐ +/// │ Contract │ Contract │ │ │ │ │ │ +/// │ entry-point │ wrapper │ Closure type │ Message │ Message │ Error │ Query │ +/// │ │ member │ │ IN │ OUT │ OUT │ │ +/// ╞═════════════╪════════════════╪═════════════════════╪═════════╪═════════╪═══════╪═══════╡ +/// │ (1) │ │ │ │ │ │ │ +/// ╞═════════════╪════════════════╪═════════════════════╪═════════╪═════════╪═══════╪═══════╡ +/// │ execute │ execute_fn │ ContractClosure │ T1 │ C │ E1 │ Q │ +/// ├─────────────┼────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ instantiate │ instantiate_fn │ ContractClosure │ T2 │ C │ E2 │ Q │ +/// ├─────────────┼────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ query │ query_fn │ QueryClosure │ T3 │ Binary │ E3 │ Q │ +/// ├─────────────┼────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ sudo │ sudo_fn │ PermissionedClosure │ T4 │ C │ E4 │ Q │ +/// ├─────────────┼────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ reply │ reply_fn │ ReplyClosure │ Reply │ C │ E5 │ Q │ +/// ├─────────────┼────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ migrate │ migrate_fn │ PermissionedClosure │ T6 │ C │ E6 │ Q │ +/// └─────────────┴────────────────┴─────────────────────┴─────────┴─────────┴───────┴───────┘ +/// ``` +/// The general schema depicting which generic type is used in entry points is shown below. +/// Entry point, when called, is provided minimum two arguments: custom query of type **Q** +/// (inside `Deps` or `DepsMut`) and input message of type **T1**, **T2**, **T3**, **T4**, +/// **Reply** or **T6**. As a result, entry point returns custom output message of type +/// Response<**C**> or **Binary** and an error of type **E1**, **E2**, **E3**, **E4**, **E5** +/// or **E6**. +/// +/// ```text +/// entry_point(query, .., message_in) -> Result +/// ┬ ┬ ┬ ┬ +/// Q >──┘ │ │ └──> E1,E2,E3,E4,E5,E6 +/// T1,T2,T3,T4,Reply,T6 >────┘ └─────────────> C,Binary +/// ``` +/// Generic type **C** defines a custom message that specific for the **whole blockchain**. +/// Similarly, the generic type **Q** defines a custom query that is also specific +/// to the **whole blockchain**. Other generic types a specific to the implemented contract. +/// So all smart contracts used in the same blockchain will have the same types for **C** and **Q**, +/// but each contract may use different type for other generic types. +/// It means that e.g. **T1** in smart contract `A` may differ from **T1** in smart contract `B`. +/// +/// [execute]: Contract::execute +/// [instantiate]: Contract::instantiate +/// [query]: Contract::query +/// [sudo]: Contract::sudo +/// [reply]: Contract::reply +/// [migrate]: Contract::migrate pub struct ContractWrapper< - T1, // Type of message passed to `execute` entry-point. - T2, // Type of message passed to `instantiate` entry-point. - T3, // Type of message passed to `query` entry-point. - E1, // Type of error returned from `execute` entry-point. - E2, // Type of error returned from `instantiate` entry-point. - E3, // Type of error returned from `query` entry-point. - C = Empty, // Type of custom message returned from all entry-points except `query`. - Q = Empty, // Type of custom query in querier passed as deps/deps_mut to all entry-points. - T4 = Empty, // Type of message passed to `sudo` entry-point. - E4 = AnyError, // Type of error returned from `sudo` entry-point. - E5 = AnyError, // Type of error returned from `reply` entry-point. - T6 = Empty, // Type of message passed to `migrate` entry-point. - E6 = AnyError, // Type of error returned from `migrate` entry-point. + T1, + T2, + T3, + E1, + E2, + E3, + C = Empty, + Q = Empty, + T4 = Empty, + E4 = AnyError, + E5 = AnyError, + T6 = Empty, + E6 = AnyError, > where - T1: DeserializeOwned, - T2: DeserializeOwned, - T3: DeserializeOwned, - T4: DeserializeOwned, - T6: DeserializeOwned, - E1: Display + Debug + Send + Sync + 'static, - E2: Display + Debug + Send + Sync + 'static, - E3: Display + Debug + Send + Sync + 'static, - E4: Display + Debug + Send + Sync + 'static, - E5: Display + Debug + Send + Sync + 'static, - E6: Display + Debug + Send + Sync + 'static, - C: CustomMsg, - Q: CustomQuery + DeserializeOwned + 'static, + T1: DeserializeOwned + 'static, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned + 'static, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned + 'static, // Type of message passed to `query` entry-point. + T4: DeserializeOwned + 'static, // Type of message passed to `sudo` entry-point. + T6: DeserializeOwned + 'static, // Type of message passed to `migrate` entry-point. + E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point. + E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point. + E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point. + E4: Display + Debug + Send + Sync + 'static, // Type of error returned from `sudo` entry-point. + E5: Display + Debug + Send + Sync + 'static, // Type of error returned from `reply` entry-point. + E6: Display + Debug + Send + Sync + 'static, // Type of error returned from `migrate` entry-point. + C: CustomMsg + 'static, // Type of custom message returned from all entry-points except `query`. + Q: CustomQuery + DeserializeOwned + 'static, // Type of custom query in querier passed as deps/deps_mut to all entry-points. { execute_fn: ContractClosure, instantiate_fn: ContractClosure, @@ -96,14 +160,14 @@ pub struct ContractWrapper< impl ContractWrapper where - T1: DeserializeOwned + 'static, - T2: DeserializeOwned + 'static, - T3: DeserializeOwned + 'static, - E1: Display + Debug + Send + Sync + 'static, - E2: Display + Debug + Send + Sync + 'static, - E3: Display + Debug + Send + Sync + 'static, - C: CustomMsg + 'static, - Q: CustomQuery + DeserializeOwned + 'static, + T1: DeserializeOwned + 'static, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned + 'static, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned + 'static, // Type of message passed to `query` entry-point. + E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point. + E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point. + E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point. + C: CustomMsg + 'static, // Type of custom message returned from all entry-points except `query`. + Q: CustomQuery + DeserializeOwned + 'static, // Type of custom query in querier passed as deps/deps_mut to all entry-points. { /// Creates a new contract wrapper with default settings. pub fn new( @@ -121,8 +185,8 @@ where } } - /// This will take a contract that returns `Response` and will "upgrade" it - /// to `Response` if needed to be compatible with a chain-specific extension. + /// This will take a contract that returns `Response` and will _upgrade_ it + /// to `Response` if needed, to be compatible with a chain-specific extension. pub fn new_with_empty( execute_fn: ContractFn, instantiate_fn: ContractFn, @@ -139,22 +203,23 @@ where } } +#[allow(clippy::type_complexity)] impl ContractWrapper where - T1: DeserializeOwned + 'static, - T2: DeserializeOwned + 'static, - T3: DeserializeOwned + 'static, - T4: DeserializeOwned + 'static, - T6: DeserializeOwned + 'static, - E1: Display + Debug + Send + Sync + 'static, - E2: Display + Debug + Send + Sync + 'static, - E3: Display + Debug + Send + Sync + 'static, - E4: Display + Debug + Send + Sync + 'static, - E5: Display + Debug + Send + Sync + 'static, - E6: Display + Debug + Send + Sync + 'static, - C: CustomMsg + 'static, - Q: CustomQuery + DeserializeOwned + 'static, + T1: DeserializeOwned + 'static, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned + 'static, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned + 'static, // Type of message passed to `query` entry-point. + T4: DeserializeOwned + 'static, // Type of message passed to `sudo` entry-point. + T6: DeserializeOwned + 'static, // Type of message passed to `migrate` entry-point. + E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point. + E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point. + E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point. + E4: Display + Debug + Send + Sync + 'static, // Type of error returned from `sudo` entry-point. + E5: Display + Debug + Send + Sync + 'static, // Type of error returned from `reply` entry-point. + E6: Display + Debug + Send + Sync + 'static, // Type of error returned from `migrate` entry-point. + C: CustomMsg + 'static, // Type of custom message returned from all entry-points except `query`. + Q: CustomQuery + DeserializeOwned + 'static, // Type of custom query in querier passed as deps/deps_mut to all entry-points. { /// Populates [ContractWrapper] with contract's `sudo` entry-point and custom message type. pub fn with_sudo( @@ -379,19 +444,19 @@ where impl Contract for ContractWrapper where - T1: DeserializeOwned, - T2: DeserializeOwned, - T3: DeserializeOwned, - T4: DeserializeOwned, - T6: DeserializeOwned, - E1: Display + Debug + Send + Sync + 'static, - E2: Display + Debug + Send + Sync + 'static, - E3: Display + Debug + Send + Sync + 'static, - E4: Display + Debug + Send + Sync + 'static, - E5: Display + Debug + Send + Sync + 'static, - E6: Display + Debug + Send + Sync + 'static, - C: CustomMsg, - Q: CustomQuery + DeserializeOwned, + T1: DeserializeOwned + 'static, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned + 'static, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned + 'static, // Type of message passed to `query` entry-point. + T4: DeserializeOwned + 'static, // Type of message passed to `sudo` entry-point. + T6: DeserializeOwned + 'static, // Type of message passed to `migrate` entry-point. + E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point. + E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point. + E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point. + E4: Display + Debug + Send + Sync + 'static, // Type of error returned from `sudo` entry-point. + E5: Display + Debug + Send + Sync + 'static, // Type of error returned from `reply` entry-point. + E6: Display + Debug + Send + Sync + 'static, // Type of error returned from `migrate` entry-point. + C: CustomMsg + 'static, // Type of custom message returned from all entry-points except `query`. + Q: CustomQuery + DeserializeOwned + 'static, // Type of custom query in querier passed as deps/deps_mut to all entry-points. { /// Calls [execute] on wrapped [Contract] trait implementor. /// From ae242c980a66f6d95f60f8eaa99ce1b5984eede4 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 15 Mar 2024 16:30:51 +0100 Subject: [PATCH 156/250] Upgraded dependencies. --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1186f73c..6ef597ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -282,9 +282,9 @@ dependencies = [ [[package]] name = "cw-utils" -version = "2.0.0-rc.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e9dfd846ca70673781742aa739bae515bc833e8cf1c033611288df5067d734" +checksum = "07dfee7f12f802431a856984a32bce1cb7da1e6c006b5409e3981035ce562dec" dependencies = [ "cosmwasm-schema", "cosmwasm-std", diff --git a/Cargo.toml b/Cargo.toml index 7f4ed519..cd537687 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ anyhow = "1.0.81" bech32 = "0.11.0" cosmwasm-std = { version = "2.0.0", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "2.0.0" -cw-utils = "2.0.0-rc.0" +cw-utils = "2.0.0" derivative = "2.2.0" itertools = "0.12.1" prost = "0.12.3" From f3b0ad7856f957341bf2abe11efd88c2a2d00d1b Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 19 Mar 2024 10:55:24 +0100 Subject: [PATCH 157/250] Applied restrictions on custom message. --- Cargo.lock | 10 +++++----- src/app.rs | 3 ++- src/staking.rs | 18 +++++++++--------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 203a637d..d59020aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -617,7 +617,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -736,7 +736,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -830,9 +830,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", @@ -856,7 +856,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] diff --git a/src/app.rs b/src/app.rs index 1d716718..a41fba85 100644 --- a/src/app.rs +++ b/src/app.rs @@ -551,7 +551,7 @@ impl From for SudoMsg { /// correct destinations during testing, simulating real-world blockchain operations. pub trait CosmosRouter { /// Type of the executed custom message. - type ExecC; + type ExecC: CustomMsg; /// Type of the query custom message. type QueryC: CustomQuery; @@ -691,6 +691,7 @@ impl MockRouter { impl CosmosRouter for MockRouter where + ExecC: CustomMsg, QueryC: CustomQuery, { type ExecC = ExecC; diff --git a/src/staking.rs b/src/staking.rs index 663e8a98..e53882b6 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -5,9 +5,9 @@ use crate::prefixed_storage::{prefixed, prefixed_read}; use crate::{BankSudo, Module}; use cosmwasm_std::{ coin, ensure, ensure_eq, to_json_binary, Addr, AllDelegationsResponse, AllValidatorsResponse, - Api, BankMsg, Binary, BlockInfo, BondedDenomResponse, Coin, CustomQuery, Decimal, Delegation, - DelegationResponse, DistributionMsg, Empty, Event, FullDelegation, Querier, StakingMsg, - StakingQuery, Storage, Timestamp, Uint128, Validator, ValidatorResponse, + Api, BankMsg, Binary, BlockInfo, BondedDenomResponse, Coin, CustomMsg, CustomQuery, Decimal, + Delegation, DelegationResponse, DistributionMsg, Empty, Event, FullDelegation, Querier, + StakingMsg, StakingQuery, Storage, Timestamp, Uint128, Validator, ValidatorResponse, }; use cw_storage_plus::{Deque, Item, Map}; use schemars::JsonSchema; @@ -130,7 +130,7 @@ pub trait Staking: Module( + fn process_queue( &self, api: &dyn Api, storage: &mut dyn Storage, @@ -544,7 +544,7 @@ impl StakeKeeper { Ok(()) } - fn process_queue( + fn process_queue( &self, api: &dyn Api, storage: &mut dyn Storage, @@ -613,7 +613,7 @@ impl StakeKeeper { } impl Staking for StakeKeeper { - fn process_queue( + fn process_queue( &self, api: &dyn Api, storage: &mut dyn Storage, @@ -629,7 +629,7 @@ impl Module for StakeKeeper { type QueryT = StakingQuery; type SudoT = StakingSudo; - fn execute( + fn execute( &self, api: &dyn Api, storage: &mut dyn Storage, @@ -846,7 +846,7 @@ impl Module for StakeKeeper { } } - fn sudo( + fn sudo( &self, api: &dyn Api, storage: &mut dyn Storage, @@ -945,7 +945,7 @@ impl Module for DistributionKeeper { type QueryT = Empty; type SudoT = Empty; - fn execute( + fn execute( &self, api: &dyn Api, storage: &mut dyn Storage, From b058bf865a08ad237c41a2b5d25432fe86cae5c9 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 19 Mar 2024 11:23:39 +0100 Subject: [PATCH 158/250] Removed static lifetime from trait bounds. --- src/contracts.rs | 76 ++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/contracts.rs b/src/contracts.rs index d1c4863a..c15586c4 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -136,19 +136,19 @@ pub struct ContractWrapper< T6 = Empty, E6 = AnyError, > where - T1: DeserializeOwned + 'static, // Type of message passed to `execute` entry-point. - T2: DeserializeOwned + 'static, // Type of message passed to `instantiate` entry-point. - T3: DeserializeOwned + 'static, // Type of message passed to `query` entry-point. - T4: DeserializeOwned + 'static, // Type of message passed to `sudo` entry-point. - T6: DeserializeOwned + 'static, // Type of message passed to `migrate` entry-point. - E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point. - E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point. - E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point. - E4: Display + Debug + Send + Sync + 'static, // Type of error returned from `sudo` entry-point. - E5: Display + Debug + Send + Sync + 'static, // Type of error returned from `reply` entry-point. - E6: Display + Debug + Send + Sync + 'static, // Type of error returned from `migrate` entry-point. - C: CustomMsg + 'static, // Type of custom message returned from all entry-points except `query`. - Q: CustomQuery + DeserializeOwned + 'static, // Type of custom query in querier passed as deps/deps_mut to all entry-points. + T1: DeserializeOwned, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned, // Type of message passed to `query` entry-point. + T4: DeserializeOwned, // Type of message passed to `sudo` entry-point. + T6: DeserializeOwned, // Type of message passed to `migrate` entry-point. + E1: Display + Debug + Send + Sync, // Type of error returned from `execute` entry-point. + E2: Display + Debug + Send + Sync, // Type of error returned from `instantiate` entry-point. + E3: Display + Debug + Send + Sync, // Type of error returned from `query` entry-point. + E4: Display + Debug + Send + Sync, // Type of error returned from `sudo` entry-point. + E5: Display + Debug + Send + Sync, // Type of error returned from `reply` entry-point. + E6: Display + Debug + Send + Sync, // Type of error returned from `migrate` entry-point. + C: CustomMsg, // Type of custom message returned from all entry-points except `query`. + Q: CustomQuery + DeserializeOwned, // Type of custom query in querier passed as deps/deps_mut to all entry-points. { execute_fn: ContractClosure, instantiate_fn: ContractClosure, @@ -207,17 +207,17 @@ where impl ContractWrapper where - T1: DeserializeOwned + 'static, // Type of message passed to `execute` entry-point. - T2: DeserializeOwned + 'static, // Type of message passed to `instantiate` entry-point. - T3: DeserializeOwned + 'static, // Type of message passed to `query` entry-point. - T4: DeserializeOwned + 'static, // Type of message passed to `sudo` entry-point. - T6: DeserializeOwned + 'static, // Type of message passed to `migrate` entry-point. - E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point. - E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point. - E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point. - E4: Display + Debug + Send + Sync + 'static, // Type of error returned from `sudo` entry-point. - E5: Display + Debug + Send + Sync + 'static, // Type of error returned from `reply` entry-point. - E6: Display + Debug + Send + Sync + 'static, // Type of error returned from `migrate` entry-point. + T1: DeserializeOwned, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned, // Type of message passed to `query` entry-point. + T4: DeserializeOwned, // Type of message passed to `sudo` entry-point. + T6: DeserializeOwned, // Type of message passed to `migrate` entry-point. + E1: Display + Debug + Send + Sync, // Type of error returned from `execute` entry-point. + E2: Display + Debug + Send + Sync, // Type of error returned from `instantiate` entry-point. + E3: Display + Debug + Send + Sync, // Type of error returned from `query` entry-point. + E4: Display + Debug + Send + Sync, // Type of error returned from `sudo` entry-point. + E5: Display + Debug + Send + Sync, // Type of error returned from `reply` entry-point. + E6: Display + Debug + Send + Sync, // Type of error returned from `migrate` entry-point. C: CustomMsg + 'static, // Type of custom message returned from all entry-points except `query`. Q: CustomQuery + DeserializeOwned + 'static, // Type of custom query in querier passed as deps/deps_mut to all entry-points. { @@ -340,8 +340,8 @@ fn customize_contract_fn( where T: DeserializeOwned + 'static, E: Display + Debug + Send + Sync + 'static, - C: CustomMsg + 'static, - Q: CustomQuery + DeserializeOwned + 'static, + C: CustomMsg, + Q: CustomQuery + DeserializeOwned, { Box::new( move |mut deps: DepsMut, @@ -359,7 +359,7 @@ fn customize_query_fn(raw_fn: QueryFn) -> QueryClosure, env: Env, msg: T| -> Result { @@ -375,8 +375,8 @@ fn customize_permissioned_fn( where T: DeserializeOwned + 'static, E: Display + Debug + Send + Sync + 'static, - C: CustomMsg + 'static, - Q: CustomQuery + DeserializeOwned + 'static, + C: CustomMsg, + Q: CustomQuery + DeserializeOwned, { Box::new( move |mut deps: DepsMut, env: Env, msg: T| -> Result, E> { @@ -388,7 +388,7 @@ where fn decustomize_deps_mut<'a, Q>(deps: &'a mut DepsMut) -> DepsMut<'a, Empty> where - Q: CustomQuery + DeserializeOwned + 'static, + Q: CustomQuery + DeserializeOwned, { DepsMut { storage: deps.storage, @@ -399,7 +399,7 @@ where fn decustomize_deps<'a, Q>(deps: &'a Deps<'a, Q>) -> Deps<'a, Empty> where - Q: CustomQuery + DeserializeOwned + 'static, + Q: CustomQuery + DeserializeOwned, { Deps { storage: deps.storage, @@ -444,19 +444,19 @@ where impl Contract for ContractWrapper where - T1: DeserializeOwned + 'static, // Type of message passed to `execute` entry-point. - T2: DeserializeOwned + 'static, // Type of message passed to `instantiate` entry-point. - T3: DeserializeOwned + 'static, // Type of message passed to `query` entry-point. - T4: DeserializeOwned + 'static, // Type of message passed to `sudo` entry-point. - T6: DeserializeOwned + 'static, // Type of message passed to `migrate` entry-point. + T1: DeserializeOwned, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned, // Type of message passed to `query` entry-point. + T4: DeserializeOwned, // Type of message passed to `sudo` entry-point. + T6: DeserializeOwned, // Type of message passed to `migrate` entry-point. E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point. E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point. E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point. E4: Display + Debug + Send + Sync + 'static, // Type of error returned from `sudo` entry-point. E5: Display + Debug + Send + Sync + 'static, // Type of error returned from `reply` entry-point. E6: Display + Debug + Send + Sync + 'static, // Type of error returned from `migrate` entry-point. - C: CustomMsg + 'static, // Type of custom message returned from all entry-points except `query`. - Q: CustomQuery + DeserializeOwned + 'static, // Type of custom query in querier passed as deps/deps_mut to all entry-points. + C: CustomMsg, // Type of custom message returned from all entry-points except `query`. + Q: CustomQuery + DeserializeOwned, // Type of custom query in querier passed as deps/deps_mut to all entry-points. { /// Calls [execute] on wrapped [Contract] trait implementor. /// From c833cd1aa0d8c3f2e7235bc0f2c7b8d063c2a48d Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 19 Mar 2024 11:33:40 +0100 Subject: [PATCH 159/250] Fixed typo. --- src/contracts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contracts.rs b/src/contracts.rs index c15586c4..5a31b99a 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -108,7 +108,7 @@ use closures::*; /// Q >──┘ │ │ └──> E1,E2,E3,E4,E5,E6 /// T1,T2,T3,T4,Reply,T6 >────┘ └─────────────> C,Binary /// ``` -/// Generic type **C** defines a custom message that specific for the **whole blockchain**. +/// Generic type **C** defines a custom message that is specific for the **whole blockchain**. /// Similarly, the generic type **Q** defines a custom query that is also specific /// to the **whole blockchain**. Other generic types a specific to the implemented contract. /// So all smart contracts used in the same blockchain will have the same types for **C** and **Q**, From 0ce640e8f1ded413edc9f3530150fb4fea71a4d8 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 19 Mar 2024 11:34:20 +0100 Subject: [PATCH 160/250] Fixed typo. --- src/contracts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contracts.rs b/src/contracts.rs index 5a31b99a..128db370 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -110,7 +110,7 @@ use closures::*; /// ``` /// Generic type **C** defines a custom message that is specific for the **whole blockchain**. /// Similarly, the generic type **Q** defines a custom query that is also specific -/// to the **whole blockchain**. Other generic types a specific to the implemented contract. +/// to the **whole blockchain**. Other generic types are specific to the implemented contract. /// So all smart contracts used in the same blockchain will have the same types for **C** and **Q**, /// but each contract may use different type for other generic types. /// It means that e.g. **T1** in smart contract `A` may differ from **T1** in smart contract `B`. From c544ebf6cb6ff41c4aaad603518a6f07c3d29ff0 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 19 Mar 2024 16:56:58 +0100 Subject: [PATCH 161/250] Editorial changes in Cargo.toml --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9371e3bf..d9337791 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,11 +2,11 @@ name = "cw-multi-test" version = "1.0.0-rc.2" authors = ["Ethan Frey "] -edition = "2021" description = "Testing tools for multi-contract interactions" -license = "Apache-2.0" repository = "https://github.com/CosmWasm/cw-multi-test" homepage = "https://cosmwasm.com" +license = "Apache-2.0" +edition = "2021" [features] default = [] From 1dae8d9acdf21061f547c7797439f6a18b3e8784 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 19 Mar 2024 17:02:54 +0100 Subject: [PATCH 162/250] Added doc comments in addresses. --- src/addresses.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/addresses.rs b/src/addresses.rs index 03411e7e..9cc0542f 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -1,4 +1,4 @@ -//! # Implementation of address generators +//! # Implementation of address conversions and generators use crate::error::AnyResult; use crate::{MockApiBech32, MockApiBech32m}; @@ -21,10 +21,12 @@ pub trait IntoAddr { } impl IntoAddr for &str { + /// Converts [&str] into [Addr]. fn into_addr(self) -> Addr { MockApiBech32::new(DEFAULT_PREFIX).addr_make(self) } + /// Converts [&str] into [Addr] with custom prefix. fn into_addr_with_prefix(self, prefix: &'static str) -> Addr { MockApiBech32::new(prefix).addr_make(self) } @@ -40,10 +42,12 @@ pub trait IntoBech32 { } impl IntoBech32 for &str { + /// Converts [&str] into [Addr] containing a string compatible with `Bech32` format with default prefix. fn into_bech32(self) -> Addr { MockApiBech32::new(DEFAULT_PREFIX).addr_make(self) } + /// Converts [&str] into [Addr] containing a string compatible with `Bech32` format with custom prefix. fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr { MockApiBech32::new(prefix).addr_make(self) } @@ -58,10 +62,12 @@ pub trait IntoBech32m { } impl IntoBech32m for &str { + /// Converts [&str] into [Addr] containing a string compatible with `Bech32m` format with default prefix. fn into_bech32m(self) -> Addr { MockApiBech32m::new(DEFAULT_PREFIX).addr_make(self) } + /// Converts [&str] into [Addr] containing a string compatible with `Bech32m` format with custom prefix. fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr { MockApiBech32m::new(prefix).addr_make(self) } From 103cf5de1e2cfc812b47e40b62042a2cd154426e Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 19 Mar 2024 17:11:17 +0100 Subject: [PATCH 163/250] Updated tests. --- src/addresses.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/addresses.rs b/src/addresses.rs index 51838c6d..43ce3a91 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -87,7 +87,7 @@ pub trait AddressGenerator { /// `WasmMsg::Instantiate` message. /// /// The default implementation generates a contract address based - /// on contract's instance identifier only. + /// on contract's code and instance identifier. /// /// # Example /// @@ -103,7 +103,7 @@ pub trait AddressGenerator { /// let my_address_generator = MyAddressGenerator{}; /// /// let addr = my_address_generator.contract_address(&api, &mut storage, 100, 1).unwrap(); - /// assert_eq!(addr.to_string(),"cosmwasm1vlc0q60lwcr89hkkkgj9u360fccw4a2jz48r3dgv0ulmlhgvjczsjfr2pk"); + /// assert!(addr.as_str().starts_with("cosmwasm1")); /// ``` fn contract_address( &self, From 8747bb5e555ffa9af114f2305398149040893ce7 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 19 Mar 2024 17:14:18 +0100 Subject: [PATCH 164/250] Updates doc comment in bank module. --- src/bank.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bank.rs b/src/bank.rs index f3a22c13..804f0d9e 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -23,7 +23,7 @@ const BALANCES: Map<&Addr, NativeBalance> = Map::new("balances"); #[cfg(feature = "cosmwasm_1_3")] const DENOM_METADATA: Map = Map::new("metadata"); -/// Default namespace for bank module. +/// Default storage namespace for bank module. pub const NAMESPACE_BANK: &[u8] = b"bank"; /// A message representing privileged actions in bank module. From ba652acd56f2850bb37c98f7f507e1bf68d3aa10 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 19 Mar 2024 17:16:09 +0100 Subject: [PATCH 165/250] Updated doc comments in checksum module. --- src/checksums.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/checksums.rs b/src/checksums.rs index 994ee79e..1f275902 100644 --- a/src/checksums.rs +++ b/src/checksums.rs @@ -1,4 +1,4 @@ -//! # Implementation of the interface to custom checksum generator +//! # Implementation of checksum generator use cosmwasm_std::{Addr, HexBinary}; use sha2::{Digest, Sha256}; From 32b9244bab008940d7090743915f24cabdb53c6e Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 19 Mar 2024 17:51:38 +0100 Subject: [PATCH 166/250] Added tests. --- tests/test_api/mod.rs | 1 + tests/test_api/test_prefixed.rs | 99 +++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 tests/test_api/test_prefixed.rs diff --git a/tests/test_api/mod.rs b/tests/test_api/mod.rs index e50ddd4e..d429f30f 100644 --- a/tests/test_api/mod.rs +++ b/tests/test_api/mod.rs @@ -4,6 +4,7 @@ use hex_literal::hex; mod test_addr; mod test_bech32; mod test_bech32m; +mod test_prefixed; const SECP256K1_MSG_HASH: [u8; 32] = hex!("5ae8317d34d1e595e3fa7247db80c0af4320cce1116de187f8f7e2e099c0d8d0"); diff --git a/tests/test_api/test_prefixed.rs b/tests/test_api/test_prefixed.rs new file mode 100644 index 00000000..4416a224 --- /dev/null +++ b/tests/test_api/test_prefixed.rs @@ -0,0 +1,99 @@ +use super::*; +use cosmwasm_std::CanonicalAddr; +use cw_multi_test::MockApiBech32; + +const HUMAN_ADDRESS: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"; + +fn api_prefix(prefix: &'static str) -> MockApiBech32 { + MockApiBech32::new(prefix) +} + +fn api_juno() -> MockApiBech32 { + api_prefix("juno") +} + +fn api_osmo() -> MockApiBech32 { + api_prefix("osmo") +} + +#[test] +fn new_api_bech32_should_work() { + let addr = api_juno().addr_make("creator"); + assert_eq!(HUMAN_ADDRESS, addr.as_str(),); +} + +#[test] +fn address_validate_should_work() { + assert_eq!( + api_juno().addr_validate(HUMAN_ADDRESS).unwrap().as_str(), + HUMAN_ADDRESS + ) +} + +#[test] +fn address_validate_invalid_address() { + api_juno().addr_validate("creator").unwrap_err(); +} + +#[test] +fn addr_validate_invalid_prefix() { + api_juno() + .addr_validate(api_osmo().addr_make("creator").as_str()) + .unwrap_err(); +} + +#[test] +fn address_canonicalize_humanize_should_work() { + let api = api_juno(); + assert_eq!( + api.addr_humanize(&api.addr_canonicalize(HUMAN_ADDRESS).unwrap()) + .unwrap() + .as_str(), + HUMAN_ADDRESS + ); +} + +#[test] +fn address_humanize_prefix_too_long() { + api_prefix( + "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", + ) + .addr_humanize(&CanonicalAddr::from([1, 2, 3, 4, 5])) + .unwrap_err(); +} + +#[test] +fn debug_should_not_panic() { + assert_debug_does_not_panic(&api_juno()); +} + +#[test] +#[should_panic( + expected = "Generating address failed with reason: hrp is too long, found 85 characters, must be <= 126" +)] +fn address_make_prefix_too_long() { + api_prefix( + "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", + ) + .addr_make("creator"); +} + +#[test] +fn secp256k1_verify_works() { + assert_secp256k1_verify_works(&api_juno()); +} + +#[test] +fn secp256k1_recover_pubkey_works() { + assert_secp256k1_recover_pubkey_works(&api_juno()); +} + +#[test] +fn ed25519_verify_works() { + assert_ed25519_verify_works(&api_juno()); +} + +#[test] +fn ed25519_batch_verify_works() { + assert_ed25519_batch_verify_works(&api_juno()); +} From 86ade5aa9eaa4f5d6370f6bcca9b57817d927bb0 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 20 Mar 2024 11:18:54 +0100 Subject: [PATCH 167/250] Unified address names. --- src/staking.rs | 58 +++++++++++++++++++++---------------------- src/tests/test_app.rs | 43 ++++++++++++++------------------ src/wasm.rs | 12 ++++----- 3 files changed, 54 insertions(+), 59 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 0bd95488..6f60a77b 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -917,16 +917,16 @@ impl DistributionKeeper { pub fn set_withdraw_address( storage: &mut dyn Storage, delegator: &Addr, - withdraw_address: &Addr, + withdraw_addr: &Addr, ) -> AnyResult<()> { - if delegator == withdraw_address { + if delegator == withdraw_addr { WITHDRAW_ADDRESS.remove(storage, delegator); Ok(()) } else { // technically we should require that this address is not // the address of a module. TODO: how? WITHDRAW_ADDRESS - .save(storage, delegator, withdraw_address) + .save(storage, delegator, withdraw_addr) .map_err(|e| e.into()) } } @@ -1069,7 +1069,7 @@ mod test { let mut store = MockStorage::new(); let block = mock_env().block; - let validator_address = api.addr_make("testvaloper1"); + let validator_addr = api.addr_make("testvaloper1"); router .staking @@ -1085,7 +1085,7 @@ mod test { // add validator let valoper1 = Validator::new( - validator_address.to_string(), + validator_addr.to_string(), validator_commission, Decimal::percent(100), Decimal::percent(1), @@ -1095,7 +1095,7 @@ mod test { .add_validator(&api, &mut store, &block, valoper1) .unwrap(); - (api, store, router, block, validator_address) + (api, store, router, block, validator_addr) } #[test] @@ -1105,11 +1105,11 @@ mod test { let stake = StakeKeeper::default(); let block = mock_env().block; - let validator_address = api.addr_make("test-validator"); + let validator_addr = api.addr_make("test-validator"); // add validator let validator = Validator::new( - validator_address.to_string(), + validator_addr.to_string(), Decimal::percent(10), Decimal::percent(20), Decimal::percent(1), @@ -1121,14 +1121,14 @@ mod test { // get it let staking_storage = prefixed_read(&store, NAMESPACE_STAKING); let val = stake - .get_validator(&staking_storage, &validator_address) + .get_validator(&staking_storage, &validator_addr) .unwrap() .unwrap(); assert_eq!(val, validator); // try to add with same address let validator_fake = Validator::new( - validator_address.to_string(), + validator_addr.to_string(), Decimal::percent(1), Decimal::percent(10), Decimal::percent(100), @@ -1140,7 +1140,7 @@ mod test { // should still be original value let staking_storage = prefixed_read(&store, NAMESPACE_STAKING); let val = stake - .get_validator(&staking_storage, &validator_address) + .get_validator(&staking_storage, &validator_addr) .unwrap() .unwrap(); assert_eq!(val, validator); @@ -1154,12 +1154,12 @@ mod test { let stake = StakeKeeper::new(); let block = mock_env().block; - let delegator_address = api.addr_make("delegator"); - let validator_address = api.addr_make("testvaloper1"); + let delegator_addr = api.addr_make("delegator"); + let validator_addr = api.addr_make("testvaloper1"); // add validator let valoper1 = Validator::new( - validator_address.to_string(), + validator_addr.to_string(), Decimal::percent(10), Decimal::percent(20), Decimal::percent(1), @@ -1175,8 +1175,8 @@ mod test { &api, &mut staking_storage, &block, - &delegator_address, - &validator_address, + &delegator_addr, + &validator_addr, coin(100, "TOKEN"), ) .unwrap(); @@ -1189,7 +1189,7 @@ mod test { &router, &block, StakingSudo::Slash { - validator: validator_address.to_string(), + validator: validator_addr.to_string(), percentage: Decimal::percent(50), }, ) @@ -1198,7 +1198,7 @@ mod test { // check stake let staking_storage = prefixed(&mut store, NAMESPACE_STAKING); let stake_left = stake - .get_stake(&staking_storage, &delegator_address, &validator_address) + .get_stake(&staking_storage, &delegator_addr, &validator_addr) .unwrap(); assert_eq!( stake_left.unwrap().amount.u128(), @@ -1214,7 +1214,7 @@ mod test { &router, &block, StakingSudo::Slash { - validator: validator_address.to_string(), + validator: validator_addr.to_string(), percentage: Decimal::percent(100), }, ) @@ -1223,18 +1223,18 @@ mod test { // check stake let staking_storage = prefixed(&mut store, NAMESPACE_STAKING); let stake_left = stake - .get_stake(&staking_storage, &delegator_address, &validator_address) + .get_stake(&staking_storage, &delegator_addr, &validator_addr) .unwrap(); assert_eq!(stake_left, None, "should have slashed whole stake"); } #[test] fn rewards_work_for_single_delegator() { - let (api, mut store, router, mut block, validator_address) = + let (api, mut store, router, mut block, validator_addr) = setup_test_env(Decimal::percent(10), Decimal::percent(10)); let stake = &router.staking; let distr = &router.distribution; - let delegator_address = api.addr_make("delegator"); + let delegator_addr = api.addr_make("delegator"); let mut staking_storage = prefixed(&mut store, NAMESPACE_STAKING); // stake 200 tokens @@ -1243,8 +1243,8 @@ mod test { &api, &mut staking_storage, &block, - &delegator_address, - &validator_address, + &delegator_addr, + &validator_addr, coin(200, "TOKEN"), ) .unwrap(); @@ -1254,7 +1254,7 @@ mod test { // should now have 200 * 10% / 2 - 10% commission = 9 tokens reward let rewards = stake - .get_rewards(&store, &block, &delegator_address, &validator_address) + .get_rewards(&store, &block, &delegator_addr, &validator_addr) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 9, "should have 9 tokens reward"); @@ -1266,16 +1266,16 @@ mod test { &mut store, &router, &block, - delegator_address.clone(), + delegator_addr.clone(), DistributionMsg::WithdrawDelegatorReward { - validator: validator_address.to_string(), + validator: validator_addr.to_string(), }, ) .unwrap(); // should have no rewards left let rewards = stake - .get_rewards(&store, &block, &delegator_address, &validator_address) + .get_rewards(&store, &block, &delegator_addr, &validator_addr) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 0); @@ -1284,7 +1284,7 @@ mod test { block.time = block.time.plus_seconds(60 * 60 * 24 * 365 / 2); // should now have 9 tokens again let rewards = stake - .get_rewards(&store, &block, &delegator_address, &validator_address) + .get_rewards(&store, &block, &delegator_addr, &validator_addr) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 9); diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index f5dc5351..dc14a31e 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -257,7 +257,7 @@ fn simple_contract() { let msg = payout::InstantiateMessage { payout: coin(5, "eth"), }; - let contract_address = app + let contract_addr = app .instantiate_contract( code_id, owner_addr.clone(), @@ -268,7 +268,7 @@ fn simple_contract() { ) .unwrap(); - let contract_data = app.contract_data(&contract_address).unwrap(); + let contract_data = app.contract_data(&contract_addr).unwrap(); assert_eq!( contract_data, ContractData { @@ -284,22 +284,17 @@ fn simple_contract() { let sender = get_balance(&app, &owner_addr); assert_eq!(sender, vec![coin(20, "btc"), coin(77, "eth")]); // get contract address, has funds - let funds = get_balance(&app, &contract_address); + let funds = get_balance(&app, &contract_addr); assert_eq!(funds, coins(23, "eth")); // create empty account - let random_address = app.api().addr_make("random"); - let funds = get_balance(&app, &random_address); + let random_addr = app.api().addr_make("random"); + let funds = get_balance(&app, &random_addr); assert_eq!(funds, vec![]); // do one payout and see money coming in let res = app - .execute_contract( - random_address.clone(), - contract_address.clone(), - &Empty {}, - &[], - ) + .execute_contract(random_addr.clone(), contract_addr.clone(), &Empty {}, &[]) .unwrap(); assert_eq!(3, res.events.len()); @@ -308,7 +303,7 @@ fn simple_contract() { assert_eq!(payout_exec.ty.as_str(), "execute"); assert_eq!( payout_exec.attributes, - [("_contract_address", &contract_address)] + [("_contract_address", &contract_addr)] ); // next is a custom wasm event @@ -317,16 +312,16 @@ fn simple_contract() { // then the transfer event let expected_transfer = Event::new("transfer") - .add_attribute("recipient", &random_address) - .add_attribute("sender", &contract_address) + .add_attribute("recipient", &random_addr) + .add_attribute("sender", &contract_addr) .add_attribute("amount", "5eth"); assert_eq!(&expected_transfer, &res.events[2]); // random got cash - let funds = get_balance(&app, &random_address); + let funds = get_balance(&app, &random_addr); assert_eq!(funds, coins(5, "eth")); // contract lost it - let funds = get_balance(&app, &contract_address); + let funds = get_balance(&app, &contract_addr); assert_eq!(funds, coins(18, "eth")); } @@ -469,18 +464,18 @@ fn reflect_error() { // reflect has 40 eth let funds = get_balance(&app, &reflect_addr); assert_eq!(funds, coins(40, "eth")); - let random_address = app.api().addr_make("random"); + let random_addr = app.api().addr_make("random"); // sending 7 eth works let msg = SubMsg::new(BankMsg::Send { - to_address: random_address.clone().into(), + to_address: random_addr.clone().into(), amount: coins(7, "eth"), }); let msgs = reflect::Message { messages: vec![msg], }; let res = app - .execute_contract(random_address.clone(), reflect_addr.clone(), &msgs, &[]) + .execute_contract(random_addr.clone(), reflect_addr.clone(), &msgs, &[]) .unwrap(); // no wasm events as no attributes assert_eq!(2, res.events.len()); @@ -493,7 +488,7 @@ fn reflect_error() { assert_eq!(transfer.ty.as_str(), "transfer"); // ensure random got paid - let funds = get_balance(&app, &random_address); + let funds = get_balance(&app, &random_addr); assert_eq!(funds, coins(7, "eth")); // reflect count should be updated to 1 @@ -505,18 +500,18 @@ fn reflect_error() { // sending 8 eth, then 3 btc should fail both let msg = SubMsg::new(BankMsg::Send { - to_address: random_address.clone().into(), + to_address: random_addr.clone().into(), amount: coins(8, "eth"), }); let msg2 = SubMsg::new(BankMsg::Send { - to_address: random_address.clone().into(), + to_address: random_addr.clone().into(), amount: coins(3, "btc"), }); let msgs = reflect::Message { messages: vec![msg, msg2], }; let err = app - .execute_contract(random_address.clone(), reflect_addr.clone(), &msgs, &[]) + .execute_contract(random_addr.clone(), reflect_addr.clone(), &msgs, &[]) .unwrap_err(); assert_eq!( StdError::overflow(OverflowError::new(OverflowOperation::Sub)), @@ -524,7 +519,7 @@ fn reflect_error() { ); // first one should have been rolled-back on error (no second payment) - let funds = get_balance(&app, &random_address); + let funds = get_balance(&app, &random_addr); assert_eq!(funds, coins(7, "eth")); // failure should not update reflect count diff --git a/src/wasm.rs b/src/wasm.rs index ac499fee..eac33116 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -2077,12 +2077,12 @@ mod test { #[test] fn can_use_custom_address_generator() { let api = MockApi::default(); - let expected_address = api.addr_make("address"); - let expected_predictable_address = api.addr_make("predictable_address"); + let expected_addr = api.addr_make("address"); + let expected_predictable_addr = api.addr_make("predictable_address"); let mut wasm_keeper: WasmKeeper = WasmKeeper::new().with_address_generator(TestAddressGenerator { - address: expected_address.clone(), - predictable_address: expected_predictable_address.clone(), + address: expected_addr.clone(), + predictable_address: expected_predictable_addr.clone(), }); let creator = api.addr_make("creator"); let code_id = wasm_keeper.store_code(creator.clone(), payout::contract()); @@ -2104,7 +2104,7 @@ mod test { .unwrap(); assert_eq!( - contract_addr, expected_address, + contract_addr, expected_addr, "custom address generator returned incorrect address" ); @@ -2122,7 +2122,7 @@ mod test { .unwrap(); assert_eq!( - contract_addr, expected_predictable_address, + contract_addr, expected_predictable_addr, "custom address generator returned incorrect address" ); } From 0e0750c3c29d8419f19778d8c2a80f56ba2abd6e Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 20 Mar 2024 13:35:21 +0100 Subject: [PATCH 168/250] Fixes after review. --- src/addresses.rs | 4 ++-- src/executor.rs | 2 +- src/tests/test_app.rs | 6 +++--- src/wasm.rs | 15 ++++++++------- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/addresses.rs b/src/addresses.rs index 43ce3a91..43d49341 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -113,7 +113,7 @@ pub trait AddressGenerator { instance_id: u64, ) -> AnyResult { let canonical_addr = instantiate_address(code_id, instance_id); - Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) + Ok(api.addr_humanize(&canonical_addr)?) } /// Generates a _predictable_ contract address, just like the real-life chain @@ -167,7 +167,7 @@ pub trait AddressGenerator { salt: &[u8], ) -> AnyResult { let canonical_addr = instantiate2_address(checksum, creator, salt)?; - Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) + Ok(api.addr_humanize(&canonical_addr)?) } } diff --git a/src/executor.rs b/src/executor.rs index fa06122d..ed2a5fad 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -56,9 +56,9 @@ impl AppResponse { /// They have the same shape, SubMsgResponse is what is returned in reply. /// This is just to make some test cases easier. impl From for AppResponse { - #[allow(deprecated)] fn from(reply: SubMsgResponse) -> Self { AppResponse { + #[allow(deprecated)] data: reply.data, events: reply.events, } diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index dc14a31e..9868298c 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -4,12 +4,12 @@ use crate::test_helpers::echo::EXECUTE_REPLY_BASE_ID; use crate::test_helpers::{caller, echo, error, hackatom, payout, reflect, CustomHelperMsg}; use crate::transactions::{transactional, StorageTransaction}; use crate::wasm::ContractData; -use crate::AppBuilder; use crate::{ custom_app, next_block, no_init, App, AppResponse, Bank, CosmosRouter, Distribution, Executor, Module, Router, Staking, Wasm, WasmSudo, }; -use cosmwasm_std::testing::{mock_env, MockApi, MockQuerier}; +use crate::{AppBuilder, IntoAddr}; +use cosmwasm_std::testing::{mock_env, MockQuerier}; use cosmwasm_std::{ coin, coins, from_json, to_json_binary, Addr, AllBalanceResponse, Api, Attribute, BankMsg, BankQuery, Binary, BlockInfo, Coin, CosmosMsg, CustomMsg, CustomQuery, Empty, Event, @@ -93,7 +93,7 @@ where /// Utility function for generating user addresses. fn addr_make(addr: &str) -> Addr { - MockApi::default().addr_make(addr) + addr.into_addr() } #[test] diff --git a/src/wasm.rs b/src/wasm.rs index eac33116..d4644c19 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -801,7 +801,6 @@ where /// /// The `data` on `AppResponse` is data returned from `reply` call, not from execution of /// sub-message itself. In case if `reply` is not called, no `data` is set. - #[allow(deprecated)] fn execute_submsg( &self, api: &dyn Api, @@ -827,11 +826,14 @@ where id, payload: Default::default(), gas_used: 0, - result: SubMsgResult::Ok(SubMsgResponse { - events: r.events.clone(), - data: r.data, - msg_responses: vec![], - }), + result: SubMsgResult::Ok( + #[allow(deprecated)] + SubMsgResponse { + events: r.events.clone(), + data: r.data, + msg_responses: vec![], + }, + ), }; // do reply and combine it with the original response let reply_res = self.reply(api, router, storage, block, contract, reply)?; @@ -843,7 +845,6 @@ where // reply is not called, no data should be returned r.data = None; } - Ok(r) } else if let Err(e) = res { if matches!(reply_on, ReplyOn::Always | ReplyOn::Error) { From 7f3be95150b58d71c0893b019191c2d1ee72254b Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 20 Mar 2024 13:45:01 +0100 Subject: [PATCH 169/250] Prepared a branch for releases 1.0.x --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d59020aa..89ffc432 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -251,7 +251,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "1.0.0-rc.2" +version = "1.0.0" dependencies = [ "anyhow", "bech32 0.11.0", diff --git a/Cargo.toml b/Cargo.toml index d9337791..77e0610e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "1.0.0-rc.2" +version = "1.0.0" authors = ["Ethan Frey "] description = "Testing tools for multi-contract interactions" repository = "https://github.com/CosmWasm/cw-multi-test" From 217e3750e0fe07969b90a2ef2d5bb9e6975a961c Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 21 Mar 2024 09:47:41 +0100 Subject: [PATCH 170/250] Reverted version number. --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 89ffc432..d59020aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -251,7 +251,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "1.0.0" +version = "1.0.0-rc.2" dependencies = [ "anyhow", "bech32 0.11.0", diff --git a/Cargo.toml b/Cargo.toml index 77e0610e..d9337791 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "1.0.0" +version = "1.0.0-rc.2" authors = ["Ethan Frey "] description = "Testing tools for multi-contract interactions" repository = "https://github.com/CosmWasm/cw-multi-test" From 67428f65d83e0332193c423b30acbfc332d34481 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 21 Mar 2024 09:51:20 +0100 Subject: [PATCH 171/250] Bumped version number. --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d59020aa..89ffc432 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -251,7 +251,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "1.0.0-rc.2" +version = "1.0.0" dependencies = [ "anyhow", "bech32 0.11.0", diff --git a/Cargo.toml b/Cargo.toml index d9337791..77e0610e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "1.0.0-rc.2" +version = "1.0.0" authors = ["Ethan Frey "] description = "Testing tools for multi-contract interactions" repository = "https://github.com/CosmWasm/cw-multi-test" From 29ce60c6e0705790d714691013e69f0216cea4c1 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 21 Mar 2024 09:58:49 +0100 Subject: [PATCH 172/250] Added co-author. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 77e0610e..b1e85b47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cw-multi-test" version = "1.0.0" -authors = ["Ethan Frey "] +authors = ["Ethan Frey ", "Dariusz Depta "] description = "Testing tools for multi-contract interactions" repository = "https://github.com/CosmWasm/cw-multi-test" homepage = "https://cosmwasm.com" From 05200979df606252eebcfa01cbdc9c9632079770 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 21 Mar 2024 10:51:44 +0100 Subject: [PATCH 173/250] Updated CHANGELOG. --- CHANGELOG.md | 76 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75fc5d19..2b840438 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,37 @@ # Changelog +## [v1.0.0](https://github.com/CosmWasm/cw-multi-test/tree/v1.0.0) (2024-03-22) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.20.1...v1.0.0) + +**Closed issues:** + +- Forward port: Fixing contract wrapper [\#145](https://github.com/CosmWasm/cw-multi-test/issues/145) +- Implement `store_code_with_id` helper [\#22](https://github.com/CosmWasm/cw-multi-test/issues/22) +- New `App::store_code` function definition [\#69](https://github.com/CosmWasm/cw-multi-test/issues/69) (wontfix) +- Make `App::store_code_with_creator` deprecated [\#70](https://github.com/CosmWasm/cw-multi-test/issues/70) (wontfix) +- Remove function `next_address` from `AddressGenerator` trait [\#90](https://github.com/CosmWasm/cw-multi-test/issues/90) +- Remove `new_with_custom_address_generator` function from `WasmKeeper` [\#91](https://github.com/CosmWasm/cw-multi-test/issues/91) + +**Merged pull requests:** + +- Refactored contract wrapper [\#149](https://github.com/CosmWasm/cw-multi-test/pull/149) ([DariuszDepta](https://github.com/DariuszDepta)) +- Fixed contract wrapper [\#148](https://github.com/CosmWasm/cw-multi-test/pull/148) ([DariuszDepta](https://github.com/DariuszDepta)) +- Remove `Addr::unchecked` where possible [\#141](https://github.com/CosmWasm/cw-multi-test/pull/141) ([DariuszDepta](https://github.com/DariuszDepta)) +- Refactored wasm trait [\#139](https://github.com/CosmWasm/cw-multi-test/pull/139) ([DariuszDepta](https://github.com/DariuszDepta)) +- Added `IntoAddr` trait [\#138](https://github.com/CosmWasm/cw-multi-test/pull/138) ([DariuszDepta](https://github.com/DariuszDepta)) +- Removed `new_with_custom_address_generator` function [\#135](https://github.com/CosmWasm/cw-multi-test/pull/135) ([DariuszDepta](https://github.com/DariuszDepta)) +- Removed `next_address` function [\#134](https://github.com/CosmWasm/cw-multi-test/pull/134) ([DariuszDepta](https://github.com/DariuszDepta)) +- Added `store_code_with_id` function to `App` [\#117](https://github.com/CosmWasm/cw-multi-test/pull/117) ([DariuszDepta](https://github.com/DariuszDepta)) + +## [v0.20.1](https://github.com/CosmWasm/cw-multi-test/tree/v0.20.1) (2024-03-15) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.20.0...v0.20.1) + +**Merged pull requests:** + +- Fixed contract wrapper [\#147](https://github.com/CosmWasm/cw-multi-test/pull/147) ([DariuszDepta](https://github.com/DariuszDepta)) + ## [v0.20.0](https://github.com/CosmWasm/cw-multi-test/tree/v0.20.0) (2023-12-06) [Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.19.0...v0.20.0) @@ -85,6 +117,15 @@ - Adds BankQuery::Supply support [\#51](https://github.com/CosmWasm/cw-multi-test/pull/51) ([JakeHartnell](https://github.com/JakeHartnell)) - Remove direct k256 dependencies [\#47](https://github.com/CosmWasm/cw-multi-test/pull/47) ([webmaster128](https://github.com/webmaster128)) +## [v0.16.6](https://github.com/CosmWasm/cw-multi-test/tree/v0.16.6) (2024-03-15) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.16.5...v0.16.6) + +**Merged pull requests:** + +- Fixed contract + wrapper [\#143](https://github.com/CosmWasm/cw-multi-test/pull/143) ([DariuszDepta](https://github.com/DariuszDepta)) + ## [v0.16.5](https://github.com/CosmWasm/cw-multi-test/tree/v0.16.5) (2023-06-07) [Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.16.4...v0.16.5) @@ -148,6 +189,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. ## [v0.16.1](https://github.com/CosmWasm/cw-plus/tree/v0.16.1) (2022-11-23) [Full Changelog](https://github.com/CosmWasm/cw-plus/compare/v0.16.0...v0.16.1) + - Modules for Stargate (IBC and Gov) messages - failing by default, but possible to exchange ## [v0.16.0](https://github.com/CosmWasm/cw-plus/tree/v0.16.0) (2022-10-14) @@ -346,7 +388,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Update changelog add upcoming [\#675](https://github.com/CosmWasm/cw-plus/pull/675) ([maurolacy](https://github.com/maurolacy)) - Reject proposals early [\#668](https://github.com/CosmWasm/cw-plus/pull/668) ([Callum-A](https://github.com/Callum-A)) - cw20-base: validate addresses are unique in initial balances [\#659](https://github.com/CosmWasm/cw-plus/pull/659) ([harryscholes](https://github.com/harryscholes)) -- New SECURITY.md refering to wasmd [\#624](https://github.com/CosmWasm/cw-plus/pull/624) ([ethanfrey](https://github.com/ethanfrey)) +- New SECURITY.md referring to wasmd [\#624](https://github.com/CosmWasm/cw-plus/pull/624) ([ethanfrey](https://github.com/ethanfrey)) ## [v0.13.0](https://github.com/CosmWasm/cw-plus/tree/v0.13.0) (2022-03-09) @@ -406,7 +448,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. **Merged pull requests:** - Prepare release v0.12.0 [\#654](https://github.com/CosmWasm/cw-plus/pull/654) ([uint](https://github.com/uint)) -- Ics20 same ack handling as ibctransfer [\#653](https://github.com/CosmWasm/cw-plus/pull/653) ([ethanfrey](https://github.com/ethanfrey)) +- Ics20 same ack handling as IBC transfer [\#653](https://github.com/CosmWasm/cw-plus/pull/653) ([ethanfrey](https://github.com/ethanfrey)) - packages: support custom queries [\#652](https://github.com/CosmWasm/cw-plus/pull/652) ([uint](https://github.com/uint)) - CW20 - Fix Docs URL [\#649](https://github.com/CosmWasm/cw-plus/pull/649) ([entrancedjames](https://github.com/entrancedjames)) - CW3: Add proposal\_id field to VoteInfo structure [\#648](https://github.com/CosmWasm/cw-plus/pull/648) ([ueco-jb](https://github.com/ueco-jb)) @@ -556,7 +598,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - ics20: Handle send errors with reply [\#520](https://github.com/CosmWasm/cw-plus/pull/520) ([ethanfrey](https://github.com/ethanfrey)) - Proper execute responses [\#519](https://github.com/CosmWasm/cw-plus/pull/519) ([ethanfrey](https://github.com/ethanfrey)) - Publish MsgInstantiate / Execute responses [\#518](https://github.com/CosmWasm/cw-plus/pull/518) ([maurolacy](https://github.com/maurolacy)) -- Fix instaniate reply data [\#517](https://github.com/CosmWasm/cw-plus/pull/517) ([ethanfrey](https://github.com/ethanfrey)) +- Fix instantiate reply data [\#517](https://github.com/CosmWasm/cw-plus/pull/517) ([ethanfrey](https://github.com/ethanfrey)) - Use protobuf de helpers [\#515](https://github.com/CosmWasm/cw-plus/pull/515) ([maurolacy](https://github.com/maurolacy)) - Add tests for the claims controller [\#514](https://github.com/CosmWasm/cw-plus/pull/514) ([sgoya](https://github.com/sgoya)) - Implement cw3-flex-multisig helper [\#479](https://github.com/CosmWasm/cw-plus/pull/479) ([orkunkl](https://github.com/orkunkl)) @@ -575,9 +617,9 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Prepare 0.10.1 release [\#513](https://github.com/CosmWasm/cw-plus/pull/513) ([ethanfrey](https://github.com/ethanfrey)) - Added cw1-whitelist-ng to CI [\#512](https://github.com/CosmWasm/cw-plus/pull/512) ([hashedone](https://github.com/hashedone)) -- cw1-subkeys-ng: Additional follow up improvements [\#506](https://github.com/CosmWasm/cw-plus/pull/506) ([hashedone](https://github.com/hashedone)) +- cw1-subkeys-ng: Additional follow-up improvements [\#506](https://github.com/CosmWasm/cw-plus/pull/506) ([hashedone](https://github.com/hashedone)) - Parse reply helpers [\#502](https://github.com/CosmWasm/cw-plus/pull/502) ([maurolacy](https://github.com/maurolacy)) -- cw1-whitelist-ng: Contract implementation in terms of semantical structures [\#499](https://github.com/CosmWasm/cw-plus/pull/499) ([hashedone](https://github.com/hashedone)) +- cw1-whitelist-ng: Contract implementation in terms of semantic structures [\#499](https://github.com/CosmWasm/cw-plus/pull/499) ([hashedone](https://github.com/hashedone)) - range\_de for IndexMap [\#498](https://github.com/CosmWasm/cw-plus/pull/498) ([uint](https://github.com/uint)) - Implement range\_de for SnapshotMap [\#497](https://github.com/CosmWasm/cw-plus/pull/497) ([uint](https://github.com/uint)) - Fix publish script [\#486](https://github.com/CosmWasm/cw-plus/pull/486) ([ethanfrey](https://github.com/ethanfrey)) @@ -625,7 +667,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Release v0.10.0-soon4 [\#477](https://github.com/CosmWasm/cw-plus/pull/477) ([ethanfrey](https://github.com/ethanfrey)) - Update to CosmWasm 1.0.0-soon2 [\#475](https://github.com/CosmWasm/cw-plus/pull/475) ([ethanfrey](https://github.com/ethanfrey)) - Allow error type conversions in ensure! and ensure\_eq! [\#474](https://github.com/CosmWasm/cw-plus/pull/474) ([webmaster128](https://github.com/webmaster128)) -- Improve error handling / remove FIXMEs [\#470](https://github.com/CosmWasm/cw-plus/pull/470) ([maurolacy](https://github.com/maurolacy)) +- Improve error handling / remove FIXME markers [\#470](https://github.com/CosmWasm/cw-plus/pull/470) ([maurolacy](https://github.com/maurolacy)) - Add ensure [\#469](https://github.com/CosmWasm/cw-plus/pull/469) ([ethanfrey](https://github.com/ethanfrey)) - Key deserializer improvements [\#467](https://github.com/CosmWasm/cw-plus/pull/467) ([maurolacy](https://github.com/maurolacy)) - Upgrade to cosmwasm/workspace-optimizer:0.12.3 [\#465](https://github.com/CosmWasm/cw-plus/pull/465) ([webmaster128](https://github.com/webmaster128)) @@ -676,7 +718,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - storage-plus: Improve in-code documentation of map primitives, in particular `MultiIndex` [\#407](https://github.com/CosmWasm/cw-plus/issues/407) - Remove use of dyn in multitest Router [\#404](https://github.com/CosmWasm/cw-plus/issues/404) - Define generic multitest module [\#387](https://github.com/CosmWasm/cw-plus/issues/387) -- Cw20 state key compatibity with previous versions [\#346](https://github.com/CosmWasm/cw-plus/issues/346) +- Cw20 state key compatibility with previous versions [\#346](https://github.com/CosmWasm/cw-plus/issues/346) - Refactor cw20-base to use controller pattern [\#205](https://github.com/CosmWasm/cw-plus/issues/205) **Merged pull requests:** @@ -732,7 +774,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Snapshot item [\#409](https://github.com/CosmWasm/cw-plus/pull/409) ([maurolacy](https://github.com/maurolacy)) - cw20-base: upgrade helper.ts to cosmjs 0.26.0 [\#406](https://github.com/CosmWasm/cw-plus/pull/406) ([spacepotahto](https://github.com/spacepotahto)) - CW1-whitelist execute multitest [\#402](https://github.com/CosmWasm/cw-plus/pull/402) ([ueco-jb](https://github.com/ueco-jb)) -- Implementing all messages handling in mutlitest App [\#398](https://github.com/CosmWasm/cw-plus/pull/398) ([hashedone](https://github.com/hashedone)) +- Implementing all messages handling in MultiTest App [\#398](https://github.com/CosmWasm/cw-plus/pull/398) ([hashedone](https://github.com/hashedone)) - Make it easier to assert events on reply statements [\#395](https://github.com/CosmWasm/cw-plus/pull/395) ([ethanfrey](https://github.com/ethanfrey)) - Add helpers to check events [\#392](https://github.com/CosmWasm/cw-plus/pull/392) ([ethanfrey](https://github.com/ethanfrey)) - Switching from String to anyhow::Error for error type in multi-test [\#389](https://github.com/CosmWasm/cw-plus/pull/389) ([hashedone](https://github.com/hashedone)) @@ -805,7 +847,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Responses validation in multi-test [\#373](https://github.com/CosmWasm/cw-plus/pull/373) ([hashedone](https://github.com/hashedone)) - Cw20 logo spec [\#370](https://github.com/CosmWasm/cw-plus/pull/370) ([ethanfrey](https://github.com/ethanfrey)) - Properly handling data in submessages in multi-test [\#369](https://github.com/CosmWasm/cw-plus/pull/369) ([hashedone](https://github.com/hashedone)) -- Abstracting API out of tests internals so it is clearly owned by `App` [\#368](https://github.com/CosmWasm/cw-plus/pull/368) ([hashedone](https://github.com/hashedone)) +- Abstracting API out of tests internals, so it is clearly owned by `App` [\#368](https://github.com/CosmWasm/cw-plus/pull/368) ([hashedone](https://github.com/hashedone)) - Storage plus doc correction [\#367](https://github.com/CosmWasm/cw-plus/pull/367) ([hashedone](https://github.com/hashedone)) - Multitest migrate support [\#366](https://github.com/CosmWasm/cw-plus/pull/366) ([ethanfrey](https://github.com/ethanfrey)) - Reorganizations of contracts in `multi-test::test_utils` [\#365](https://github.com/CosmWasm/cw-plus/pull/365) ([hashedone](https://github.com/hashedone)) @@ -858,7 +900,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Proper event/data handling on reply in multitest [\#326](https://github.com/CosmWasm/cw-plus/issues/326) - Messages differ for cw20 & cw20\_base [\#320](https://github.com/CosmWasm/cw-plus/issues/320) - Upgrade cw20-staking to cw 15 [\#312](https://github.com/CosmWasm/cw-plus/issues/312) -- Uprade cw20-ics20 to cw 0.15 [\#311](https://github.com/CosmWasm/cw-plus/issues/311) +- Upgrade cw20-ics20 to cw 0.15 [\#311](https://github.com/CosmWasm/cw-plus/issues/311) - Upgrade cw20-escrow to 0.15 [\#309](https://github.com/CosmWasm/cw-plus/issues/309) - Upgrade cw20-bonding to 0.15 [\#307](https://github.com/CosmWasm/cw-plus/issues/307) - cw1-subkeys [\#305](https://github.com/CosmWasm/cw-plus/issues/305) @@ -928,7 +970,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. **Merged pull requests:** - Clarify index\_key\(\) range\(\) vs prefix\(\) behaviour [\#291](https://github.com/CosmWasm/cw-plus/pull/291) ([maurolacy](https://github.com/maurolacy)) -- Pkowned to vec u8 [\#290](https://github.com/CosmWasm/cw-plus/pull/290) ([maurolacy](https://github.com/maurolacy)) +- PkOwned to vec u8 [\#290](https://github.com/CosmWasm/cw-plus/pull/290) ([maurolacy](https://github.com/maurolacy)) - Update to CosmWasm v0.14.0 [\#289](https://github.com/CosmWasm/cw-plus/pull/289) ([ethanfrey](https://github.com/ethanfrey)) - Primary key / index key helpers [\#288](https://github.com/CosmWasm/cw-plus/pull/288) ([maurolacy](https://github.com/maurolacy)) @@ -978,7 +1020,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. **Merged pull requests:** -- Bump dependency to cosmasm v0.14.0-beta3 [\#269](https://github.com/CosmWasm/cw-plus/pull/269) ([ethanfrey](https://github.com/ethanfrey)) +- Bump dependency to cosmwasm v0.14.0-beta3 [\#269](https://github.com/CosmWasm/cw-plus/pull/269) ([ethanfrey](https://github.com/ethanfrey)) - Remove unused PrimaryKey::parse\_key [\#267](https://github.com/CosmWasm/cw-plus/pull/267) ([webmaster128](https://github.com/webmaster128)) - Use workspace-optimizer:0.11.0 [\#262](https://github.com/CosmWasm/cw-plus/pull/262) ([webmaster128](https://github.com/webmaster128)) - Update cosmwasm-std [\#260](https://github.com/CosmWasm/cw-plus/pull/260) ([yihuang](https://github.com/yihuang)) @@ -1089,7 +1131,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Don't use hooks for snapshotting on cw3-cw4 interface [\#162](https://github.com/CosmWasm/cw-plus/issues/162) - Refactor snapshotting into reusable module [\#161](https://github.com/CosmWasm/cw-plus/issues/161) - Distinguish between weight 0 and not member in cw3 queries [\#154](https://github.com/CosmWasm/cw-plus/issues/154) -- Migrate strorage-plus to v0.12.0 [\#149](https://github.com/CosmWasm/cw-plus/issues/149) +- Migrate storage-plus to v0.12.0 [\#149](https://github.com/CosmWasm/cw-plus/issues/149) - Asymmetries between query and execute in CW1 \(subkeys\) [\#145](https://github.com/CosmWasm/cw-plus/issues/145) - Add token-weighted group [\#142](https://github.com/CosmWasm/cw-plus/issues/142) - Multisig handles changes to group membership [\#141](https://github.com/CosmWasm/cw-plus/issues/141) @@ -1197,7 +1239,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. **Closed issues:** -- Migration to 0.11: errors of shared functions accross contracts [\#103](https://github.com/CosmWasm/cw-plus/issues/103) +- Migration to 0.11: errors of shared functions across contracts [\#103](https://github.com/CosmWasm/cw-plus/issues/103) - Look at serde\(flatten\) to simplify return value composition [\#57](https://github.com/CosmWasm/cw-plus/issues/57) **Merged pull requests:** @@ -1239,7 +1281,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. **Closed issues:** - Implement Copy for Coin / Vec\ [\#77](https://github.com/CosmWasm/cw-plus/issues/77) -- Why does not cw20 pass the received native token? [\#74](https://github.com/CosmWasm/cw-plus/issues/74) +- Why cw20 does not pass the received native token? [\#74](https://github.com/CosmWasm/cw-plus/issues/74) - Cw20Coin duplication [\#73](https://github.com/CosmWasm/cw-plus/issues/73) - Fix docker run script in all contract README [\#69](https://github.com/CosmWasm/cw-plus/issues/69) - Add cw20 support to atomic swap contract [\#27](https://github.com/CosmWasm/cw-plus/issues/27) @@ -1292,7 +1334,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Bump all CosmWasm dependencies to 0.10.1 [\#56](https://github.com/CosmWasm/cw-plus/pull/56) ([ethanfrey](https://github.com/ethanfrey)) - Add new query to return all allowances on subkeys [\#54](https://github.com/CosmWasm/cw-plus/pull/54) ([ethanfrey](https://github.com/ethanfrey)) - Add CanSend query to the cw1 spec [\#53](https://github.com/CosmWasm/cw-plus/pull/53) ([ethanfrey](https://github.com/ethanfrey)) -- Add Expration to cw0 [\#51](https://github.com/CosmWasm/cw-plus/pull/51) ([ethanfrey](https://github.com/ethanfrey)) +- Add expiration to cw0 [\#51](https://github.com/CosmWasm/cw-plus/pull/51) ([ethanfrey](https://github.com/ethanfrey)) - Nft 721 spec [\#50](https://github.com/CosmWasm/cw-plus/pull/50) ([ethanfrey](https://github.com/ethanfrey)) - Add Subkeys helper [\#49](https://github.com/CosmWasm/cw-plus/pull/49) ([ethanfrey](https://github.com/ethanfrey)) - Add helpers to cw20-base [\#46](https://github.com/CosmWasm/cw-plus/pull/46) ([ethanfrey](https://github.com/ethanfrey)) @@ -1348,6 +1390,4 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Define all Message and Query types [\#11](https://github.com/CosmWasm/cw-plus/pull/11) ([ethanfrey](https://github.com/ethanfrey)) - Set up basic CI script [\#10](https://github.com/CosmWasm/cw-plus/pull/10) ([ethanfrey](https://github.com/ethanfrey)) - - \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* From ea7b3e767fbf30001c15d333a2548962374af4a9 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 21 Mar 2024 10:58:59 +0100 Subject: [PATCH 174/250] Bumped version number. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cd537687..14011f79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "2.0.0-rc.2" +version = "2.0.0" authors = ["Ethan Frey "] description = "Testing tools for multi-contract interactions" repository = "https://github.com/CosmWasm/cw-multi-test" From ee02a0b93551c23e7a581ad0e2ab33d1abfbf418 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 21 Mar 2024 11:01:37 +0100 Subject: [PATCH 175/250] Added co-author. --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3ac89382..401c81eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -250,7 +250,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "2.0.0-rc.2" +version = "2.0.0" dependencies = [ "anyhow", "bech32 0.11.0", diff --git a/Cargo.toml b/Cargo.toml index 14011f79..87c83cbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cw-multi-test" version = "2.0.0" -authors = ["Ethan Frey "] +authors = ["Ethan Frey ", "Dariusz Depta "] description = "Testing tools for multi-contract interactions" repository = "https://github.com/CosmWasm/cw-multi-test" homepage = "https://cosmwasm.com" From f9a8955e4668a2aac17e638b82e493b0179b86f4 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 21 Mar 2024 11:09:15 +0100 Subject: [PATCH 176/250] Updated CHANGELOG. --- CHANGELOG.md | 89 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75fc5d19..2b023d50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,50 @@ # Changelog +## [v2.0.0](https://github.com/CosmWasm/cw-multi-test/tree/v2.0.0) (2024-03-22) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v1.0.0...v2.0.0) + +**Closed issues:** + +- Forward port: Fixing contract wrapper [\#146](https://github.com/CosmWasm/cw-multi-test/issues/146) +- Forward port: `store_code_with_id` helper [#131](https://github.com/CosmWasm/cw-multi-test/issues/131) + +**Merged pull requests:** + +- V2: upgrading dependencies and refactoring [\#128](https://github.com/CosmWasm/cw-multi-test/pull/128) ([DariuszDepta](https://github.com/DariuszDepta)) + +## [v1.0.0](https://github.com/CosmWasm/cw-multi-test/tree/v1.0.0) (2024-03-22) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.20.1...v1.0.0) + +**Closed issues:** + +- Forward port: Fixing contract wrapper [\#145](https://github.com/CosmWasm/cw-multi-test/issues/145) +- Implement `store_code_with_id` helper [\#22](https://github.com/CosmWasm/cw-multi-test/issues/22) +- New `App::store_code` function definition [\#69](https://github.com/CosmWasm/cw-multi-test/issues/69) (wontfix) +- Make `App::store_code_with_creator` deprecated [\#70](https://github.com/CosmWasm/cw-multi-test/issues/70) (wontfix) +- Remove function `next_address` from `AddressGenerator` trait [\#90](https://github.com/CosmWasm/cw-multi-test/issues/90) +- Remove `new_with_custom_address_generator` function from `WasmKeeper` [\#91](https://github.com/CosmWasm/cw-multi-test/issues/91) + +**Merged pull requests:** + +- Refactored contract wrapper [\#149](https://github.com/CosmWasm/cw-multi-test/pull/149) ([DariuszDepta](https://github.com/DariuszDepta)) +- Fixed contract wrapper [\#148](https://github.com/CosmWasm/cw-multi-test/pull/148) ([DariuszDepta](https://github.com/DariuszDepta)) +- Remove `Addr::unchecked` where possible [\#141](https://github.com/CosmWasm/cw-multi-test/pull/141) ([DariuszDepta](https://github.com/DariuszDepta)) +- Refactored wasm trait [\#139](https://github.com/CosmWasm/cw-multi-test/pull/139) ([DariuszDepta](https://github.com/DariuszDepta)) +- Added `IntoAddr` trait [\#138](https://github.com/CosmWasm/cw-multi-test/pull/138) ([DariuszDepta](https://github.com/DariuszDepta)) +- Removed `new_with_custom_address_generator` function [\#135](https://github.com/CosmWasm/cw-multi-test/pull/135) ([DariuszDepta](https://github.com/DariuszDepta)) +- Removed `next_address` function [\#134](https://github.com/CosmWasm/cw-multi-test/pull/134) ([DariuszDepta](https://github.com/DariuszDepta)) +- Added `store_code_with_id` function to `App` [\#117](https://github.com/CosmWasm/cw-multi-test/pull/117) ([DariuszDepta](https://github.com/DariuszDepta)) + +## [v0.20.1](https://github.com/CosmWasm/cw-multi-test/tree/v0.20.1) (2024-03-15) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.20.0...v0.20.1) + +**Merged pull requests:** + +- Fixed contract wrapper [\#147](https://github.com/CosmWasm/cw-multi-test/pull/147) ([DariuszDepta](https://github.com/DariuszDepta)) + ## [v0.20.0](https://github.com/CosmWasm/cw-multi-test/tree/v0.20.0) (2023-12-06) [Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.19.0...v0.20.0) @@ -85,6 +130,15 @@ - Adds BankQuery::Supply support [\#51](https://github.com/CosmWasm/cw-multi-test/pull/51) ([JakeHartnell](https://github.com/JakeHartnell)) - Remove direct k256 dependencies [\#47](https://github.com/CosmWasm/cw-multi-test/pull/47) ([webmaster128](https://github.com/webmaster128)) +## [v0.16.6](https://github.com/CosmWasm/cw-multi-test/tree/v0.16.6) (2024-03-15) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.16.5...v0.16.6) + +**Merged pull requests:** + +- Fixed contract + wrapper [\#143](https://github.com/CosmWasm/cw-multi-test/pull/143) ([DariuszDepta](https://github.com/DariuszDepta)) + ## [v0.16.5](https://github.com/CosmWasm/cw-multi-test/tree/v0.16.5) (2023-06-07) [Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.16.4...v0.16.5) @@ -148,6 +202,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. ## [v0.16.1](https://github.com/CosmWasm/cw-plus/tree/v0.16.1) (2022-11-23) [Full Changelog](https://github.com/CosmWasm/cw-plus/compare/v0.16.0...v0.16.1) + - Modules for Stargate (IBC and Gov) messages - failing by default, but possible to exchange ## [v0.16.0](https://github.com/CosmWasm/cw-plus/tree/v0.16.0) (2022-10-14) @@ -346,7 +401,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Update changelog add upcoming [\#675](https://github.com/CosmWasm/cw-plus/pull/675) ([maurolacy](https://github.com/maurolacy)) - Reject proposals early [\#668](https://github.com/CosmWasm/cw-plus/pull/668) ([Callum-A](https://github.com/Callum-A)) - cw20-base: validate addresses are unique in initial balances [\#659](https://github.com/CosmWasm/cw-plus/pull/659) ([harryscholes](https://github.com/harryscholes)) -- New SECURITY.md refering to wasmd [\#624](https://github.com/CosmWasm/cw-plus/pull/624) ([ethanfrey](https://github.com/ethanfrey)) +- New SECURITY.md referring to wasmd [\#624](https://github.com/CosmWasm/cw-plus/pull/624) ([ethanfrey](https://github.com/ethanfrey)) ## [v0.13.0](https://github.com/CosmWasm/cw-plus/tree/v0.13.0) (2022-03-09) @@ -406,7 +461,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. **Merged pull requests:** - Prepare release v0.12.0 [\#654](https://github.com/CosmWasm/cw-plus/pull/654) ([uint](https://github.com/uint)) -- Ics20 same ack handling as ibctransfer [\#653](https://github.com/CosmWasm/cw-plus/pull/653) ([ethanfrey](https://github.com/ethanfrey)) +- Ics20 same ack handling as IBC transfer [\#653](https://github.com/CosmWasm/cw-plus/pull/653) ([ethanfrey](https://github.com/ethanfrey)) - packages: support custom queries [\#652](https://github.com/CosmWasm/cw-plus/pull/652) ([uint](https://github.com/uint)) - CW20 - Fix Docs URL [\#649](https://github.com/CosmWasm/cw-plus/pull/649) ([entrancedjames](https://github.com/entrancedjames)) - CW3: Add proposal\_id field to VoteInfo structure [\#648](https://github.com/CosmWasm/cw-plus/pull/648) ([ueco-jb](https://github.com/ueco-jb)) @@ -556,7 +611,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - ics20: Handle send errors with reply [\#520](https://github.com/CosmWasm/cw-plus/pull/520) ([ethanfrey](https://github.com/ethanfrey)) - Proper execute responses [\#519](https://github.com/CosmWasm/cw-plus/pull/519) ([ethanfrey](https://github.com/ethanfrey)) - Publish MsgInstantiate / Execute responses [\#518](https://github.com/CosmWasm/cw-plus/pull/518) ([maurolacy](https://github.com/maurolacy)) -- Fix instaniate reply data [\#517](https://github.com/CosmWasm/cw-plus/pull/517) ([ethanfrey](https://github.com/ethanfrey)) +- Fix instantiate reply data [\#517](https://github.com/CosmWasm/cw-plus/pull/517) ([ethanfrey](https://github.com/ethanfrey)) - Use protobuf de helpers [\#515](https://github.com/CosmWasm/cw-plus/pull/515) ([maurolacy](https://github.com/maurolacy)) - Add tests for the claims controller [\#514](https://github.com/CosmWasm/cw-plus/pull/514) ([sgoya](https://github.com/sgoya)) - Implement cw3-flex-multisig helper [\#479](https://github.com/CosmWasm/cw-plus/pull/479) ([orkunkl](https://github.com/orkunkl)) @@ -575,9 +630,9 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Prepare 0.10.1 release [\#513](https://github.com/CosmWasm/cw-plus/pull/513) ([ethanfrey](https://github.com/ethanfrey)) - Added cw1-whitelist-ng to CI [\#512](https://github.com/CosmWasm/cw-plus/pull/512) ([hashedone](https://github.com/hashedone)) -- cw1-subkeys-ng: Additional follow up improvements [\#506](https://github.com/CosmWasm/cw-plus/pull/506) ([hashedone](https://github.com/hashedone)) +- cw1-subkeys-ng: Additional follow-up improvements [\#506](https://github.com/CosmWasm/cw-plus/pull/506) ([hashedone](https://github.com/hashedone)) - Parse reply helpers [\#502](https://github.com/CosmWasm/cw-plus/pull/502) ([maurolacy](https://github.com/maurolacy)) -- cw1-whitelist-ng: Contract implementation in terms of semantical structures [\#499](https://github.com/CosmWasm/cw-plus/pull/499) ([hashedone](https://github.com/hashedone)) +- cw1-whitelist-ng: Contract implementation in terms of semantic structures [\#499](https://github.com/CosmWasm/cw-plus/pull/499) ([hashedone](https://github.com/hashedone)) - range\_de for IndexMap [\#498](https://github.com/CosmWasm/cw-plus/pull/498) ([uint](https://github.com/uint)) - Implement range\_de for SnapshotMap [\#497](https://github.com/CosmWasm/cw-plus/pull/497) ([uint](https://github.com/uint)) - Fix publish script [\#486](https://github.com/CosmWasm/cw-plus/pull/486) ([ethanfrey](https://github.com/ethanfrey)) @@ -625,7 +680,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Release v0.10.0-soon4 [\#477](https://github.com/CosmWasm/cw-plus/pull/477) ([ethanfrey](https://github.com/ethanfrey)) - Update to CosmWasm 1.0.0-soon2 [\#475](https://github.com/CosmWasm/cw-plus/pull/475) ([ethanfrey](https://github.com/ethanfrey)) - Allow error type conversions in ensure! and ensure\_eq! [\#474](https://github.com/CosmWasm/cw-plus/pull/474) ([webmaster128](https://github.com/webmaster128)) -- Improve error handling / remove FIXMEs [\#470](https://github.com/CosmWasm/cw-plus/pull/470) ([maurolacy](https://github.com/maurolacy)) +- Improve error handling / remove FIXME markers [\#470](https://github.com/CosmWasm/cw-plus/pull/470) ([maurolacy](https://github.com/maurolacy)) - Add ensure [\#469](https://github.com/CosmWasm/cw-plus/pull/469) ([ethanfrey](https://github.com/ethanfrey)) - Key deserializer improvements [\#467](https://github.com/CosmWasm/cw-plus/pull/467) ([maurolacy](https://github.com/maurolacy)) - Upgrade to cosmwasm/workspace-optimizer:0.12.3 [\#465](https://github.com/CosmWasm/cw-plus/pull/465) ([webmaster128](https://github.com/webmaster128)) @@ -676,7 +731,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - storage-plus: Improve in-code documentation of map primitives, in particular `MultiIndex` [\#407](https://github.com/CosmWasm/cw-plus/issues/407) - Remove use of dyn in multitest Router [\#404](https://github.com/CosmWasm/cw-plus/issues/404) - Define generic multitest module [\#387](https://github.com/CosmWasm/cw-plus/issues/387) -- Cw20 state key compatibity with previous versions [\#346](https://github.com/CosmWasm/cw-plus/issues/346) +- Cw20 state key compatibility with previous versions [\#346](https://github.com/CosmWasm/cw-plus/issues/346) - Refactor cw20-base to use controller pattern [\#205](https://github.com/CosmWasm/cw-plus/issues/205) **Merged pull requests:** @@ -732,7 +787,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Snapshot item [\#409](https://github.com/CosmWasm/cw-plus/pull/409) ([maurolacy](https://github.com/maurolacy)) - cw20-base: upgrade helper.ts to cosmjs 0.26.0 [\#406](https://github.com/CosmWasm/cw-plus/pull/406) ([spacepotahto](https://github.com/spacepotahto)) - CW1-whitelist execute multitest [\#402](https://github.com/CosmWasm/cw-plus/pull/402) ([ueco-jb](https://github.com/ueco-jb)) -- Implementing all messages handling in mutlitest App [\#398](https://github.com/CosmWasm/cw-plus/pull/398) ([hashedone](https://github.com/hashedone)) +- Implementing all messages handling in MultiTest App [\#398](https://github.com/CosmWasm/cw-plus/pull/398) ([hashedone](https://github.com/hashedone)) - Make it easier to assert events on reply statements [\#395](https://github.com/CosmWasm/cw-plus/pull/395) ([ethanfrey](https://github.com/ethanfrey)) - Add helpers to check events [\#392](https://github.com/CosmWasm/cw-plus/pull/392) ([ethanfrey](https://github.com/ethanfrey)) - Switching from String to anyhow::Error for error type in multi-test [\#389](https://github.com/CosmWasm/cw-plus/pull/389) ([hashedone](https://github.com/hashedone)) @@ -805,7 +860,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Responses validation in multi-test [\#373](https://github.com/CosmWasm/cw-plus/pull/373) ([hashedone](https://github.com/hashedone)) - Cw20 logo spec [\#370](https://github.com/CosmWasm/cw-plus/pull/370) ([ethanfrey](https://github.com/ethanfrey)) - Properly handling data in submessages in multi-test [\#369](https://github.com/CosmWasm/cw-plus/pull/369) ([hashedone](https://github.com/hashedone)) -- Abstracting API out of tests internals so it is clearly owned by `App` [\#368](https://github.com/CosmWasm/cw-plus/pull/368) ([hashedone](https://github.com/hashedone)) +- Abstracting API out of tests internals, so it is clearly owned by `App` [\#368](https://github.com/CosmWasm/cw-plus/pull/368) ([hashedone](https://github.com/hashedone)) - Storage plus doc correction [\#367](https://github.com/CosmWasm/cw-plus/pull/367) ([hashedone](https://github.com/hashedone)) - Multitest migrate support [\#366](https://github.com/CosmWasm/cw-plus/pull/366) ([ethanfrey](https://github.com/ethanfrey)) - Reorganizations of contracts in `multi-test::test_utils` [\#365](https://github.com/CosmWasm/cw-plus/pull/365) ([hashedone](https://github.com/hashedone)) @@ -858,7 +913,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Proper event/data handling on reply in multitest [\#326](https://github.com/CosmWasm/cw-plus/issues/326) - Messages differ for cw20 & cw20\_base [\#320](https://github.com/CosmWasm/cw-plus/issues/320) - Upgrade cw20-staking to cw 15 [\#312](https://github.com/CosmWasm/cw-plus/issues/312) -- Uprade cw20-ics20 to cw 0.15 [\#311](https://github.com/CosmWasm/cw-plus/issues/311) +- Upgrade cw20-ics20 to cw 0.15 [\#311](https://github.com/CosmWasm/cw-plus/issues/311) - Upgrade cw20-escrow to 0.15 [\#309](https://github.com/CosmWasm/cw-plus/issues/309) - Upgrade cw20-bonding to 0.15 [\#307](https://github.com/CosmWasm/cw-plus/issues/307) - cw1-subkeys [\#305](https://github.com/CosmWasm/cw-plus/issues/305) @@ -928,7 +983,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. **Merged pull requests:** - Clarify index\_key\(\) range\(\) vs prefix\(\) behaviour [\#291](https://github.com/CosmWasm/cw-plus/pull/291) ([maurolacy](https://github.com/maurolacy)) -- Pkowned to vec u8 [\#290](https://github.com/CosmWasm/cw-plus/pull/290) ([maurolacy](https://github.com/maurolacy)) +- PkOwned to vec u8 [\#290](https://github.com/CosmWasm/cw-plus/pull/290) ([maurolacy](https://github.com/maurolacy)) - Update to CosmWasm v0.14.0 [\#289](https://github.com/CosmWasm/cw-plus/pull/289) ([ethanfrey](https://github.com/ethanfrey)) - Primary key / index key helpers [\#288](https://github.com/CosmWasm/cw-plus/pull/288) ([maurolacy](https://github.com/maurolacy)) @@ -978,7 +1033,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. **Merged pull requests:** -- Bump dependency to cosmasm v0.14.0-beta3 [\#269](https://github.com/CosmWasm/cw-plus/pull/269) ([ethanfrey](https://github.com/ethanfrey)) +- Bump dependency to cosmwasm v0.14.0-beta3 [\#269](https://github.com/CosmWasm/cw-plus/pull/269) ([ethanfrey](https://github.com/ethanfrey)) - Remove unused PrimaryKey::parse\_key [\#267](https://github.com/CosmWasm/cw-plus/pull/267) ([webmaster128](https://github.com/webmaster128)) - Use workspace-optimizer:0.11.0 [\#262](https://github.com/CosmWasm/cw-plus/pull/262) ([webmaster128](https://github.com/webmaster128)) - Update cosmwasm-std [\#260](https://github.com/CosmWasm/cw-plus/pull/260) ([yihuang](https://github.com/yihuang)) @@ -1089,7 +1144,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Don't use hooks for snapshotting on cw3-cw4 interface [\#162](https://github.com/CosmWasm/cw-plus/issues/162) - Refactor snapshotting into reusable module [\#161](https://github.com/CosmWasm/cw-plus/issues/161) - Distinguish between weight 0 and not member in cw3 queries [\#154](https://github.com/CosmWasm/cw-plus/issues/154) -- Migrate strorage-plus to v0.12.0 [\#149](https://github.com/CosmWasm/cw-plus/issues/149) +- Migrate storage-plus to v0.12.0 [\#149](https://github.com/CosmWasm/cw-plus/issues/149) - Asymmetries between query and execute in CW1 \(subkeys\) [\#145](https://github.com/CosmWasm/cw-plus/issues/145) - Add token-weighted group [\#142](https://github.com/CosmWasm/cw-plus/issues/142) - Multisig handles changes to group membership [\#141](https://github.com/CosmWasm/cw-plus/issues/141) @@ -1197,7 +1252,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. **Closed issues:** -- Migration to 0.11: errors of shared functions accross contracts [\#103](https://github.com/CosmWasm/cw-plus/issues/103) +- Migration to 0.11: errors of shared functions across contracts [\#103](https://github.com/CosmWasm/cw-plus/issues/103) - Look at serde\(flatten\) to simplify return value composition [\#57](https://github.com/CosmWasm/cw-plus/issues/57) **Merged pull requests:** @@ -1239,7 +1294,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. **Closed issues:** - Implement Copy for Coin / Vec\ [\#77](https://github.com/CosmWasm/cw-plus/issues/77) -- Why does not cw20 pass the received native token? [\#74](https://github.com/CosmWasm/cw-plus/issues/74) +- Why cw20 does not pass the received native token? [\#74](https://github.com/CosmWasm/cw-plus/issues/74) - Cw20Coin duplication [\#73](https://github.com/CosmWasm/cw-plus/issues/73) - Fix docker run script in all contract README [\#69](https://github.com/CosmWasm/cw-plus/issues/69) - Add cw20 support to atomic swap contract [\#27](https://github.com/CosmWasm/cw-plus/issues/27) @@ -1292,7 +1347,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Bump all CosmWasm dependencies to 0.10.1 [\#56](https://github.com/CosmWasm/cw-plus/pull/56) ([ethanfrey](https://github.com/ethanfrey)) - Add new query to return all allowances on subkeys [\#54](https://github.com/CosmWasm/cw-plus/pull/54) ([ethanfrey](https://github.com/ethanfrey)) - Add CanSend query to the cw1 spec [\#53](https://github.com/CosmWasm/cw-plus/pull/53) ([ethanfrey](https://github.com/ethanfrey)) -- Add Expration to cw0 [\#51](https://github.com/CosmWasm/cw-plus/pull/51) ([ethanfrey](https://github.com/ethanfrey)) +- Add expiration to cw0 [\#51](https://github.com/CosmWasm/cw-plus/pull/51) ([ethanfrey](https://github.com/ethanfrey)) - Nft 721 spec [\#50](https://github.com/CosmWasm/cw-plus/pull/50) ([ethanfrey](https://github.com/ethanfrey)) - Add Subkeys helper [\#49](https://github.com/CosmWasm/cw-plus/pull/49) ([ethanfrey](https://github.com/ethanfrey)) - Add helpers to cw20-base [\#46](https://github.com/CosmWasm/cw-plus/pull/46) ([ethanfrey](https://github.com/ethanfrey)) @@ -1348,6 +1403,4 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Define all Message and Query types [\#11](https://github.com/CosmWasm/cw-plus/pull/11) ([ethanfrey](https://github.com/ethanfrey)) - Set up basic CI script [\#10](https://github.com/CosmWasm/cw-plus/pull/10) ([ethanfrey](https://github.com/ethanfrey)) - - \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* From da33f6379b00c7036bcb8ea7a96bb026da1bb73b Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 22 Mar 2024 09:55:01 +0100 Subject: [PATCH 177/250] Prepared a test case. --- Cargo.lock | 4 +- tests/mod.rs | 34 ++++++------- tests/test_app_builder/test_with_storage.rs | 3 +- tests/test_contract_storage/mod.rs | 56 +++++++++++++++++++++ 4 files changed, 76 insertions(+), 21 deletions(-) create mode 100644 tests/test_contract_storage/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 401c81eb..16b642a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,9 +39,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "95d8e92cac0961e91dbd517496b00f7e9b92363dbe6d42c3198268323798860c" dependencies = [ "addr2line", "cc", diff --git a/tests/mod.rs b/tests/mod.rs index f5370608..de502f44 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -1,37 +1,35 @@ #![cfg(test)] -use cw_storage_plus::Item; -use serde::{Deserialize, Serialize}; - mod test_api; mod test_app; mod test_app_builder; +mod test_contract_storage; mod test_module; mod test_wasm; -const COUNTER: Item = Item::new("count"); - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -enum CounterQueryMsg { - Counter {}, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -struct CounterResponseMsg { - value: u64, -} - mod test_contracts { - use super::*; pub mod counter { - use super::*; use cosmwasm_std::{ to_json_binary, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError, WasmMsg, }; use cw_multi_test::{Contract, ContractWrapper}; + use cw_storage_plus::Item; + use serde::{Deserialize, Serialize}; + + const COUNTER: Item = Item::new("count"); + + #[derive(Debug, Clone, Serialize, Deserialize)] + #[serde(rename_all = "snake_case")] + pub enum CounterQueryMsg { + Counter {}, + } + + #[derive(Debug, Clone, Serialize, Deserialize)] + pub struct CounterResponseMsg { + pub value: u64, + } fn instantiate( deps: DepsMut, diff --git a/tests/test_app_builder/test_with_storage.rs b/tests/test_app_builder/test_with_storage.rs index 72f8998f..3290f9c1 100644 --- a/tests/test_app_builder/test_with_storage.rs +++ b/tests/test_app_builder/test_with_storage.rs @@ -1,4 +1,5 @@ -use crate::{test_contracts, CounterQueryMsg, CounterResponseMsg}; +use crate::test_contracts; +use crate::test_contracts::counter::{CounterQueryMsg, CounterResponseMsg}; use cosmwasm_std::{to_json_binary, Empty, Order, Record, Storage, WasmMsg}; use cw_multi_test::{no_init, AppBuilder, Executor}; use std::collections::BTreeMap; diff --git a/tests/test_contract_storage/mod.rs b/tests/test_contract_storage/mod.rs new file mode 100644 index 00000000..116fefc5 --- /dev/null +++ b/tests/test_contract_storage/mod.rs @@ -0,0 +1,56 @@ +use crate::test_contracts::counter; +use crate::test_contracts::counter::{CounterQueryMsg, CounterResponseMsg}; +use cosmwasm_std::{to_json_binary, Empty, WasmMsg}; +use cw_multi_test::{App, Executor}; + +#[test] +fn read_write_contract_storage_should_work() { + // prepare the blockchain + let mut app = App::default(); + + // store the contract code + let creator_addr = app.api().addr_make("creator"); + let code_id = app.store_code_with_creator(creator_addr, counter::contract()); + assert_eq!(1, code_id); + + // instantiate a new contract + let owner_addr = app.api().addr_make("owner"); + let contract_addr = app + .instantiate_contract(code_id, owner_addr.clone(), &Empty {}, &[], "counter", None) + .unwrap(); + assert!(contract_addr.as_str().starts_with("cosmwasm1")); + + // `counter` contract should return value 1 after instantiation + let query_res: CounterResponseMsg = app + .wrap() + .query_wasm_smart(&contract_addr, &CounterQueryMsg::Counter {}) + .unwrap(); + assert_eq!(1, query_res.value); + + // execute `counter` contract - this increments a counter with one + let execute_msg = WasmMsg::Execute { + contract_addr: contract_addr.clone().into(), + msg: to_json_binary(&Empty {}).unwrap(), + funds: vec![], + }; + app.execute_contract(owner_addr, contract_addr.clone(), &execute_msg, &[]) + .unwrap(); + + // now the `counter` contract should return value 2 + let query_res: CounterResponseMsg = app + .wrap() + .query_wasm_smart(&contract_addr, &CounterQueryMsg::Counter {}) + .unwrap(); + assert_eq!(2, query_res.value); + + // change the contract storage, set a value to 100 + // TODO + + // now the `counter` contract should return value 100 + let query_res: CounterResponseMsg = app + .wrap() + .query_wasm_smart(&contract_addr, &CounterQueryMsg::Counter {}) + .unwrap(); + assert_eq!(2, query_res.value); + // TODO assert_eq!(100, query_res.value); +} From ae8d30cdef18204785ebfbc81cc9e3b5d8cc4ee3 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 22 Mar 2024 14:05:33 +0100 Subject: [PATCH 178/250] Exposed contract storage in App. --- src/app.rs | 32 ++++++++----- src/wasm.rs | 72 +++++++++++++++--------------- tests/mod.rs | 2 +- tests/test_contract_storage/mod.rs | 28 ++++++++++-- 4 files changed, 84 insertions(+), 50 deletions(-) diff --git a/src/app.rs b/src/app.rs index a4008827..aed75edc 100644 --- a/src/app.rs +++ b/src/app.rs @@ -255,11 +255,9 @@ where /// 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 { - self.init_modules(|router, _, _| { - router - .wasm - .store_code(MockApi::default().addr_make("creator"), code) - }) + self.router + .wasm + .store_code(MockApi::default().addr_make("creator"), code) } /// Registers contract code (like [store_code](Self::store_code)), @@ -269,7 +267,7 @@ where creator: Addr, code: Box>, ) -> u64 { - self.init_modules(|router, _, _| router.wasm.store_code(creator, code)) + self.router.wasm.store_code(creator, code) } /// Registers contract code (like [store_code_with_creator](Self::store_code_with_creator)), @@ -280,7 +278,7 @@ where code_id: u64, code: Box>, ) -> AnyResult { - self.init_modules(|router, _, _| router.wasm.store_code_with_id(creator, code_id, code)) + self.router.wasm.store_code_with_id(creator, code_id, code) } /// Duplicates the contract code identified by `code_id` and returns @@ -333,17 +331,31 @@ where /// assert_eq!("code id 100: no such code", app.duplicate_code(100).unwrap_err().to_string()); /// ``` pub fn duplicate_code(&mut self, code_id: u64) -> AnyResult { - self.init_modules(|router, _, _| router.wasm.duplicate_code(code_id)) + self.router.wasm.duplicate_code(code_id) } /// Returns `ContractData` for the contract with specified address. pub fn contract_data(&self, address: &Addr) -> AnyResult { - self.read_module(|router, _, storage| router.wasm.contract_data(storage, address)) + self.router.wasm.contract_data(&self.storage, address) } /// Returns a raw state dump of all key-values held by a contract with specified address. pub fn dump_wasm_raw(&self, address: &Addr) -> Vec { - self.read_module(|router, _, storage| router.wasm.dump_wasm_raw(storage, address)) + self.router.wasm.dump_wasm_raw(&self.storage, address) + } + + /// Returns **read-only** storage for a contract with specified address. + pub fn contract_storage<'a>(&'a self, contract_addr: &Addr) -> Box { + self.router + .wasm + .contract_storage(&self.storage, contract_addr) + } + + /// Returns **read-write** storage for a contract with specified address. + pub fn contract_storage_mut<'a>(&'a mut self, contract_addr: &Addr) -> Box { + self.router + .wasm + .contract_storage_mut(&mut self.storage, contract_addr) } } diff --git a/src/wasm.rs b/src/wasm.rs index d4644c19..35bf331b 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -134,6 +134,39 @@ pub trait Wasm { /// Returns a raw state dump of all key-values held by a contract with specified address. fn dump_wasm_raw(&self, storage: &dyn Storage, address: &Addr) -> Vec; + + /// Returns the namespace of the contract storage. + fn contract_namespace(&self, contract: &Addr) -> Vec { + let mut name = b"contract_data/".to_vec(); + name.extend_from_slice(contract.as_bytes()); + name + } + + /// Returns **read-only** (not mutable) contract storage. + fn contract_storage<'a>( + &self, + storage: &'a dyn Storage, + address: &Addr, + ) -> Box { + // We double-namespace this, once from global storage -> wasm_storage + // then from wasm_storage -> the contracts subspace + let namespace = self.contract_namespace(address); + let storage = ReadonlyPrefixedStorage::multilevel(storage, &[NAMESPACE_WASM, &namespace]); + Box::new(storage) + } + + /// Returns **read-write** (mutable) contract storage. + fn contract_storage_mut<'a>( + &self, + storage: &'a mut dyn Storage, + address: &Addr, + ) -> Box { + // We double-namespace this, once from global storage -> wasm_storage + // then from wasm_storage -> the contracts subspace + let namespace = self.contract_namespace(address); + let storage = PrefixedStorage::multilevel(storage, &[NAMESPACE_WASM, &namespace]); + Box::new(storage) + } } /// A structure representing a default wasm keeper. @@ -300,7 +333,7 @@ where /// Returns a raw state dump of all key-values held by a contract with specified address. fn dump_wasm_raw(&self, storage: &dyn Storage, address: &Addr) -> Vec { - let storage = self.contract_storage_readonly(storage, address); + let storage = self.contract_storage(storage, address); storage.range(None, None, Order::Ascending).collect() } } @@ -323,37 +356,6 @@ impl WasmKeeper { .ok_or_else(|| Error::unregistered_code_id(code_id))?) } - fn contract_namespace(&self, contract: &Addr) -> Vec { - let mut name = b"contract_data/".to_vec(); - name.extend_from_slice(contract.as_bytes()); - name - } - - fn contract_storage<'a>( - &self, - storage: &'a mut dyn Storage, - address: &Addr, - ) -> Box { - // We double-namespace this, once from global storage -> wasm_storage - // then from wasm_storage -> the contracts subspace - let namespace = self.contract_namespace(address); - let storage = PrefixedStorage::multilevel(storage, &[NAMESPACE_WASM, &namespace]); - Box::new(storage) - } - - // fails RUNTIME if you try to write. please don't - fn contract_storage_readonly<'a>( - &self, - storage: &'a dyn Storage, - address: &Addr, - ) -> Box { - // We double-namespace this, once from global storage -> wasm_storage - // then from wasm_storage -> the contracts subspace - let namespace = self.contract_namespace(address); - let storage = ReadonlyPrefixedStorage::multilevel(storage, &[NAMESPACE_WASM, &namespace]); - Box::new(storage) - } - fn verify_attributes(attributes: &[Attribute]) -> AnyResult<()> { for attr in attributes { let key = attr.key.trim(); @@ -536,7 +538,7 @@ where /// Returns the value stored under specified key in contracts storage. pub fn query_raw(&self, address: Addr, storage: &dyn Storage, key: &[u8]) -> Binary { - let storage = self.contract_storage_readonly(storage, &address); + let storage = self.contract_storage(storage, &address); let data = storage.get(key).unwrap_or_default(); data.into() } @@ -1140,7 +1142,7 @@ where { let contract = self.contract_data(storage, &address)?; let handler = self.contract_code(contract.code_id)?; - let storage = self.contract_storage_readonly(storage, &address); + let storage = self.contract_storage(storage, &address); let env = self.get_env(address, block); let deps = Deps { @@ -1172,7 +1174,7 @@ where // However, we need to get write and read access to the same storage in two different objects, // and this is the only way I know how to do so. transactional(storage, |write_cache, read_store| { - let mut contract_storage = self.contract_storage(write_cache, &address); + let mut contract_storage = self.contract_storage_mut(write_cache, &address); let querier = RouterQuerier::new(router, api, read_store, block); let env = self.get_env(address, block); diff --git a/tests/mod.rs b/tests/mod.rs index de502f44..dbae92ed 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -18,7 +18,7 @@ mod test_contracts { use cw_storage_plus::Item; use serde::{Deserialize, Serialize}; - const COUNTER: Item = Item::new("count"); + const COUNTER: Item = Item::new("counter"); #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] diff --git a/tests/test_contract_storage/mod.rs b/tests/test_contract_storage/mod.rs index 116fefc5..1ac55bb4 100644 --- a/tests/test_contract_storage/mod.rs +++ b/tests/test_contract_storage/mod.rs @@ -2,9 +2,13 @@ use crate::test_contracts::counter; use crate::test_contracts::counter::{CounterQueryMsg, CounterResponseMsg}; use cosmwasm_std::{to_json_binary, Empty, WasmMsg}; use cw_multi_test::{App, Executor}; +use cw_storage_plus::Item; #[test] fn read_write_contract_storage_should_work() { + // counter value saved in contract state + const COUNTER: Item = Item::new("counter"); + // prepare the blockchain let mut app = App::default(); @@ -27,6 +31,13 @@ fn read_write_contract_storage_should_work() { .unwrap(); assert_eq!(1, query_res.value); + { + // read the counter value directly from contract storage + let storage = app.contract_storage(&contract_addr); + let value = COUNTER.load(&*storage).unwrap(); + assert_eq!(1, value); + } + // execute `counter` contract - this increments a counter with one let execute_msg = WasmMsg::Execute { contract_addr: contract_addr.clone().into(), @@ -43,14 +54,23 @@ fn read_write_contract_storage_should_work() { .unwrap(); assert_eq!(2, query_res.value); - // change the contract storage, set a value to 100 - // TODO + { + // read the counter value directly from contract storage + let storage = app.contract_storage(&contract_addr); + let value = COUNTER.load(&*storage).unwrap(); + assert_eq!(2, value); + } + + { + // write the counter value directly into contract storage + let mut storage = app.contract_storage_mut(&contract_addr); + COUNTER.save(&mut *storage, &100).unwrap(); + } // now the `counter` contract should return value 100 let query_res: CounterResponseMsg = app .wrap() .query_wasm_smart(&contract_addr, &CounterQueryMsg::Counter {}) .unwrap(); - assert_eq!(2, query_res.value); - // TODO assert_eq!(100, query_res.value); + assert_eq!(100, query_res.value); } From 7b7ad5458dc883ff5e56ea6d4f125f936a397670 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 25 Mar 2024 13:08:14 +0100 Subject: [PATCH 179/250] Dependency refreshment. --- Cargo.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16b642a1..df0edc51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,9 +39,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.70" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95d8e92cac0961e91dbd517496b00f7e9b92363dbe6d42c3198268323798860c" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -114,9 +114,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" @@ -599,7 +599,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -712,7 +712,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -806,9 +806,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.53" +version = "2.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" dependencies = [ "proc-macro2", "quote", @@ -832,7 +832,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] From 7a5d136e24366db37b13d6b2e2283ba8c46b3c38 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 26 Mar 2024 09:49:44 +0100 Subject: [PATCH 180/250] Exposed prefixed storage. --- Cargo.lock | 26 +++++----- src/app.rs | 11 +++++ src/bank.rs | 2 +- src/prefixed_storage/mod.rs | 14 ++++-- tests/mod.rs | 1 + tests/test_prefixed_storage/mod.rs | 1 + .../test_prefixed_storage_bank.rs | 47 +++++++++++++++++++ 7 files changed, 84 insertions(+), 18 deletions(-) create mode 100644 tests/test_prefixed_storage/mod.rs create mode 100644 tests/test_prefixed_storage/test_prefixed_storage_bank.rs diff --git a/Cargo.lock b/Cargo.lock index 401c81eb..14931905 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,9 +39,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -114,9 +114,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" @@ -500,9 +500,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "k256" @@ -599,7 +599,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -712,7 +712,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -728,9 +728,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "itoa", "ryu", @@ -806,9 +806,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.53" +version = "2.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" dependencies = [ "proc-macro2", "quote", @@ -832,7 +832,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] diff --git a/src/app.rs b/src/app.rs index a4008827..6f20afe7 100644 --- a/src/app.rs +++ b/src/app.rs @@ -5,6 +5,7 @@ use crate::executor::{AppResponse, Executor}; use crate::gov::Gov; use crate::ibc::Ibc; use crate::module::{FailingModule, Module}; +use crate::prefixed_storage::{prefixed, prefixed_read}; use crate::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking, StakingSudo}; use crate::stargate::{Stargate, StargateFailingModule}; use crate::transactions::transactional; @@ -345,6 +346,16 @@ where pub fn dump_wasm_raw(&self, address: &Addr) -> Vec { self.read_module(|router, _, storage| router.wasm.dump_wasm_raw(storage, address)) } + + /// Returns **read-only** prefixed storage with specified namespace. + pub fn prefixed_storage<'a>(&'a self, namespace: &[u8]) -> Box { + Box::new(prefixed_read(&self.storage, namespace)) + } + + /// Returns **mutable** prefixed storage with specified namespace. + pub fn prefixed_storage_mut<'a>(&'a mut self, namespace: &[u8]) -> Box { + Box::new(prefixed(&mut self.storage, namespace)) + } } impl diff --git a/src/bank.rs b/src/bank.rs index 1843c7e3..4586e93f 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -20,7 +20,7 @@ const BALANCES: Map<&Addr, NativeBalance> = Map::new("balances"); const DENOM_METADATA: Map = Map::new("metadata"); /// Default storage namespace for bank module. -pub const NAMESPACE_BANK: &[u8] = b"bank"; +const NAMESPACE_BANK: &[u8] = b"bank"; /// A message representing privileged actions in bank module. #[derive(Clone, Debug, PartialEq, Eq, JsonSchema)] diff --git a/src/prefixed_storage/mod.rs b/src/prefixed_storage/mod.rs index 2666a855..4f00af43 100644 --- a/src/prefixed_storage/mod.rs +++ b/src/prefixed_storage/mod.rs @@ -19,12 +19,14 @@ pub fn prefixed_read<'a>( ReadonlyPrefixedStorage::new(storage, namespace) } +/// Prefixed, mutable storage. pub struct PrefixedStorage<'a> { storage: &'a mut dyn Storage, prefix: Vec, } impl<'a> PrefixedStorage<'a> { + /// Returns a mutable prefixed storage with specified namespace. pub fn new(storage: &'a mut dyn Storage, namespace: &[u8]) -> Self { PrefixedStorage { storage, @@ -32,8 +34,9 @@ impl<'a> PrefixedStorage<'a> { } } - // Nested namespaces as documented in - // https://github.com/webmaster128/key-namespacing#nesting + /// Returns a mutable prefixed storage with [nested namespaces]. + /// + /// [nested namespaces]: https://github.com/webmaster128/key-namespacing#nesting pub fn multilevel(storage: &'a mut dyn Storage, namespaces: &[&[u8]]) -> Self { PrefixedStorage { storage, @@ -67,12 +70,14 @@ impl<'a> Storage for PrefixedStorage<'a> { } } +/// Prefixed, read-only storage. pub struct ReadonlyPrefixedStorage<'a> { storage: &'a dyn Storage, prefix: Vec, } impl<'a> ReadonlyPrefixedStorage<'a> { + /// Returns a read-only prefixed storage with specified namespace. pub fn new(storage: &'a dyn Storage, namespace: &[u8]) -> Self { ReadonlyPrefixedStorage { storage, @@ -80,8 +85,9 @@ impl<'a> ReadonlyPrefixedStorage<'a> { } } - // Nested namespaces as documented in - // https://github.com/webmaster128/key-namespacing#nesting + /// Returns a read-only prefixed storage with [nested namespaces]. + /// + /// [nested namespaces]: https://github.com/webmaster128/key-namespacing#nesting pub fn multilevel(storage: &'a dyn Storage, namespaces: &[&[u8]]) -> Self { ReadonlyPrefixedStorage { storage, diff --git a/tests/mod.rs b/tests/mod.rs index f5370608..ddba5c28 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -7,6 +7,7 @@ mod test_api; mod test_app; mod test_app_builder; mod test_module; +mod test_prefixed_storage; mod test_wasm; const COUNTER: Item = Item::new("count"); diff --git a/tests/test_prefixed_storage/mod.rs b/tests/test_prefixed_storage/mod.rs new file mode 100644 index 00000000..d0e4ced6 --- /dev/null +++ b/tests/test_prefixed_storage/mod.rs @@ -0,0 +1 @@ +mod test_prefixed_storage_bank; diff --git a/tests/test_prefixed_storage/test_prefixed_storage_bank.rs b/tests/test_prefixed_storage/test_prefixed_storage_bank.rs new file mode 100644 index 00000000..9505b34f --- /dev/null +++ b/tests/test_prefixed_storage/test_prefixed_storage_bank.rs @@ -0,0 +1,47 @@ +use cosmwasm_std::{coin, Addr}; +use cw_multi_test::{App, IntoAddr}; +use cw_storage_plus::Map; +use cw_utils::NativeBalance; +use std::ops::Deref; + +const NAMESPACE_BANK: &[u8] = b"bank"; +const BALANCES: Map<&Addr, NativeBalance> = Map::new("balances"); + +#[test] +fn reading_bank_storage_should_work() { + // prepare balance owner + let owner_addr = "owner".into_addr(); + + // set balances + let init_funds = vec![coin(1, "BTC"), coin(2, "ETH")]; + let app = App::new(|router, _, storage| { + router + .bank + .init_balance(storage, &owner_addr, init_funds) + .unwrap(); + }); + + // get the read-only prefixed storage for bank + let storage = app.prefixed_storage(NAMESPACE_BANK); + let balances = BALANCES.load(storage.deref(), &owner_addr).unwrap(); + assert_eq!("BTC1ETH2", balances.to_string()); +} + +#[test] +fn writing_bank_storage_should_work() { + // prepare balance owner + let owner_addr = "owner".into_addr(); + + let mut app = App::default(); + // get the mutable prefixed storage for bank + let mut storage = app.prefixed_storage_mut(NAMESPACE_BANK); + + // set balances manually + let mut balance = NativeBalance(vec![coin(3, "BTC"), coin(4, "ETH")]); + balance.normalize(); + BALANCES.save(&mut *storage, &owner_addr, &balance).unwrap(); + + // check balances + let balances = BALANCES.load(storage.deref(), &owner_addr).unwrap(); + assert_eq!("BTC3ETH4", balances.to_string()); +} From 4933a1e1e4e536fbe85b7e1ad241687a61e61f87 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 26 Mar 2024 10:25:59 +0100 Subject: [PATCH 181/250] Exposed prefixed, multilevel storage. --- src/app.rs | 20 +++++++++- src/prefixed_storage/mod.rs | 20 +++++++++- tests/test_prefixed_storage/mod.rs | 1 + .../test_prefixed_multilevel_storage.rs | 40 +++++++++++++++++++ .../test_prefixed_storage_bank.rs | 6 ++- 5 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 tests/test_prefixed_storage/test_prefixed_multilevel_storage.rs diff --git a/src/app.rs b/src/app.rs index 6f20afe7..b3d8db82 100644 --- a/src/app.rs +++ b/src/app.rs @@ -5,7 +5,9 @@ use crate::executor::{AppResponse, Executor}; use crate::gov::Gov; use crate::ibc::Ibc; use crate::module::{FailingModule, Module}; -use crate::prefixed_storage::{prefixed, prefixed_read}; +use crate::prefixed_storage::{ + prefixed, prefixed_multilevel, prefixed_multilevel_read, prefixed_read, +}; use crate::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking, StakingSudo}; use crate::stargate::{Stargate, StargateFailingModule}; use crate::transactions::transactional; @@ -356,6 +358,22 @@ where pub fn prefixed_storage_mut<'a>(&'a mut self, namespace: &[u8]) -> Box { Box::new(prefixed(&mut self.storage, namespace)) } + + /// Returns **read-only** prefixed, multilevel storage with specified namespaces. + pub fn prefixed_multilevel_storage<'a>( + &'a self, + namespaces: &[&[u8]], + ) -> Box { + Box::new(prefixed_multilevel_read(&self.storage, namespaces)) + } + + /// Returns **mutable** prefixed, multilevel storage with specified namespaces. + pub fn prefixed_multilevel_storage_mut<'a>( + &'a mut self, + namespaces: &[&[u8]], + ) -> Box { + Box::new(prefixed_multilevel(&mut self.storage, namespaces)) + } } impl diff --git a/src/prefixed_storage/mod.rs b/src/prefixed_storage/mod.rs index 4f00af43..77416fc6 100644 --- a/src/prefixed_storage/mod.rs +++ b/src/prefixed_storage/mod.rs @@ -6,12 +6,12 @@ use namespace_helpers::{get_with_prefix, range_with_prefix, remove_with_prefix, mod length_prefixed; mod namespace_helpers; -/// An alias of PrefixedStorage::new for less verbose usage +/// An alias of [PrefixedStorage::new] for less verbose usage. pub fn prefixed<'a>(storage: &'a mut dyn Storage, namespace: &[u8]) -> PrefixedStorage<'a> { PrefixedStorage::new(storage, namespace) } -/// An alias of ReadonlyPrefixedStorage::new for less verbose usage +/// An alias of [ReadonlyPrefixedStorage::new] for less verbose usage. pub fn prefixed_read<'a>( storage: &'a dyn Storage, namespace: &[u8], @@ -19,6 +19,22 @@ pub fn prefixed_read<'a>( ReadonlyPrefixedStorage::new(storage, namespace) } +/// An alias of [PrefixedStorage::multilevel] for less verbose usage. +pub fn prefixed_multilevel<'a>( + storage: &'a mut dyn Storage, + namespaces: &[&[u8]], +) -> PrefixedStorage<'a> { + PrefixedStorage::multilevel(storage, namespaces) +} + +/// An alias of [ReadonlyPrefixedStorage::multilevel] for less verbose usage. +pub fn prefixed_multilevel_read<'a>( + storage: &'a dyn Storage, + namespaces: &[&[u8]], +) -> ReadonlyPrefixedStorage<'a> { + ReadonlyPrefixedStorage::multilevel(storage, namespaces) +} + /// Prefixed, mutable storage. pub struct PrefixedStorage<'a> { storage: &'a mut dyn Storage, diff --git a/tests/test_prefixed_storage/mod.rs b/tests/test_prefixed_storage/mod.rs index d0e4ced6..aeda3e9d 100644 --- a/tests/test_prefixed_storage/mod.rs +++ b/tests/test_prefixed_storage/mod.rs @@ -1 +1,2 @@ +mod test_prefixed_multilevel_storage; mod test_prefixed_storage_bank; diff --git a/tests/test_prefixed_storage/test_prefixed_multilevel_storage.rs b/tests/test_prefixed_storage/test_prefixed_multilevel_storage.rs new file mode 100644 index 00000000..03dd64c3 --- /dev/null +++ b/tests/test_prefixed_storage/test_prefixed_multilevel_storage.rs @@ -0,0 +1,40 @@ +use cosmwasm_std::{coin, Addr}; +use cw_multi_test::{App, IntoAddr}; +use cw_storage_plus::Map; +use cw_utils::NativeBalance; +use std::ops::{Deref, DerefMut}; + +const NAMESPACE_CENTRAL_BANK: &[u8] = b"central-bank"; +const NAMESPACE_NATIONAL_BANK: &[u8] = b"national-bank"; +const NAMESPACE_LOCAL_BANK: &[u8] = b"local-bank"; +const NAMESPACES: &[&[u8]] = &[ + NAMESPACE_NATIONAL_BANK, + NAMESPACE_CENTRAL_BANK, + NAMESPACE_LOCAL_BANK, +]; +const BALANCES: Map<&Addr, NativeBalance> = Map::new("balances"); + +#[test] +fn multilevel_storage_should_work() { + // prepare balance owner + let owner_addr = "owner".into_addr(); + // create the blockchain + let mut app = App::default(); + { + // get the mutable prefixed, multilevel storage for banks + let mut storage_mut = app.prefixed_multilevel_storage_mut(NAMESPACES); + // set balances manually + let mut balance = NativeBalance(vec![coin(111, "BTC"), coin(222, "ETH")]); + balance.normalize(); + BALANCES + .save(storage_mut.deref_mut(), &owner_addr, &balance) + .unwrap(); + } + { + // get the read-only prefixed, multilevel storage for banks + let storage = app.prefixed_multilevel_storage(NAMESPACES); + // read balances manually + let balances = BALANCES.load(storage.deref(), &owner_addr).unwrap(); + assert_eq!("BTC111ETH222", balances.to_string()); + } +} diff --git a/tests/test_prefixed_storage/test_prefixed_storage_bank.rs b/tests/test_prefixed_storage/test_prefixed_storage_bank.rs index 9505b34f..653ddcf8 100644 --- a/tests/test_prefixed_storage/test_prefixed_storage_bank.rs +++ b/tests/test_prefixed_storage/test_prefixed_storage_bank.rs @@ -2,7 +2,7 @@ use cosmwasm_std::{coin, Addr}; use cw_multi_test::{App, IntoAddr}; use cw_storage_plus::Map; use cw_utils::NativeBalance; -use std::ops::Deref; +use std::ops::{Deref, DerefMut}; const NAMESPACE_BANK: &[u8] = b"bank"; const BALANCES: Map<&Addr, NativeBalance> = Map::new("balances"); @@ -39,7 +39,9 @@ fn writing_bank_storage_should_work() { // set balances manually let mut balance = NativeBalance(vec![coin(3, "BTC"), coin(4, "ETH")]); balance.normalize(); - BALANCES.save(&mut *storage, &owner_addr, &balance).unwrap(); + BALANCES + .save(storage.deref_mut(), &owner_addr, &balance) + .unwrap(); // check balances let balances = BALANCES.load(storage.deref(), &owner_addr).unwrap(); From bc2f2312916dbc4ce89c64051b00fa240c3393bb Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 27 Mar 2024 11:30:52 +0100 Subject: [PATCH 182/250] Fixed typos. --- src/prefixed_storage/length_prefixed.rs | 4 ++-- src/tests/test_app.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/prefixed_storage/length_prefixed.rs b/src/prefixed_storage/length_prefixed.rs index 18543f50..c00bb2a5 100644 --- a/src/prefixed_storage/length_prefixed.rs +++ b/src/prefixed_storage/length_prefixed.rs @@ -85,7 +85,7 @@ mod tests { #[test] fn to_length_prefixed_calculates_capacity_correctly() { // Those tests cannot guarantee the required capacity was calculated correctly before - // the vector allocation but increase the likelyhood of a proper implementation. + // the vector allocation but increase the likelihood of a proper implementation. let key = to_length_prefixed(b""); assert_eq!(key.capacity(), key.len()); @@ -144,7 +144,7 @@ mod tests { #[test] fn to_length_prefixed_nested_calculates_capacity_correctly() { // Those tests cannot guarantee the required capacity was calculated correctly before - // the vector allocation but increase the likelyhood of a proper implementation. + // the vector allocation but increase the likelihood of a proper implementation. let key = to_length_prefixed_nested(&[]); assert_eq!(key.capacity(), key.len()); diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 9868298c..685234eb 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -622,7 +622,7 @@ fn reflect_sub_message_reply_works() { ) .unwrap(); - // no reply writen beforehand + // no reply written beforehand let query = reflect::QueryMsg::Reply { id: 123 }; let res: StdResult = app.wrap().query_wasm_smart(&reflect_addr, &query); res.unwrap_err(); From 47b801863106145ed3035be317458ac3fdf7816c Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 4 Apr 2024 12:57:18 +0200 Subject: [PATCH 183/250] Remove CLA.md The reposirory is fully Apache 2 licensed for a long time --- CLA.md | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 CLA.md diff --git a/CLA.md b/CLA.md deleted file mode 100644 index 17a701ee..00000000 --- a/CLA.md +++ /dev/null @@ -1,23 +0,0 @@ -## Contributor License Agreement -The following terms are used throughout this agreement: - -* You - the person or legal entity including its affiliates asked to accept this agreement. An affiliate is any entity that controls or is controlled by the legal entity, or is under common control with it. -* Project - is an umbrella term that refers to any and all Confio OÜ open source projects. -* Contribution - any type of work that is submitted to a Project, including any modifications or additions to existing work. -* Submitted - conveyed to a Project via a pull request, commit, issue, or any form of electronic, written, or verbal communication with Confio OÜ, contributors or maintainers. - -## 1. Grant of Copyright License. - -Subject to the terms and conditions of this agreement, You grant to the Projects’ maintainers, contributors, users and to Confio OÜ a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your contributions and such derivative works. Except for this license, You reserve all rights, title, and interest in your contributions. - -## 2. Grant of Patent License. - -Subject to the terms and conditions of this agreement, You grant to the Projects’ maintainers, contributors, users and to Confio OÜ a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer your contributions, where such license applies only to those patent claims licensable by you that are necessarily infringed by your contribution or by combination of your contribution with the project to which this contribution was submitted. - -If any entity institutes patent litigation - including cross-claim or counterclaim in a lawsuit - against You alleging that your contribution or any project it was submitted to constitutes or is responsible for direct or contributory patent infringement, then any patent licenses granted to that entity under this agreement shall terminate as of the date such litigation is filed. - -## 3. Source of Contribution. - -Your contribution is either your original creation, based upon previous work that, to the best of your knowledge, is covered under an appropriate open source license and you have the right under that license to submit that work with modifications, whether created in whole or in part by you, or you have clearly identified the source of the contribution and any license or other restriction (like related patents, trademarks, and license agreements) of which you are personally aware. - -_Based in [GitHub's CLA](https://cla.github.com/agreement)__ \ No newline at end of file From 21c3c30608b258a4a9a061f73b63e9dc65186c88 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 18 Apr 2024 09:49:01 +0200 Subject: [PATCH 184/250] Upgraded dependencies. --- .circleci/config.yml | 26 ++++++------ Cargo.lock | 95 ++++++++++++++++++++------------------------ Cargo.toml | 8 ++-- 3 files changed, 60 insertions(+), 69 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e6bef762..50ebb17b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -30,7 +30,7 @@ workflows: jobs: build_and_test: docker: - - image: rust:1.65.0 + - image: rust:1.70 working_directory: ~/project steps: - checkout @@ -42,8 +42,8 @@ jobs: command: cargo update - restore_cache: keys: - - cargocache-v2-multi-test:1.65.0-{{ checksum "Cargo.lock" }} - - cargocache-v2-multi-test:1.65.0- + - cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} + - cargocache-v2-multi-test:1.70- - run: name: Build library for native target command: cargo build --locked @@ -54,7 +54,7 @@ jobs: paths: - /usr/local/cargo/registry - target - key: cargocache-v2-multi-test:1.65.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} build_minimal: docker: @@ -70,7 +70,7 @@ jobs: command: rm Cargo.lock - restore_cache: keys: - - cargocache-v2-multi-test:1.65.0-minimal-{{ checksum "Cargo.toml" }} + - cargocache-v2-multi-test:1.70-minimal-{{ checksum "Cargo.toml" }} - run: name: Build library for native target command: cargo build -Zminimal-versions --all-features @@ -81,11 +81,11 @@ jobs: paths: - /usr/local/cargo/registry - target - key: cargocache-v2-multi-test:1.65.0-minimal-{{ checksum "Cargo.toml" }} + key: cargocache-v2-multi-test:1.70-minimal-{{ checksum "Cargo.toml" }} build_maximal: docker: - - image: rust:1.65.0 + - image: rust:1.70 working_directory: ~/project/ steps: - checkout @@ -97,7 +97,7 @@ jobs: command: cargo update - restore_cache: keys: - - cargocache-v2-multi-test:1.65.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} - run: name: Build library for native target command: cargo build --locked --all-features @@ -108,11 +108,11 @@ jobs: paths: - /usr/local/cargo/registry - target - key: cargocache-v2-multi-test:1.65.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} lint: docker: - - image: rust:1.65.0 + - image: rust:1.70 steps: - checkout - run: @@ -123,8 +123,8 @@ jobs: command: cargo update - restore_cache: keys: - - cargocache-v2-lint-rust:1.65.0-{{ checksum "Cargo.lock" }} - - cargocache-v2-lint-rust:1.65.0- + - cargocache-v2-lint-rust:1.70-{{ checksum "Cargo.lock" }} + - cargocache-v2-lint-rust:1.70- - run: name: Add rustfmt component command: rustup component add rustfmt @@ -143,7 +143,7 @@ jobs: - target/debug/.fingerprint - target/debug/build - target/debug/deps - key: cargocache-v2-lint-rust:1.65.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-lint-rust:1.70-{{ checksum "Cargo.lock" }} coverage: # https://circleci.com/developer/images?imageType=machine diff --git a/Cargo.lock b/Cargo.lock index 14931905..b6dcc839 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" dependencies = [ "backtrace", ] @@ -120,9 +120,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.90" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" [[package]] name = "cfg-if" @@ -138,9 +138,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-crypto" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5fd9485d4f1f4330547a8a5aaf0958c68b4d620975ded2c15f2ed5c49e8e74" +checksum = "d1cd7a367ebd007cb05fe17e9c449beeb3636b15160750f2c6226c7dfd46df37" dependencies = [ "digest 0.10.7", "ed25519-zebra", @@ -151,18 +151,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d692944045feabbf46c75e8f072024bb885a7742025e40d46913296fe9fbbd06" +checksum = "db01ae480b00f133b78830db3211ff63afe08093e78c77ee20e73f7134849a60" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a67c099aba9e334bbc1fc8037fe8e7ba91d06b215d9ffa7af91893c44aa420c6" +checksum = "de6e530d13452b4e9d882008193ab165032307a31f197b45d7b4e2aeff7577b5" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -173,9 +173,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2bb09168f6e86bf583361fdb0a0fed2625652e9edcfce731cb55ef4cb8de3d" +checksum = "c0ef0d7a8ae8807b8e8f5c94333d12aa9a11efc05f7b864f362582a2b167c663" dependencies = [ "proc-macro2", "quote", @@ -184,9 +184,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464f484b3f289935a41e374560c66c59a8f881aefc74742558e42008f1b0b7f3" +checksum = "f6201969327d8fe5e9596e8c36e376ab595a885bdfcaa6a0bf57748f9ea2be2b" dependencies = [ "base64", "bech32 0.9.1", @@ -260,7 +260,7 @@ dependencies = [ "derivative", "hex", "hex-literal", - "itertools 0.12.1", + "itertools", "once_cell", "prost", "schemars", @@ -295,9 +295,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "zeroize", @@ -372,9 +372,9 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "elliptic-curve" @@ -424,9 +424,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -480,15 +480,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.12.1" @@ -526,9 +517,9 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "miniz_oxide" @@ -572,18 +563,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" dependencies = [ "bytes", "prost-derive", @@ -591,22 +582,22 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.60", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -688,9 +679,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.197" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" dependencies = [ "serde_derive", ] @@ -706,13 +697,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.60", ] [[package]] @@ -728,9 +719,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ "itoa", "ryu", @@ -806,9 +797,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.55" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -832,7 +823,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.60", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 87c83cbe..91bc8498 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,16 +14,16 @@ backtrace = ["anyhow/backtrace"] cosmwasm_2_0 = ["cosmwasm-std/cosmwasm_2_0"] [dependencies] -anyhow = "1.0.81" +anyhow = "1.0.82" bech32 = "0.11.0" -cosmwasm-std = { version = "2.0.0", features = ["iterator", "staking", "stargate"] } +cosmwasm-std = { version = "2.0.1", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "2.0.0" cw-utils = "2.0.0" derivative = "2.2.0" itertools = "0.12.1" -prost = "0.12.3" +prost = "0.12.4" schemars = "0.8.16" -serde = "1.0.197" +serde = "1.0.198" sha2 = "0.10.8" thiserror = "1.0.58" From 8c3284f4cbdbc77fc59a8232471ac0159bb1088f Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 18 Apr 2024 09:56:53 +0200 Subject: [PATCH 185/250] Upgraded dependencies. --- .circleci/config.yml | 26 ++++++------ Cargo.lock | 95 ++++++++++++++++++++------------------------ Cargo.toml | 8 ++-- 3 files changed, 60 insertions(+), 69 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e6bef762..50ebb17b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -30,7 +30,7 @@ workflows: jobs: build_and_test: docker: - - image: rust:1.65.0 + - image: rust:1.70 working_directory: ~/project steps: - checkout @@ -42,8 +42,8 @@ jobs: command: cargo update - restore_cache: keys: - - cargocache-v2-multi-test:1.65.0-{{ checksum "Cargo.lock" }} - - cargocache-v2-multi-test:1.65.0- + - cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} + - cargocache-v2-multi-test:1.70- - run: name: Build library for native target command: cargo build --locked @@ -54,7 +54,7 @@ jobs: paths: - /usr/local/cargo/registry - target - key: cargocache-v2-multi-test:1.65.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} build_minimal: docker: @@ -70,7 +70,7 @@ jobs: command: rm Cargo.lock - restore_cache: keys: - - cargocache-v2-multi-test:1.65.0-minimal-{{ checksum "Cargo.toml" }} + - cargocache-v2-multi-test:1.70-minimal-{{ checksum "Cargo.toml" }} - run: name: Build library for native target command: cargo build -Zminimal-versions --all-features @@ -81,11 +81,11 @@ jobs: paths: - /usr/local/cargo/registry - target - key: cargocache-v2-multi-test:1.65.0-minimal-{{ checksum "Cargo.toml" }} + key: cargocache-v2-multi-test:1.70-minimal-{{ checksum "Cargo.toml" }} build_maximal: docker: - - image: rust:1.65.0 + - image: rust:1.70 working_directory: ~/project/ steps: - checkout @@ -97,7 +97,7 @@ jobs: command: cargo update - restore_cache: keys: - - cargocache-v2-multi-test:1.65.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} - run: name: Build library for native target command: cargo build --locked --all-features @@ -108,11 +108,11 @@ jobs: paths: - /usr/local/cargo/registry - target - key: cargocache-v2-multi-test:1.65.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} lint: docker: - - image: rust:1.65.0 + - image: rust:1.70 steps: - checkout - run: @@ -123,8 +123,8 @@ jobs: command: cargo update - restore_cache: keys: - - cargocache-v2-lint-rust:1.65.0-{{ checksum "Cargo.lock" }} - - cargocache-v2-lint-rust:1.65.0- + - cargocache-v2-lint-rust:1.70-{{ checksum "Cargo.lock" }} + - cargocache-v2-lint-rust:1.70- - run: name: Add rustfmt component command: rustup component add rustfmt @@ -143,7 +143,7 @@ jobs: - target/debug/.fingerprint - target/debug/build - target/debug/deps - key: cargocache-v2-lint-rust:1.65.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-lint-rust:1.70-{{ checksum "Cargo.lock" }} coverage: # https://circleci.com/developer/images?imageType=machine diff --git a/Cargo.lock b/Cargo.lock index 14931905..b6dcc839 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" dependencies = [ "backtrace", ] @@ -120,9 +120,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.90" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" [[package]] name = "cfg-if" @@ -138,9 +138,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-crypto" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5fd9485d4f1f4330547a8a5aaf0958c68b4d620975ded2c15f2ed5c49e8e74" +checksum = "d1cd7a367ebd007cb05fe17e9c449beeb3636b15160750f2c6226c7dfd46df37" dependencies = [ "digest 0.10.7", "ed25519-zebra", @@ -151,18 +151,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d692944045feabbf46c75e8f072024bb885a7742025e40d46913296fe9fbbd06" +checksum = "db01ae480b00f133b78830db3211ff63afe08093e78c77ee20e73f7134849a60" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a67c099aba9e334bbc1fc8037fe8e7ba91d06b215d9ffa7af91893c44aa420c6" +checksum = "de6e530d13452b4e9d882008193ab165032307a31f197b45d7b4e2aeff7577b5" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -173,9 +173,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2bb09168f6e86bf583361fdb0a0fed2625652e9edcfce731cb55ef4cb8de3d" +checksum = "c0ef0d7a8ae8807b8e8f5c94333d12aa9a11efc05f7b864f362582a2b167c663" dependencies = [ "proc-macro2", "quote", @@ -184,9 +184,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464f484b3f289935a41e374560c66c59a8f881aefc74742558e42008f1b0b7f3" +checksum = "f6201969327d8fe5e9596e8c36e376ab595a885bdfcaa6a0bf57748f9ea2be2b" dependencies = [ "base64", "bech32 0.9.1", @@ -260,7 +260,7 @@ dependencies = [ "derivative", "hex", "hex-literal", - "itertools 0.12.1", + "itertools", "once_cell", "prost", "schemars", @@ -295,9 +295,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "zeroize", @@ -372,9 +372,9 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "elliptic-curve" @@ -424,9 +424,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -480,15 +480,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.12.1" @@ -526,9 +517,9 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "miniz_oxide" @@ -572,18 +563,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" dependencies = [ "bytes", "prost-derive", @@ -591,22 +582,22 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.60", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -688,9 +679,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.197" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" dependencies = [ "serde_derive", ] @@ -706,13 +697,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.60", ] [[package]] @@ -728,9 +719,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ "itoa", "ryu", @@ -806,9 +797,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.55" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -832,7 +823,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.60", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 87c83cbe..91bc8498 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,16 +14,16 @@ backtrace = ["anyhow/backtrace"] cosmwasm_2_0 = ["cosmwasm-std/cosmwasm_2_0"] [dependencies] -anyhow = "1.0.81" +anyhow = "1.0.82" bech32 = "0.11.0" -cosmwasm-std = { version = "2.0.0", features = ["iterator", "staking", "stargate"] } +cosmwasm-std = { version = "2.0.1", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "2.0.0" cw-utils = "2.0.0" derivative = "2.2.0" itertools = "0.12.1" -prost = "0.12.3" +prost = "0.12.4" schemars = "0.8.16" -serde = "1.0.197" +serde = "1.0.198" sha2 = "0.10.8" thiserror = "1.0.58" From 689f22b908916e7a00478d6ede5ae36432cdcc89 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 18 Apr 2024 11:37:35 +0200 Subject: [PATCH 186/250] Added AnyGate trait. --- src/anygate.rs | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 ++ 2 files changed, 90 insertions(+) create mode 100644 src/anygate.rs diff --git a/src/anygate.rs b/src/anygate.rs new file mode 100644 index 00000000..dfb86053 --- /dev/null +++ b/src/anygate.rs @@ -0,0 +1,88 @@ +//! # Handler for `CosmosMsg::Stargate`, `CosmosMsg::Any`, `QueryRequest::Stargate` and `QueryRequest::Grpc` messages + +use crate::error::AnyResult; +use crate::{AppResponse, CosmosRouter}; +use anyhow::bail; +use cosmwasm_std::{ + Addr, AnyMsg, Api, Binary, BlockInfo, CustomMsg, CustomQuery, GrpcQuery, Querier, Storage, +}; +use serde::de::DeserializeOwned; + +/// Interface of handlers for processing `Stargate`/`Any` message variants +/// and `Stargate`/`Grpc` queries. +pub trait AnyGate { + /// 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, + { + let _ = (api, storage, router, block); + bail!( + "Unexpected execute from {}, type_url={}, value={}", + sender, + type_url, + value + ) + } + + /// Processes `CosmosMsg::Any` message variant. + fn execute_any( + &self, + api: &dyn Api, + storage: &mut dyn Storage, + router: &dyn CosmosRouter, + block: &BlockInfo, + sender: Addr, + msg: AnyMsg, + ) -> AnyResult + where + ExecC: CustomMsg + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + let _ = (api, storage, router, block); + bail!("Unexpected execute from {}, msg={:?}", sender, msg,) + } + + /// Processes `QueryRequest::Stargate` query. + fn query_stargate( + &self, + api: &dyn Api, + storage: &dyn Storage, + querier: &dyn Querier, + block: &BlockInfo, + path: String, + data: Binary, + ) -> AnyResult { + let _ = (api, storage, querier, block); + bail!("Unexpected query, path={}, data={}", path, data) + } + + /// Processes `QueryRequest::Grpc` query. + fn query_grpc( + &self, + api: &dyn Api, + storage: &dyn Storage, + querier: &dyn Querier, + block: &BlockInfo, + request: GrpcQuery, + ) -> AnyResult { + let _ = (api, storage, querier, block); + bail!("Unexpected query, request={:?}", request) + } +} + +/// Always failing handler for `Stargate`/`Any` message variants +/// and `Stargate`/`Grpc` queries. +pub struct FailingAnyGate; + +impl AnyGate for FailingAnyGate {} diff --git a/src/lib.rs b/src/lib.rs index d5f1225b..f6e7af42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -125,6 +125,7 @@ #![deny(rustdoc::missing_crate_level_docs)] mod addresses; +mod anygate; mod api; mod app; mod app_builder; @@ -148,6 +149,7 @@ mod wasm; pub use crate::addresses::{ AddressGenerator, IntoAddr, IntoBech32, IntoBech32m, SimpleAddressGenerator, }; +pub use crate::anygate::{AnyGate, FailingAnyGate}; pub use crate::api::{MockApiBech32, MockApiBech32m}; pub use crate::app::{ custom_app, next_block, no_init, App, BasicApp, CosmosRouter, Router, SudoMsg, From 47c52a87f81432be4c75456ea7534735e78ed4d6 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 18 Apr 2024 13:13:04 +0200 Subject: [PATCH 187/250] Added anygate generics. --- src/anygate.rs | 6 +- src/app.rs | 82 +++++++++++++----- src/app_builder.rs | 196 ++++++++++++++++++++++++++++++++++++------ src/lib.rs | 2 +- src/staking.rs | 6 +- src/tests/test_app.rs | 4 +- src/wasm.rs | 4 +- 7 files changed, 242 insertions(+), 58 deletions(-) diff --git a/src/anygate.rs b/src/anygate.rs index dfb86053..e66581fa 100644 --- a/src/anygate.rs +++ b/src/anygate.rs @@ -10,7 +10,7 @@ use serde::de::DeserializeOwned; /// Interface of handlers for processing `Stargate`/`Any` message variants /// and `Stargate`/`Grpc` queries. -pub trait AnyGate { +pub trait Anygate { /// Processes `CosmosMsg::Stargate` message variant. fn execute_stargate( &self, @@ -83,6 +83,6 @@ pub trait AnyGate { /// Always failing handler for `Stargate`/`Any` message variants /// and `Stargate`/`Grpc` queries. -pub struct FailingAnyGate; +pub struct FailingAnygate; -impl AnyGate for FailingAnyGate {} +impl Anygate for FailingAnygate {} diff --git a/src/app.rs b/src/app.rs index 6608ffd0..ce12fd05 100644 --- a/src/app.rs +++ b/src/app.rs @@ -12,7 +12,7 @@ use crate::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking, Sta use crate::stargate::{Stargate, StargateFailingModule}; use crate::transactions::transactional; use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; -use crate::{AppBuilder, GovFailingModule, IbcFailingModule}; +use crate::{Anygate, AppBuilder, FailingAnygate, GovFailingModule, IbcFailingModule}; use cosmwasm_std::testing::{MockApi, MockStorage}; use cosmwasm_std::{ from_json, to_json_binary, Addr, Api, Binary, BlockInfo, ContractResult, CosmosMsg, CustomMsg, @@ -43,6 +43,7 @@ pub type BasicApp = App< IbcFailingModule, GovFailingModule, StargateFailingModule, + FailingAnygate, >; /// # Blockchain application simulator @@ -60,16 +61,17 @@ pub struct App< Ibc = IbcFailingModule, Gov = GovFailingModule, Stargate = StargateFailingModule, + Anygate = FailingAnygate, > { - pub(crate) router: Router, + pub(crate) router: Router, pub(crate) api: Api, pub(crate) storage: Storage, pub(crate) block: BlockInfo, } /// No-op application initialization function. -pub fn no_init( - router: &mut Router, +pub fn no_init( + router: &mut Router, api: &dyn Api, storage: &mut dyn Storage, ) { @@ -96,6 +98,7 @@ impl BasicApp { IbcFailingModule, GovFailingModule, StargateFailingModule, + FailingAnygate, >, &dyn Api, &mut dyn Storage, @@ -121,6 +124,7 @@ where IbcFailingModule, GovFailingModule, StargateFailingModule, + FailingAnygate, >, &dyn Api, &mut dyn Storage, @@ -129,8 +133,21 @@ where AppBuilder::new_custom().build(init_fn) } -impl Querier - for App +impl + Querier + for App< + BankT, + ApiT, + StorageT, + CustomT, + WasmT, + StakingT, + DistrT, + IbcT, + GovT, + StargateT, + AnygateT, + > where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -144,6 +161,7 @@ where IbcT: Ibc, GovT: Gov, StargateT: Stargate, + AnygateT: Anygate, { fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { self.router @@ -152,9 +170,21 @@ where } } -impl +impl Executor - for App + for App< + BankT, + ApiT, + StorageT, + CustomT, + WasmT, + StakingT, + DistrT, + IbcT, + GovT, + StargateT, + AnygateT, + > where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -168,6 +198,7 @@ where IbcT: Ibc, GovT: Gov, StargateT: Stargate, + AnygateT: Anygate, { fn execute(&mut self, sender: Addr, msg: CosmosMsg) -> AnyResult { let mut all = self.execute_multi(sender, vec![msg])?; @@ -176,8 +207,8 @@ where } } -impl - App +impl + App where WasmT: Wasm, BankT: Bank, @@ -189,11 +220,12 @@ where IbcT: Ibc, GovT: Gov, StargateT: Stargate, + AnygateT: Anygate, { /// Returns a shared reference to application's router. pub fn router( &self, - ) -> &Router { + ) -> &Router { &self.router } @@ -216,7 +248,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, @@ -228,7 +260,7 @@ where pub fn read_module(&self, query_fn: F) -> T where F: FnOnce( - &Router, + &Router, &dyn Api, &dyn Storage, ) -> T, @@ -239,8 +271,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, @@ -252,6 +284,7 @@ where IbcT: Ibc, GovT: Gov, StargateT: Stargate, + AnygateT: Anygate, CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, { @@ -388,8 +421,8 @@ where } } -impl - App +impl + App where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -403,6 +436,7 @@ where IbcT: Ibc, GovT: Gov, StargateT: Stargate, + AnygateT: Anygate, { /// Sets the initial block properties. pub fn set_block(&mut self, block: BlockInfo) { @@ -506,7 +540,7 @@ where /// The Router plays a critical role in managing and directing /// transactions within the Cosmos blockchain. #[derive(Clone)] -pub struct Router { +pub struct Router { /// Wasm module instance to be used in this [Router]. pub(crate) wasm: Wasm, /// Bank module instance to be used in this [Router]. @@ -523,10 +557,12 @@ pub struct Router { pub gov: Gov, /// Stargate module instance to be used in this [Router]. pub stargate: Stargate, + /// AnyGate handler instance to be used in this [Router]. + pub anygate: Anygate, } -impl - Router +impl + Router where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -538,6 +574,7 @@ where IbcT: Ibc, GovT: Gov, StargateT: Stargate, + AnygateT: Anygate, { /// Returns a querier populated with the instance of this [Router]. pub fn querier<'a>( @@ -625,8 +662,8 @@ pub trait CosmosRouter { ) -> AnyResult; } -impl CosmosRouter - for Router +impl CosmosRouter + for Router where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -638,6 +675,7 @@ where IbcT: Ibc, GovT: Gov, StargateT: Stargate, + AnygateT: Anygate, { type ExecC = CustomT::ExecT; type QueryC = CustomT::QueryT; diff --git a/src/app_builder.rs b/src/app_builder.rs index 56434c17..970bea0e 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -1,9 +1,9 @@ -//!AppBuilder helps you set up your test blockchain environment step by step [App]. +//! AppBuilder helps you set up your test blockchain environment step by step [App]. use crate::{ - App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingModule, Gov, GovFailingModule, - Ibc, IbcFailingModule, Module, Router, StakeKeeper, Staking, Stargate, StargateFailingModule, - Wasm, WasmKeeper, + Anygate, App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingAnygate, + FailingModule, Gov, GovFailingModule, Ibc, IbcFailingModule, Module, Router, StakeKeeper, + Staking, Stargate, StargateFailingModule, Wasm, WasmKeeper, }; use cosmwasm_std::testing::{mock_env, MockApi, MockStorage}; use cosmwasm_std::{Api, BlockInfo, CustomMsg, CustomQuery, Empty, Storage}; @@ -39,11 +39,13 @@ pub type BasicAppBuilder = AppBuilder< IbcFailingModule, GovFailingModule, StargateFailingModule, + FailingAnygate, >; /// 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, @@ -55,6 +57,7 @@ pub struct AppBuilder { fn default() -> Self { @@ -88,6 +92,7 @@ impl IbcFailingModule, GovFailingModule, StargateFailingModule, + FailingAnygate, > { /// Creates builder with default components working with empty exec and query messages. @@ -104,6 +109,7 @@ impl ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), stargate: StargateFailingModule::new(), + anygate: FailingAnygate, } } } @@ -120,6 +126,7 @@ impl IbcFailingModule, GovFailingModule, StargateFailingModule, + FailingAnygate, > where ExecC: CustomMsg + DeserializeOwned + 'static, @@ -140,12 +147,25 @@ where ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), stargate: StargateFailingModule::new(), + anygate: FailingAnygate, } } } -impl - AppBuilder +impl + AppBuilder< + BankT, + ApiT, + StorageT, + CustomT, + WasmT, + StakingT, + DistrT, + IbcT, + GovT, + StargateT, + AnygateT, + > where CustomT: Module, WasmT: Wasm, @@ -158,8 +178,19 @@ where pub fn with_wasm>( self, wasm: NewWasm, - ) -> AppBuilder - { + ) -> AppBuilder< + BankT, + ApiT, + StorageT, + CustomT, + NewWasm, + StakingT, + DistrT, + IbcT, + GovT, + StargateT, + AnygateT, + > { let AppBuilder { bank, api, @@ -171,6 +202,7 @@ where ibc, gov, stargate, + anygate, .. } = self; @@ -186,6 +218,7 @@ where ibc, gov, stargate, + anygate, } } @@ -193,8 +226,19 @@ where pub fn with_bank( self, bank: NewBank, - ) -> AppBuilder - { + ) -> AppBuilder< + NewBank, + ApiT, + StorageT, + CustomT, + WasmT, + StakingT, + DistrT, + IbcT, + GovT, + StargateT, + AnygateT, + > { let AppBuilder { wasm, api, @@ -206,6 +250,7 @@ where ibc, gov, stargate, + anygate, .. } = self; @@ -221,6 +266,7 @@ where ibc, gov, stargate, + anygate, } } @@ -228,8 +274,19 @@ where pub fn with_api( self, api: NewApi, - ) -> AppBuilder - { + ) -> AppBuilder< + BankT, + NewApi, + StorageT, + CustomT, + WasmT, + StakingT, + DistrT, + IbcT, + GovT, + StargateT, + AnygateT, + > { let AppBuilder { wasm, bank, @@ -241,6 +298,7 @@ where ibc, gov, stargate, + anygate, .. } = self; @@ -256,6 +314,7 @@ where ibc, gov, stargate, + anygate, } } @@ -263,8 +322,19 @@ where pub fn with_storage( self, storage: NewStorage, - ) -> AppBuilder - { + ) -> AppBuilder< + BankT, + ApiT, + NewStorage, + CustomT, + WasmT, + StakingT, + DistrT, + IbcT, + GovT, + StargateT, + AnygateT, + > { let AppBuilder { wasm, api, @@ -276,6 +346,7 @@ where ibc, gov, stargate, + anygate, .. } = self; @@ -291,6 +362,7 @@ where ibc, gov, stargate, + anygate, } } @@ -302,8 +374,19 @@ where pub fn with_custom( self, custom: NewCustom, - ) -> AppBuilder - { + ) -> AppBuilder< + BankT, + ApiT, + StorageT, + NewCustom, + WasmT, + StakingT, + DistrT, + IbcT, + GovT, + StargateT, + AnygateT, + > { let AppBuilder { wasm, bank, @@ -315,6 +398,7 @@ where ibc, gov, stargate, + anygate, .. } = self; @@ -330,6 +414,7 @@ where ibc, gov, stargate, + anygate, } } @@ -337,8 +422,19 @@ where pub fn with_staking( self, staking: NewStaking, - ) -> AppBuilder - { + ) -> AppBuilder< + BankT, + ApiT, + StorageT, + CustomT, + WasmT, + NewStaking, + DistrT, + IbcT, + GovT, + StargateT, + AnygateT, + > { let AppBuilder { wasm, api, @@ -350,6 +446,7 @@ where ibc, gov, stargate, + anygate, .. } = self; @@ -365,6 +462,7 @@ where ibc, gov, stargate, + anygate, } } @@ -383,6 +481,7 @@ where IbcT, GovT, StargateT, + AnygateT, > { let AppBuilder { wasm, @@ -395,6 +494,7 @@ where ibc, gov, stargate, + anygate, .. } = self; @@ -410,6 +510,7 @@ where ibc, gov, stargate, + anygate, } } @@ -423,8 +524,19 @@ where pub fn with_ibc( self, ibc: NewIbc, - ) -> AppBuilder - { + ) -> AppBuilder< + BankT, + ApiT, + StorageT, + CustomT, + WasmT, + StakingT, + DistrT, + NewIbc, + GovT, + StargateT, + AnygateT, + > { let AppBuilder { wasm, api, @@ -436,6 +548,7 @@ where distribution, gov, stargate, + anygate, .. } = self; @@ -447,6 +560,7 @@ where wasm, custom, staking, + anygate, distribution, ibc, gov, @@ -458,8 +572,19 @@ where pub fn with_gov( self, gov: NewGov, - ) -> AppBuilder - { + ) -> AppBuilder< + BankT, + ApiT, + StorageT, + CustomT, + WasmT, + StakingT, + DistrT, + IbcT, + NewGov, + StargateT, + AnygateT, + > { let AppBuilder { wasm, api, @@ -471,6 +596,7 @@ where distribution, ibc, stargate, + anygate, .. } = self; @@ -486,6 +612,7 @@ where ibc, gov, stargate, + anygate, } } @@ -493,8 +620,19 @@ where pub fn with_stargate( self, stargate: NewStargate, - ) -> AppBuilder - { + ) -> AppBuilder< + BankT, + ApiT, + StorageT, + CustomT, + WasmT, + StakingT, + DistrT, + IbcT, + GovT, + NewStargate, + AnygateT, + > { let AppBuilder { wasm, api, @@ -506,6 +644,7 @@ where distribution, ibc, gov, + anygate, .. } = self; @@ -521,6 +660,7 @@ where ibc, gov, stargate, + anygate, } } @@ -536,7 +676,7 @@ where pub fn build( self, init_fn: F, - ) -> App + ) -> App where BankT: Bank, ApiT: Api, @@ -548,8 +688,9 @@ where IbcT: Ibc, GovT: Gov, StargateT: Stargate, + AnygateT: Anygate, F: FnOnce( - &mut Router, + &mut Router, &dyn Api, &mut dyn Storage, ), @@ -563,6 +704,7 @@ where ibc: self.ibc, gov: self.gov, stargate: self.stargate, + anygate: self.anygate, }; let mut app = App { diff --git a/src/lib.rs b/src/lib.rs index f6e7af42..3059b98f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -149,7 +149,7 @@ mod wasm; pub use crate::addresses::{ AddressGenerator, IntoAddr, IntoBech32, IntoBech32m, SimpleAddressGenerator, }; -pub use crate::anygate::{AnyGate, FailingAnyGate}; +pub use crate::anygate::{Anygate, FailingAnygate}; pub use crate::api::{MockApiBech32, MockApiBech32m}; pub use crate::app::{ custom_app, next_block, no_init, App, BasicApp, CosmosRouter, Router, SudoMsg, diff --git a/src/staking.rs b/src/staking.rs index 6f60a77b..5729e6bc 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1026,8 +1026,8 @@ mod test { use super::*; use crate::stargate::StargateFailingModule; use crate::{ - app::MockRouter, BankKeeper, FailingModule, GovFailingModule, IbcFailingModule, Router, - WasmKeeper, + app::MockRouter, BankKeeper, FailingAnygate, FailingModule, GovFailingModule, + IbcFailingModule, Router, WasmKeeper, }; use cosmwasm_std::{ from_json, @@ -1045,6 +1045,7 @@ mod test { IbcFailingModule, GovFailingModule, StargateFailingModule, + FailingAnygate, >; fn mock_router() -> BasicRouter { @@ -1057,6 +1058,7 @@ mod test { ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), stargate: StargateFailingModule::new(), + anygate: FailingAnygate, } } diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 685234eb..cc01c9e0 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 35bf331b..f29c3df7 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1259,7 +1259,7 @@ mod test { use crate::stargate::StargateFailingModule; use crate::test_helpers::{caller, error, payout}; use crate::transactions::StorageTransaction; - use crate::{GovFailingModule, IbcFailingModule}; + use crate::{FailingAnygate, GovFailingModule, IbcFailingModule}; use cosmwasm_std::testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage}; use cosmwasm_std::{ coin, from_json, to_json_vec, CanonicalAddr, CodeInfoResponse, CosmosMsg, Empty, HexBinary, @@ -1276,6 +1276,7 @@ mod test { IbcFailingModule, GovFailingModule, StargateFailingModule, + FailingAnygate, >; fn wasm_keeper() -> WasmKeeper { @@ -1292,6 +1293,7 @@ mod test { ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), stargate: StargateFailingModule::new(), + anygate: FailingAnygate, } } From 55a6a2600b72af6bfc3cdcfe727f6d6003347a98 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 19 Apr 2024 09:32:19 +0200 Subject: [PATCH 188/250] Implemented anygate. --- src/anygate.rs | 81 ++++++++++++++++++-- src/app.rs | 14 +++- src/app_builder.rs | 48 ++++++++++++ src/lib.rs | 2 +- src/test_helpers/stargate.rs | 8 +- src/tests/test_stargate.rs | 10 +-- tests/test_app_builder/test_with_stargate.rs | 6 +- 7 files changed, 145 insertions(+), 24 deletions(-) diff --git a/src/anygate.rs b/src/anygate.rs index e66581fa..60d8d248 100644 --- a/src/anygate.rs +++ b/src/anygate.rs @@ -28,10 +28,10 @@ pub trait Anygate { { let _ = (api, storage, router, block); bail!( - "Unexpected execute from {}, type_url={}, value={}", - sender, + "Unexpected stargate execute: type_url={}, value={} from {}", type_url, - value + value, + sender, ) } @@ -50,7 +50,7 @@ pub trait Anygate { QueryC: CustomQuery + DeserializeOwned + 'static, { let _ = (api, storage, router, block); - bail!("Unexpected execute from {}, msg={:?}", sender, msg,) + bail!("Unexpected any execute: msg={:?} from {}", msg, sender) } /// Processes `QueryRequest::Stargate` query. @@ -64,7 +64,7 @@ pub trait Anygate { data: Binary, ) -> AnyResult { let _ = (api, storage, querier, block); - bail!("Unexpected query, path={}, data={}", path, data) + bail!("Unexpected stargate query: path={}, data={}", path, data) } /// Processes `QueryRequest::Grpc` query. @@ -77,12 +77,77 @@ pub trait Anygate { request: GrpcQuery, ) -> AnyResult { let _ = (api, storage, querier, block); - bail!("Unexpected query, request={:?}", request) + bail!("Unexpected grpc query: request={:?}", request) } } -/// Always failing handler for `Stargate`/`Any` message variants -/// and `Stargate`/`Grpc` queries. +/// Always failing handler for `Stargate`/`Any` message variants and `Stargate`/`Grpc` queries. pub struct FailingAnygate; impl Anygate for FailingAnygate {} + +/// Always accepting handler for `Stargate`/`Any` message variants and `Stargate`/`Grpc` queries. +pub struct AcceptingAnygate; + +impl Anygate for AcceptingAnygate { + 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, + { + let _ = (api, storage, router, block, sender, type_url, value); + Ok(AppResponse::default()) + } + + fn execute_any( + &self, + api: &dyn Api, + storage: &mut dyn Storage, + router: &dyn CosmosRouter, + block: &BlockInfo, + sender: Addr, + msg: AnyMsg, + ) -> AnyResult + where + ExecC: CustomMsg + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + let _ = (api, storage, router, block, sender, msg); + Ok(AppResponse::default()) + } + + fn query_stargate( + &self, + api: &dyn Api, + storage: &dyn Storage, + querier: &dyn Querier, + block: &BlockInfo, + path: String, + data: Binary, + ) -> AnyResult { + let _ = (api, storage, querier, block, path, data); + Ok(Binary::default()) + } + + fn query_grpc( + &self, + api: &dyn Api, + storage: &dyn Storage, + querier: &dyn Querier, + block: &BlockInfo, + request: GrpcQuery, + ) -> AnyResult { + let _ = (api, storage, querier, block, request); + //TODO this must be fixed + Ok(Binary::default()) + } +} diff --git a/src/app.rs b/src/app.rs index ce12fd05..578ef597 100644 --- a/src/app.rs +++ b/src/app.rs @@ -698,9 +698,13 @@ 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), + #[allow(deprecated)] + CosmosMsg::Stargate { type_url, value } => self + .anygate + .execute_stargate(api, storage, self, block, sender, type_url, value), CosmosMsg::Any(msg) => self - .stargate - .execute(api, storage, self, block, sender, msg), + .anygate + .execute_any(api, storage, self, block, sender, msg), _ => bail!("Cannot execute {:?}", msg), } } @@ -722,7 +726,11 @@ 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::Grpc(req) => self.stargate.query(api, storage, &querier, block, req), + #[allow(deprecated)] + QueryRequest::Stargate { path, data } => self + .anygate + .query_stargate(api, storage, &querier, block, path, data), + QueryRequest::Grpc(req) => self.anygate.query_grpc(api, storage, &querier, block, req), _ => unimplemented!(), } } diff --git a/src/app_builder.rs b/src/app_builder.rs index 970bea0e..abdd422c 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -664,6 +664,54 @@ where } } + /// Overwrites the default anygate interface. + pub fn with_anygate( + self, + anygate: NewAnygate, + ) -> AppBuilder< + BankT, + ApiT, + StorageT, + CustomT, + WasmT, + StakingT, + DistrT, + IbcT, + GovT, + StargateT, + NewAnygate, + > { + let AppBuilder { + wasm, + api, + storage, + custom, + block, + staking, + bank, + distribution, + ibc, + gov, + stargate, + .. + } = self; + + AppBuilder { + api, + block, + storage, + bank, + wasm, + custom, + staking, + distribution, + ibc, + gov, + stargate, + anygate, + } + } + /// Overwrites the initial block. pub fn with_block(mut self, block: BlockInfo) -> Self { self.block = block; diff --git a/src/lib.rs b/src/lib.rs index 3059b98f..49dee462 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -149,7 +149,7 @@ mod wasm; pub use crate::addresses::{ AddressGenerator, IntoAddr, IntoBech32, IntoBech32m, SimpleAddressGenerator, }; -pub use crate::anygate::{Anygate, FailingAnygate}; +pub use crate::anygate::{AcceptingAnygate, Anygate, FailingAnygate}; pub use crate::api::{MockApiBech32, MockApiBech32m}; pub use crate::app::{ custom_app, next_block, no_init, App, BasicApp, CosmosRouter, Router, SudoMsg, diff --git a/src/test_helpers/stargate.rs b/src/test_helpers/stargate.rs index c624c2c3..a4165354 100644 --- a/src/test_helpers/stargate.rs +++ b/src/test_helpers/stargate.rs @@ -1,6 +1,6 @@ use crate::{Contract, ContractWrapper}; use cosmwasm_std::{ - AnyMsg, Binary, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdResult, + Binary, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdResult, }; fn instantiate(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { @@ -8,10 +8,12 @@ fn instantiate(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> St } fn execute(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { - Ok(Response::new().add_message(CosmosMsg::Any(AnyMsg { + #[allow(deprecated)] + let msg = CosmosMsg::Stargate { type_url: "/this.is.a.stargate.test.helper".to_string(), value: Default::default(), - }))) + }; + Ok(Response::new().add_message(msg)) } fn query(_deps: Deps, _env: Env, _msg: Empty) -> StdResult { diff --git a/src/tests/test_stargate.rs b/src/tests/test_stargate.rs index 157b61b5..94f19030 100644 --- a/src/tests/test_stargate.rs +++ b/src/tests/test_stargate.rs @@ -1,9 +1,9 @@ use crate::test_helpers::stargate; -use crate::{no_init, App, AppBuilder, Executor, StargateAcceptingModule}; +use crate::{no_init, AcceptingAnygate, App, AppBuilder, Executor}; use cosmwasm_std::Empty; #[test] -fn default_failing_stargate_module_should_work() { +fn default_failing_stargate_handler_should_work() { let mut app = App::default(); // store the contract @@ -27,13 +27,13 @@ fn default_failing_stargate_module_should_work() { .source() .unwrap() .to_string() - .starts_with("Unexpected exec msg AnyMsg")); + .starts_with("Unexpected stargate execute")); } #[test] -fn accepting_stargate_module_should_work() { +fn accepting_stargate_handler_should_work() { let mut app = AppBuilder::default() - .with_stargate(StargateAcceptingModule::new()) + .with_anygate(AcceptingAnygate) .build(no_init); // store the contract diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index 85a61e0e..74a597fe 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -1,7 +1,7 @@ use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; use cosmwasm_std::{to_json_vec, AnyMsg, CosmosMsg, Empty, GrpcQuery, QueryRequest}; use cw_multi_test::{ - no_init, AppBuilder, Executor, Stargate, StargateAcceptingModule, StargateFailingModule, + no_init, AcceptingAnygate, AppBuilder, Executor, Stargate, StargateFailingModule, }; type MyStargateKeeper = MyKeeper; @@ -56,9 +56,7 @@ fn building_app_with_custom_stargate_should_work() { #[test] fn building_app_with_accepting_stargate_should_work() { let app_builder = AppBuilder::default(); - let mut app = app_builder - .with_stargate(StargateAcceptingModule::new()) - .build(no_init); + let mut app = app_builder.with_anygate(AcceptingAnygate).build(no_init); // prepare user addresses let sender_addr = app.api().addr_make("sender"); From da797c80216bf886bd038e3f6604f0a716d8f701 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 19 Apr 2024 10:42:48 +0200 Subject: [PATCH 189/250] Fixed tests. --- src/anygate.rs | 122 +++++------ src/app.rs | 83 ++------ src/app_builder.rs | 211 +++---------------- src/staking.rs | 3 - src/tests/test_app.rs | 4 +- src/wasm.rs | 3 - tests/test_app_builder/test_with_stargate.rs | 205 +++++++++++++----- 7 files changed, 261 insertions(+), 370 deletions(-) diff --git a/src/anygate.rs b/src/anygate.rs index 60d8d248..82f3efda 100644 --- a/src/anygate.rs +++ b/src/anygate.rs @@ -4,7 +4,8 @@ use crate::error::AnyResult; use crate::{AppResponse, CosmosRouter}; use anyhow::bail; use cosmwasm_std::{ - Addr, AnyMsg, Api, Binary, BlockInfo, CustomMsg, CustomQuery, GrpcQuery, Querier, Storage, + to_json_binary, Addr, AnyMsg, Api, Binary, BlockInfo, CustomMsg, CustomQuery, Empty, GrpcQuery, + Querier, Storage, }; use serde::de::DeserializeOwned; @@ -14,10 +15,10 @@ pub trait Anygate { /// Processes `CosmosMsg::Stargate` message variant. fn execute_stargate( &self, - api: &dyn Api, - storage: &mut dyn Storage, - router: &dyn CosmosRouter, - block: &BlockInfo, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, sender: Addr, type_url: String, value: Binary, @@ -26,7 +27,6 @@ pub trait Anygate { ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { - let _ = (api, storage, router, block); bail!( "Unexpected stargate execute: type_url={}, value={} from {}", type_url, @@ -35,13 +35,26 @@ pub trait Anygate { ) } + /// 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) + } + /// Processes `CosmosMsg::Any` message variant. fn execute_any( &self, - api: &dyn Api, - storage: &mut dyn Storage, - router: &dyn CosmosRouter, - block: &BlockInfo, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, sender: Addr, msg: AnyMsg, ) -> AnyResult @@ -49,34 +62,18 @@ pub trait Anygate { ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { - let _ = (api, storage, router, block); bail!("Unexpected any execute: msg={:?} from {}", msg, 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 { - let _ = (api, storage, querier, block); - bail!("Unexpected stargate query: path={}, data={}", path, data) - } - /// Processes `QueryRequest::Grpc` query. fn query_grpc( &self, - api: &dyn Api, - storage: &dyn Storage, - querier: &dyn Querier, - block: &BlockInfo, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, request: GrpcQuery, ) -> AnyResult { - let _ = (api, storage, querier, block); bail!("Unexpected grpc query: request={:?}", request) } } @@ -92,62 +89,57 @@ pub struct AcceptingAnygate; impl Anygate for AcceptingAnygate { fn execute_stargate( &self, - api: &dyn Api, - storage: &mut dyn Storage, - router: &dyn CosmosRouter, - block: &BlockInfo, - sender: Addr, - type_url: String, - value: Binary, + _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, { - let _ = (api, storage, router, block, sender, type_url, value); Ok(AppResponse::default()) } + fn query_stargate( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + _path: String, + _data: Binary, + ) -> AnyResult { + to_json_binary(&Empty {}).map_err(Into::into) + } + fn execute_any( &self, - api: &dyn Api, - storage: &mut dyn Storage, - router: &dyn CosmosRouter, - block: &BlockInfo, - sender: Addr, - msg: AnyMsg, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + _sender: Addr, + _msg: AnyMsg, ) -> AnyResult where ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { - let _ = (api, storage, router, block, sender, msg); Ok(AppResponse::default()) } - fn query_stargate( - &self, - api: &dyn Api, - storage: &dyn Storage, - querier: &dyn Querier, - block: &BlockInfo, - path: String, - data: Binary, - ) -> AnyResult { - let _ = (api, storage, querier, block, path, data); - Ok(Binary::default()) - } - fn query_grpc( &self, - api: &dyn Api, - storage: &dyn Storage, - querier: &dyn Querier, - block: &BlockInfo, - request: GrpcQuery, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + _request: GrpcQuery, ) -> AnyResult { - let _ = (api, storage, querier, block, request); - //TODO this must be fixed Ok(Binary::default()) } } diff --git a/src/app.rs b/src/app.rs index 578ef597..6d5b1ea9 100644 --- a/src/app.rs +++ b/src/app.rs @@ -9,7 +9,6 @@ use crate::prefixed_storage::{ prefixed, prefixed_multilevel, prefixed_multilevel_read, prefixed_read, }; use crate::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking, StakingSudo}; -use crate::stargate::{Stargate, StargateFailingModule}; use crate::transactions::transactional; use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; use crate::{Anygate, AppBuilder, FailingAnygate, GovFailingModule, IbcFailingModule}; @@ -42,7 +41,6 @@ pub type BasicApp = App< DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailingModule, FailingAnygate, >; @@ -60,18 +58,17 @@ pub struct App< Distr = DistributionKeeper, Ibc = IbcFailingModule, Gov = GovFailingModule, - Stargate = StargateFailingModule, Anygate = FailingAnygate, > { - pub(crate) router: Router, + pub(crate) router: Router, pub(crate) api: Api, pub(crate) storage: Storage, pub(crate) block: BlockInfo, } /// No-op application initialization function. -pub fn no_init( - router: &mut Router, +pub fn no_init( + router: &mut Router, api: &dyn Api, storage: &mut dyn Storage, ) { @@ -97,7 +94,6 @@ impl BasicApp { DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailingModule, FailingAnygate, >, &dyn Api, @@ -123,7 +119,6 @@ where DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailingModule, FailingAnygate, >, &dyn Api, @@ -133,21 +128,8 @@ where AppBuilder::new_custom().build(init_fn) } -impl - Querier - for App< - BankT, - ApiT, - StorageT, - CustomT, - WasmT, - StakingT, - DistrT, - IbcT, - GovT, - StargateT, - AnygateT, - > +impl Querier + for App where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -160,7 +142,6 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - StargateT: Stargate, AnygateT: Anygate, { fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { @@ -170,21 +151,9 @@ where } } -impl +impl Executor - for App< - BankT, - ApiT, - StorageT, - CustomT, - WasmT, - StakingT, - DistrT, - IbcT, - GovT, - StargateT, - AnygateT, - > + for App where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -197,7 +166,6 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - StargateT: Stargate, AnygateT: Anygate, { fn execute(&mut self, sender: Addr, msg: CosmosMsg) -> AnyResult { @@ -207,8 +175,8 @@ where } } -impl - App +impl + App where WasmT: Wasm, BankT: Bank, @@ -219,13 +187,10 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - StargateT: Stargate, AnygateT: Anygate, { /// Returns a shared reference to application's router. - pub fn router( - &self, - ) -> &Router { + pub fn router(&self) -> &Router { &self.router } @@ -248,7 +213,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, @@ -260,7 +225,7 @@ where pub fn read_module(&self, query_fn: F) -> T where F: FnOnce( - &Router, + &Router, &dyn Api, &dyn Storage, ) -> T, @@ -271,8 +236,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, @@ -283,7 +248,6 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - StargateT: Stargate, AnygateT: Anygate, CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -421,8 +385,8 @@ where } } -impl - App +impl + App where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -435,7 +399,6 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - StargateT: Stargate, AnygateT: Anygate, { /// Sets the initial block properties. @@ -540,7 +503,7 @@ where /// The Router plays a critical role in managing and directing /// transactions within the Cosmos blockchain. #[derive(Clone)] -pub struct Router { +pub struct Router { /// Wasm module instance to be used in this [Router]. pub(crate) wasm: Wasm, /// Bank module instance to be used in this [Router]. @@ -555,14 +518,12 @@ pub struct Router - Router +impl + Router where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -573,7 +534,6 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - StargateT: Stargate, AnygateT: Anygate, { /// Returns a querier populated with the instance of this [Router]. @@ -662,8 +622,8 @@ pub trait CosmosRouter { ) -> AnyResult; } -impl CosmosRouter - for Router +impl CosmosRouter + for Router where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -674,7 +634,6 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - StargateT: Stargate, AnygateT: Anygate, { type ExecC = CustomT::ExecT; diff --git a/src/app_builder.rs b/src/app_builder.rs index abdd422c..2a2196b2 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -3,7 +3,7 @@ use crate::{ Anygate, App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingAnygate, FailingModule, Gov, GovFailingModule, Ibc, IbcFailingModule, Module, Router, StakeKeeper, - Staking, Stargate, StargateFailingModule, Wasm, WasmKeeper, + Staking, Wasm, WasmKeeper, }; use cosmwasm_std::testing::{mock_env, MockApi, MockStorage}; use cosmwasm_std::{Api, BlockInfo, CustomMsg, CustomQuery, Empty, Storage}; @@ -38,14 +38,12 @@ pub type BasicAppBuilder = AppBuilder< DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailingModule, FailingAnygate, >; /// 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, @@ -56,7 +54,6 @@ pub struct AppBuilder { @@ -91,7 +87,6 @@ impl DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailingModule, FailingAnygate, > { @@ -108,7 +103,6 @@ impl distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), - stargate: StargateFailingModule::new(), anygate: FailingAnygate, } } @@ -125,7 +119,6 @@ impl DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailingModule, FailingAnygate, > where @@ -146,26 +139,13 @@ where distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), - stargate: StargateFailingModule::new(), anygate: FailingAnygate, } } } -impl - AppBuilder< - BankT, - ApiT, - StorageT, - CustomT, - WasmT, - StakingT, - DistrT, - IbcT, - GovT, - StargateT, - AnygateT, - > +impl + AppBuilder where CustomT: Module, WasmT: Wasm, @@ -178,19 +158,8 @@ where pub fn with_wasm>( self, wasm: NewWasm, - ) -> AppBuilder< - BankT, - ApiT, - StorageT, - CustomT, - NewWasm, - StakingT, - DistrT, - IbcT, - GovT, - StargateT, - AnygateT, - > { + ) -> AppBuilder + { let AppBuilder { bank, api, @@ -201,7 +170,6 @@ where distribution, ibc, gov, - stargate, anygate, .. } = self; @@ -217,7 +185,6 @@ where distribution, ibc, gov, - stargate, anygate, } } @@ -226,19 +193,8 @@ where pub fn with_bank( self, bank: NewBank, - ) -> AppBuilder< - NewBank, - ApiT, - StorageT, - CustomT, - WasmT, - StakingT, - DistrT, - IbcT, - GovT, - StargateT, - AnygateT, - > { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -249,7 +205,6 @@ where distribution, ibc, gov, - stargate, anygate, .. } = self; @@ -265,7 +220,6 @@ where distribution, ibc, gov, - stargate, anygate, } } @@ -274,19 +228,8 @@ where pub fn with_api( self, api: NewApi, - ) -> AppBuilder< - BankT, - NewApi, - StorageT, - CustomT, - WasmT, - StakingT, - DistrT, - IbcT, - GovT, - StargateT, - AnygateT, - > { + ) -> AppBuilder + { let AppBuilder { wasm, bank, @@ -297,7 +240,6 @@ where distribution, ibc, gov, - stargate, anygate, .. } = self; @@ -313,7 +255,6 @@ where distribution, ibc, gov, - stargate, anygate, } } @@ -322,19 +263,8 @@ where pub fn with_storage( self, storage: NewStorage, - ) -> AppBuilder< - BankT, - ApiT, - NewStorage, - CustomT, - WasmT, - StakingT, - DistrT, - IbcT, - GovT, - StargateT, - AnygateT, - > { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -345,7 +275,6 @@ where distribution, ibc, gov, - stargate, anygate, .. } = self; @@ -361,7 +290,6 @@ where distribution, ibc, gov, - stargate, anygate, } } @@ -374,19 +302,8 @@ where pub fn with_custom( self, custom: NewCustom, - ) -> AppBuilder< - BankT, - ApiT, - StorageT, - NewCustom, - WasmT, - StakingT, - DistrT, - IbcT, - GovT, - StargateT, - AnygateT, - > { + ) -> AppBuilder + { let AppBuilder { wasm, bank, @@ -397,7 +314,6 @@ where distribution, ibc, gov, - stargate, anygate, .. } = self; @@ -413,7 +329,6 @@ where distribution, ibc, gov, - stargate, anygate, } } @@ -422,19 +337,8 @@ where pub fn with_staking( self, staking: NewStaking, - ) -> AppBuilder< - BankT, - ApiT, - StorageT, - CustomT, - WasmT, - NewStaking, - DistrT, - IbcT, - GovT, - StargateT, - AnygateT, - > { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -445,7 +349,6 @@ where distribution, ibc, gov, - stargate, anygate, .. } = self; @@ -461,7 +364,6 @@ where distribution, ibc, gov, - stargate, anygate, } } @@ -480,7 +382,6 @@ where NewDistribution, IbcT, GovT, - StargateT, AnygateT, > { let AppBuilder { @@ -493,7 +394,6 @@ where bank, ibc, gov, - stargate, anygate, .. } = self; @@ -509,7 +409,6 @@ where distribution, ibc, gov, - stargate, anygate, } } @@ -524,19 +423,8 @@ where pub fn with_ibc( self, ibc: NewIbc, - ) -> AppBuilder< - BankT, - ApiT, - StorageT, - CustomT, - WasmT, - StakingT, - DistrT, - NewIbc, - GovT, - StargateT, - AnygateT, - > { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -547,7 +435,6 @@ where bank, distribution, gov, - stargate, anygate, .. } = self; @@ -564,7 +451,6 @@ where distribution, ibc, gov, - stargate, } } @@ -572,19 +458,8 @@ where pub fn with_gov( self, gov: NewGov, - ) -> AppBuilder< - BankT, - ApiT, - StorageT, - CustomT, - WasmT, - StakingT, - DistrT, - IbcT, - NewGov, - StargateT, - AnygateT, - > { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -595,7 +470,6 @@ where bank, distribution, ibc, - stargate, anygate, .. } = self; @@ -611,28 +485,16 @@ where distribution, ibc, gov, - stargate, anygate, } } /// Overwrites the default stargate interface. - pub fn with_stargate( + pub fn with_stargate( self, - stargate: NewStargate, - ) -> AppBuilder< - BankT, - ApiT, - StorageT, - CustomT, - WasmT, - StakingT, - DistrT, - IbcT, - GovT, - NewStargate, - AnygateT, - > { + anygate: NewStargate, + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -644,7 +506,6 @@ where distribution, ibc, gov, - anygate, .. } = self; @@ -659,7 +520,6 @@ where distribution, ibc, gov, - stargate, anygate, } } @@ -668,19 +528,8 @@ where pub fn with_anygate( self, anygate: NewAnygate, - ) -> AppBuilder< - BankT, - ApiT, - StorageT, - CustomT, - WasmT, - StakingT, - DistrT, - IbcT, - GovT, - StargateT, - NewAnygate, - > { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -692,7 +541,6 @@ where distribution, ibc, gov, - stargate, .. } = self; @@ -707,7 +555,6 @@ where distribution, ibc, gov, - stargate, anygate, } } @@ -724,7 +571,7 @@ where pub fn build( self, init_fn: F, - ) -> App + ) -> App where BankT: Bank, ApiT: Api, @@ -735,10 +582,9 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - StargateT: Stargate, AnygateT: Anygate, F: FnOnce( - &mut Router, + &mut Router, &dyn Api, &mut dyn Storage, ), @@ -751,7 +597,6 @@ where distribution: self.distribution, ibc: self.ibc, gov: self.gov, - stargate: self.stargate, anygate: self.anygate, }; diff --git a/src/staking.rs b/src/staking.rs index 5729e6bc..490ed3fc 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1024,7 +1024,6 @@ impl Module for DistributionKeeper { #[cfg(test)] mod test { use super::*; - use crate::stargate::StargateFailingModule; use crate::{ app::MockRouter, BankKeeper, FailingAnygate, FailingModule, GovFailingModule, IbcFailingModule, Router, WasmKeeper, @@ -1044,7 +1043,6 @@ mod test { DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailingModule, FailingAnygate, >; @@ -1057,7 +1055,6 @@ mod test { distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), - stargate: StargateFailingModule::new(), anygate: FailingAnygate, } } diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index cc01c9e0..3a30c6ef 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 f29c3df7..ab406f4a 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1256,7 +1256,6 @@ mod test { use crate::bank::BankKeeper; use crate::module::FailingModule; use crate::staking::{DistributionKeeper, StakeKeeper}; - use crate::stargate::StargateFailingModule; use crate::test_helpers::{caller, error, payout}; use crate::transactions::StorageTransaction; use crate::{FailingAnygate, GovFailingModule, IbcFailingModule}; @@ -1275,7 +1274,6 @@ mod test { DistributionKeeper, IbcFailingModule, GovFailingModule, - StargateFailingModule, FailingAnygate, >; @@ -1292,7 +1290,6 @@ mod test { distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), - stargate: StargateFailingModule::new(), anygate: FailingAnygate, } } diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index 74a597fe..6c7f81ba 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -1,56 +1,136 @@ -use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; -use cosmwasm_std::{to_json_vec, AnyMsg, CosmosMsg, Empty, GrpcQuery, QueryRequest}; +use anyhow::bail; +use cosmwasm_std::{ + to_json_vec, Addr, AnyMsg, Api, Binary, BlockInfo, CosmosMsg, CustomMsg, CustomQuery, Empty, + Event, GrpcQuery, Querier, QueryRequest, Storage, +}; +use cw_multi_test::error::AnyResult; use cw_multi_test::{ - no_init, AcceptingAnygate, AppBuilder, Executor, Stargate, StargateFailingModule, + no_init, AcceptingAnygate, Anygate, AppBuilder, AppResponse, CosmosRouter, Executor, + FailingAnygate, }; - -type MyStargateKeeper = MyKeeper; - -impl Stargate for MyStargateKeeper {} - -const EXECUTE_MSG: &str = "stargate execute called"; -const QUERY_MSG: &str = "stargate query called"; +use serde::de::DeserializeOwned; + +const MSG_STARGATE_EXECUTE: &str = "stargate execute called"; +const MSG_STARGATE_QUERY: &str = "stargate query called"; +const MSG_ANY_EXECUTE: &str = "any execute called"; +const MSG_GRPC_QUERY: &str = "grpc query called"; + +struct StargateKeeper; + +impl Anygate for StargateKeeper { + 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!(MSG_STARGATE_EXECUTE) + } + + fn query_stargate( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + _path: String, + _data: Binary, + ) -> AnyResult { + bail!(MSG_STARGATE_QUERY) + } + + fn execute_any( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + _sender: Addr, + _msg: AnyMsg, + ) -> AnyResult + where + ExecC: CustomMsg + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + bail!(MSG_ANY_EXECUTE) + } + + fn query_grpc( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + _request: GrpcQuery, + ) -> AnyResult { + bail!(MSG_GRPC_QUERY) + } +} #[test] fn building_app_with_custom_stargate_should_work() { - // build custom stargate keeper - let stargate_keeper = MyStargateKeeper::new(EXECUTE_MSG, QUERY_MSG, NO_MESSAGE); - // build the application with custom stargate keeper let app_builder = AppBuilder::default(); - let mut app = app_builder.with_stargate(stargate_keeper).build(no_init); + let mut app = app_builder.with_stargate(StargateKeeper).build(no_init); // prepare user addresses let sender_addr = app.api().addr_make("sender"); - // executing stargate message should return - // an error defined in custom stargate keeper + // executing `stargate` message should return an error defined in custom stargate keeper + #[allow(deprecated)] + let msg = CosmosMsg::Stargate { + type_url: "test".to_string(), + value: Default::default(), + }; assert_eq!( - app.execute( - sender_addr, - CosmosMsg::Any(AnyMsg { - type_url: "test".to_string(), - value: Default::default() - }), - ) - .unwrap_err() - .to_string(), - EXECUTE_MSG, + app.execute(sender_addr.clone(), msg) + .unwrap_err() + .to_string(), + MSG_STARGATE_EXECUTE, ); - // executing stargate query should return - // an error defined in custom stargate keeper - let query: QueryRequest = QueryRequest::Grpc(GrpcQuery { + // executing `stargate` query should return an error defined in custom stargate keeper + #[allow(deprecated)] + let request: QueryRequest = QueryRequest::Stargate { path: "test".to_string(), data: Default::default(), + }; + assert!(app + .wrap() + .query::(&request) + .unwrap_err() + .to_string() + .ends_with(MSG_STARGATE_QUERY)); + + // executing `any` message should return an error defined in custom stargate keeper + let msg = CosmosMsg::Any(AnyMsg { + type_url: "test".to_string(), + value: Default::default(), }); assert_eq!( - app.wrap() - .raw_query(to_json_vec(&query).unwrap().as_slice()) - .unwrap() - .unwrap_err(), - QUERY_MSG + app.execute(sender_addr, msg).unwrap_err().to_string(), + MSG_ANY_EXECUTE, ); + + // executing `grpc` query should return an error defined in custom stargate keeper + let request: QueryRequest = QueryRequest::Grpc(GrpcQuery { + path: "test".to_string(), + data: Default::default(), + }); + assert!(app + .wrap() + .query::(&request) + .unwrap_err() + .to_string() + .ends_with(MSG_GRPC_QUERY)); } #[test] @@ -61,30 +141,51 @@ fn building_app_with_accepting_stargate_should_work() { // prepare user addresses let sender_addr = app.api().addr_make("sender"); - app.execute( - sender_addr, - CosmosMsg::Any(AnyMsg { - type_url: "test".to_string(), - value: Default::default(), - }), - ) - .unwrap(); + // executing `stargate` query should success and return empty values + #[allow(deprecated)] + let msg = CosmosMsg::Stargate { + type_url: "test".to_string(), + value: Default::default(), + }; + let AppResponse { events, data } = app.execute(sender_addr.clone(), msg).unwrap(); + assert_eq!(events, Vec::::new()); + assert_eq!(data, None); + + // executing `stargate` query should success and return Empty message + #[allow(deprecated)] + let request: QueryRequest = QueryRequest::Stargate { + path: "test".to_string(), + data: Default::default(), + }; + assert_eq!(app.wrap().query::(&request).unwrap(), Empty {}); - let _ = app - .wrap() - .query::(&QueryRequest::Grpc(GrpcQuery { - path: "test".to_string(), - data: Default::default(), - })) - .is_ok(); + // executing `any` message should success and return empty values + let msg = CosmosMsg::Any(AnyMsg { + type_url: "test".to_string(), + value: Default::default(), + }); + let AppResponse { events, data } = app.execute(sender_addr, msg).unwrap(); + assert_eq!(events, Vec::::new()); + assert_eq!(data, None); + + // executing `grpc` query should success and return empty binary + let request: QueryRequest = QueryRequest::Grpc(GrpcQuery { + path: "test".to_string(), + data: Default::default(), + }); + assert_eq!( + app.wrap() + .raw_query(to_json_vec(&request).unwrap().as_slice()) + .unwrap() + .unwrap(), + Binary::default() + ); } #[test] fn building_app_with_failing_stargate_should_work() { let app_builder = AppBuilder::default(); - let mut app = app_builder - .with_stargate(StargateFailingModule::new()) - .build(no_init); + let mut app = app_builder.with_stargate(FailingAnygate).build(no_init); // prepare user addresses let sender_addr = app.api().addr_make("sender"); From a252333f14b544d0841d2bb52c1b55a2c8219533 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 19 Apr 2024 15:23:39 +0200 Subject: [PATCH 190/250] Improved tests. --- tests/test_app_builder/test_with_stargate.rs | 57 ++++++++++++++------ 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index 6c7f81ba..9ff3c3e1 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -183,27 +183,54 @@ fn building_app_with_accepting_stargate_should_work() { } #[test] -fn building_app_with_failing_stargate_should_work() { +fn default_failing_stargate_should_work() { let app_builder = AppBuilder::default(); let mut app = app_builder.with_stargate(FailingAnygate).build(no_init); // prepare user addresses let sender_addr = app.api().addr_make("sender"); - app.execute( - sender_addr, - CosmosMsg::Any(AnyMsg { - type_url: "test".to_string(), - value: Default::default(), - }), - ) - .unwrap_err(); + #[allow(deprecated)] + let msg = CosmosMsg::Stargate { + type_url: "test".to_string(), + value: Default::default(), + }; + assert!(app + .execute(sender_addr.clone(), msg) + .unwrap_err() + .to_string() + .starts_with("Unexpected stargate execute")); - let _ = app + #[allow(deprecated)] + let request: QueryRequest = QueryRequest::Stargate { + path: "test".to_string(), + data: Default::default(), + }; + assert!(app .wrap() - .query::(&QueryRequest::Grpc(GrpcQuery { - path: "test".to_string(), - data: Default::default(), - })) - .unwrap_err(); + .query::(&request) + .unwrap_err() + .to_string() + .contains("Unexpected stargate query")); + + let msg = CosmosMsg::Any(AnyMsg { + type_url: "test".to_string(), + value: Default::default(), + }); + assert!(app + .execute(sender_addr, msg) + .unwrap_err() + .to_string() + .starts_with("Unexpected any execute")); + + let request: QueryRequest = QueryRequest::Grpc(GrpcQuery { + path: "test".to_string(), + data: Default::default(), + }); + assert!(app + .wrap() + .raw_query(to_json_vec(&request).unwrap().as_slice()) + .unwrap() + .unwrap_err() + .starts_with("Unexpected grpc query")); } From 60b937876740571174cceae0e9cfa7b9d418946a Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 19 Apr 2024 15:33:29 +0200 Subject: [PATCH 191/250] Final refactoring. --- src/anygate.rs | 145 ------------------ src/app.rs | 80 +++++----- src/app_builder.rs | 129 ++++++---------- src/lib.rs | 4 +- src/staking.rs | 8 +- src/stargate.rs | 150 +++++++++++++++++-- src/tests/test_app.rs | 4 +- src/tests/test_stargate.rs | 4 +- src/wasm.rs | 6 +- tests/test_app_builder/test_with_stargate.rs | 10 +- 10 files changed, 245 insertions(+), 295 deletions(-) delete mode 100644 src/anygate.rs diff --git a/src/anygate.rs b/src/anygate.rs deleted file mode 100644 index 82f3efda..00000000 --- a/src/anygate.rs +++ /dev/null @@ -1,145 +0,0 @@ -//! # Handler for `CosmosMsg::Stargate`, `CosmosMsg::Any`, `QueryRequest::Stargate` and `QueryRequest::Grpc` messages - -use crate::error::AnyResult; -use crate::{AppResponse, CosmosRouter}; -use anyhow::bail; -use cosmwasm_std::{ - to_json_binary, Addr, AnyMsg, Api, Binary, BlockInfo, CustomMsg, CustomQuery, Empty, GrpcQuery, - Querier, Storage, -}; -use serde::de::DeserializeOwned; - -/// Interface of handlers for processing `Stargate`/`Any` message variants -/// and `Stargate`/`Grpc` queries. -pub trait Anygate { - /// 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) - } - - /// Processes `CosmosMsg::Any` message variant. - fn execute_any( - &self, - _api: &dyn Api, - _storage: &mut dyn Storage, - _router: &dyn CosmosRouter, - _block: &BlockInfo, - sender: Addr, - msg: AnyMsg, - ) -> AnyResult - where - ExecC: CustomMsg + DeserializeOwned + 'static, - QueryC: CustomQuery + DeserializeOwned + 'static, - { - bail!("Unexpected any execute: msg={:?} from {}", msg, sender) - } - - /// Processes `QueryRequest::Grpc` query. - fn query_grpc( - &self, - _api: &dyn Api, - _storage: &dyn Storage, - _querier: &dyn Querier, - _block: &BlockInfo, - request: GrpcQuery, - ) -> AnyResult { - bail!("Unexpected grpc query: request={:?}", request) - } -} - -/// Always failing handler for `Stargate`/`Any` message variants and `Stargate`/`Grpc` queries. -pub struct FailingAnygate; - -impl Anygate for FailingAnygate {} - -/// Always accepting handler for `Stargate`/`Any` message variants and `Stargate`/`Grpc` queries. -pub struct AcceptingAnygate; - -impl Anygate for AcceptingAnygate { - 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_json_binary(&Empty {}).map_err(Into::into) - } - - fn execute_any( - &self, - _api: &dyn Api, - _storage: &mut dyn Storage, - _router: &dyn CosmosRouter, - _block: &BlockInfo, - _sender: Addr, - _msg: AnyMsg, - ) -> AnyResult - where - ExecC: CustomMsg + DeserializeOwned + 'static, - QueryC: CustomQuery + DeserializeOwned + 'static, - { - Ok(AppResponse::default()) - } - - fn query_grpc( - &self, - _api: &dyn Api, - _storage: &dyn Storage, - _querier: &dyn Querier, - _block: &BlockInfo, - _request: GrpcQuery, - ) -> AnyResult { - Ok(Binary::default()) - } -} diff --git a/src/app.rs b/src/app.rs index 6d5b1ea9..25c65f56 100644 --- a/src/app.rs +++ b/src/app.rs @@ -11,7 +11,7 @@ use crate::prefixed_storage::{ use crate::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking, StakingSudo}; use crate::transactions::transactional; use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; -use crate::{Anygate, AppBuilder, FailingAnygate, GovFailingModule, IbcFailingModule}; +use crate::{AppBuilder, GovFailingModule, IbcFailingModule, Stargate, StargateFailing}; use cosmwasm_std::testing::{MockApi, MockStorage}; use cosmwasm_std::{ from_json, to_json_binary, Addr, Api, Binary, BlockInfo, ContractResult, CosmosMsg, CustomMsg, @@ -41,7 +41,7 @@ pub type BasicApp = App< DistributionKeeper, IbcFailingModule, GovFailingModule, - FailingAnygate, + StargateFailing, >; /// # Blockchain application simulator @@ -58,17 +58,17 @@ pub struct App< Distr = DistributionKeeper, Ibc = IbcFailingModule, Gov = GovFailingModule, - Anygate = FailingAnygate, + Stargate = StargateFailing, > { - pub(crate) router: Router, + pub(crate) router: Router, pub(crate) api: Api, pub(crate) storage: Storage, pub(crate) block: BlockInfo, } /// No-op application initialization function. -pub fn no_init( - router: &mut Router, +pub fn no_init( + router: &mut Router, api: &dyn Api, storage: &mut dyn Storage, ) { @@ -94,7 +94,7 @@ impl BasicApp { DistributionKeeper, IbcFailingModule, GovFailingModule, - FailingAnygate, + StargateFailing, >, &dyn Api, &mut dyn Storage, @@ -119,7 +119,7 @@ where DistributionKeeper, IbcFailingModule, GovFailingModule, - FailingAnygate, + StargateFailing, >, &dyn Api, &mut dyn Storage, @@ -128,8 +128,8 @@ where AppBuilder::new_custom().build(init_fn) } -impl Querier - for App +impl Querier + for App where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -142,7 +142,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - AnygateT: Anygate, + StargateT: Stargate, { fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { self.router @@ -151,9 +151,9 @@ where } } -impl +impl Executor - for App + for App where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -166,7 +166,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - AnygateT: Anygate, + StargateT: Stargate, { fn execute(&mut self, sender: Addr, msg: CosmosMsg) -> AnyResult { let mut all = self.execute_multi(sender, vec![msg])?; @@ -175,8 +175,8 @@ where } } -impl - App +impl + App where WasmT: Wasm, BankT: Bank, @@ -187,10 +187,12 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - AnygateT: Anygate, + StargateT: Stargate, { /// Returns a shared reference to application's router. - pub fn router(&self) -> &Router { + pub fn router( + &self, + ) -> &Router { &self.router } @@ -213,7 +215,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, @@ -225,7 +227,7 @@ where pub fn read_module(&self, query_fn: F) -> T where F: FnOnce( - &Router, + &Router, &dyn Api, &dyn Storage, ) -> T, @@ -236,8 +238,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, @@ -248,7 +250,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - AnygateT: Anygate, + StargateT: Stargate, CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, { @@ -385,8 +387,8 @@ where } } -impl - App +impl + App where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -399,7 +401,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - AnygateT: Anygate, + StargateT: Stargate, { /// Sets the initial block properties. pub fn set_block(&mut self, block: BlockInfo) { @@ -503,7 +505,7 @@ where /// The Router plays a critical role in managing and directing /// transactions within the Cosmos blockchain. #[derive(Clone)] -pub struct Router { +pub struct Router { /// Wasm module instance to be used in this [Router]. pub(crate) wasm: Wasm, /// Bank module instance to be used in this [Router]. @@ -518,12 +520,12 @@ pub struct Router { pub ibc: Ibc, /// Governance module instance to be used in this [Router]. pub gov: Gov, - /// AnyGate handler instance to be used in this [Router]. - pub anygate: Anygate, + /// Stargate handler instance to be used in this [Router]. + pub stargate: Stargate, } -impl - Router +impl + Router where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -534,7 +536,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - AnygateT: Anygate, + StargateT: Stargate, { /// Returns a querier populated with the instance of this [Router]. pub fn querier<'a>( @@ -622,8 +624,8 @@ pub trait CosmosRouter { ) -> AnyResult; } -impl CosmosRouter - for Router +impl CosmosRouter + for Router where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, @@ -634,7 +636,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - AnygateT: Anygate, + StargateT: Stargate, { type ExecC = CustomT::ExecT; type QueryC = CustomT::QueryT; @@ -659,10 +661,10 @@ where CosmosMsg::Gov(msg) => self.gov.execute(api, storage, self, block, sender, msg), #[allow(deprecated)] CosmosMsg::Stargate { type_url, value } => self - .anygate + .stargate .execute_stargate(api, storage, self, block, sender, type_url, value), CosmosMsg::Any(msg) => self - .anygate + .stargate .execute_any(api, storage, self, block, sender, msg), _ => bail!("Cannot execute {:?}", msg), } @@ -687,9 +689,9 @@ where QueryRequest::Ibc(req) => self.ibc.query(api, storage, &querier, block, req), #[allow(deprecated)] QueryRequest::Stargate { path, data } => self - .anygate + .stargate .query_stargate(api, storage, &querier, block, path, data), - QueryRequest::Grpc(req) => self.anygate.query_grpc(api, storage, &querier, block, req), + QueryRequest::Grpc(req) => self.stargate.query_grpc(api, storage, &querier, block, req), _ => unimplemented!(), } } diff --git a/src/app_builder.rs b/src/app_builder.rs index 2a2196b2..ad9b0dc5 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -1,9 +1,9 @@ //! AppBuilder helps you set up your test blockchain environment step by step [App]. use crate::{ - Anygate, App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingAnygate, - FailingModule, Gov, GovFailingModule, Ibc, IbcFailingModule, Module, Router, StakeKeeper, - Staking, Wasm, WasmKeeper, + App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingModule, Gov, GovFailingModule, + Ibc, IbcFailingModule, Module, Router, StakeKeeper, Staking, Stargate, StargateFailing, Wasm, + WasmKeeper, }; use cosmwasm_std::testing::{mock_env, MockApi, MockStorage}; use cosmwasm_std::{Api, BlockInfo, CustomMsg, CustomQuery, Empty, Storage}; @@ -38,12 +38,12 @@ pub type BasicAppBuilder = AppBuilder< DistributionKeeper, IbcFailingModule, GovFailingModule, - FailingAnygate, + StargateFailing, >; /// 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, @@ -54,7 +54,7 @@ pub struct AppBuilder { fn default() -> Self { @@ -87,7 +87,7 @@ impl DistributionKeeper, IbcFailingModule, GovFailingModule, - FailingAnygate, + StargateFailing, > { /// Creates builder with default components working with empty exec and query messages. @@ -103,7 +103,7 @@ impl distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), - anygate: FailingAnygate, + stargate: StargateFailing, } } } @@ -119,7 +119,7 @@ impl DistributionKeeper, IbcFailingModule, GovFailingModule, - FailingAnygate, + StargateFailing, > where ExecC: CustomMsg + DeserializeOwned + 'static, @@ -139,13 +139,13 @@ where distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), - anygate: FailingAnygate, + stargate: StargateFailing, } } } -impl - AppBuilder +impl + AppBuilder where CustomT: Module, WasmT: Wasm, @@ -158,7 +158,7 @@ where pub fn with_wasm>( self, wasm: NewWasm, - ) -> AppBuilder + ) -> AppBuilder { let AppBuilder { bank, @@ -170,7 +170,7 @@ where distribution, ibc, gov, - anygate, + stargate, .. } = self; @@ -185,7 +185,7 @@ where distribution, ibc, gov, - anygate, + stargate, } } @@ -193,7 +193,7 @@ where pub fn with_bank( self, bank: NewBank, - ) -> AppBuilder + ) -> AppBuilder { let AppBuilder { wasm, @@ -205,7 +205,7 @@ where distribution, ibc, gov, - anygate, + stargate, .. } = self; @@ -220,7 +220,7 @@ where distribution, ibc, gov, - anygate, + stargate, } } @@ -228,7 +228,7 @@ where pub fn with_api( self, api: NewApi, - ) -> AppBuilder + ) -> AppBuilder { let AppBuilder { wasm, @@ -240,7 +240,7 @@ where distribution, ibc, gov, - anygate, + stargate, .. } = self; @@ -255,7 +255,7 @@ where distribution, ibc, gov, - anygate, + stargate, } } @@ -263,7 +263,7 @@ where pub fn with_storage( self, storage: NewStorage, - ) -> AppBuilder + ) -> AppBuilder { let AppBuilder { wasm, @@ -275,7 +275,7 @@ where distribution, ibc, gov, - anygate, + stargate, .. } = self; @@ -290,7 +290,7 @@ where distribution, ibc, gov, - anygate, + stargate, } } @@ -302,7 +302,7 @@ where pub fn with_custom( self, custom: NewCustom, - ) -> AppBuilder + ) -> AppBuilder { let AppBuilder { wasm, @@ -314,7 +314,7 @@ where distribution, ibc, gov, - anygate, + stargate, .. } = self; @@ -329,7 +329,7 @@ where distribution, ibc, gov, - anygate, + stargate, } } @@ -337,7 +337,7 @@ where pub fn with_staking( self, staking: NewStaking, - ) -> AppBuilder + ) -> AppBuilder { let AppBuilder { wasm, @@ -349,7 +349,7 @@ where distribution, ibc, gov, - anygate, + stargate, .. } = self; @@ -364,7 +364,7 @@ where distribution, ibc, gov, - anygate, + stargate, } } @@ -382,7 +382,7 @@ where NewDistribution, IbcT, GovT, - AnygateT, + StargateT, > { let AppBuilder { wasm, @@ -394,7 +394,7 @@ where bank, ibc, gov, - anygate, + stargate, .. } = self; @@ -409,7 +409,7 @@ where distribution, ibc, gov, - anygate, + stargate, } } @@ -423,7 +423,7 @@ where pub fn with_ibc( self, ibc: NewIbc, - ) -> AppBuilder + ) -> AppBuilder { let AppBuilder { wasm, @@ -435,7 +435,7 @@ where bank, distribution, gov, - anygate, + stargate, .. } = self; @@ -447,7 +447,7 @@ where wasm, custom, staking, - anygate, + stargate, distribution, ibc, gov, @@ -458,7 +458,7 @@ where pub fn with_gov( self, gov: NewGov, - ) -> AppBuilder + ) -> AppBuilder { let AppBuilder { wasm, @@ -470,7 +470,7 @@ where bank, distribution, ibc, - anygate, + stargate, .. } = self; @@ -485,14 +485,14 @@ where distribution, ibc, gov, - anygate, + stargate, } } /// Overwrites the default stargate interface. - pub fn with_stargate( + pub fn with_stargate( self, - anygate: NewStargate, + stargate: NewStargate, ) -> AppBuilder { let AppBuilder { @@ -520,42 +520,7 @@ where distribution, ibc, gov, - anygate, - } - } - - /// Overwrites the default anygate interface. - pub fn with_anygate( - self, - anygate: NewAnygate, - ) -> AppBuilder - { - let AppBuilder { - wasm, - api, - storage, - custom, - block, - staking, - bank, - distribution, - ibc, - gov, - .. - } = self; - - AppBuilder { - api, - block, - storage, - bank, - wasm, - custom, - staking, - distribution, - ibc, - gov, - anygate, + stargate, } } @@ -571,7 +536,7 @@ where pub fn build( self, init_fn: F, - ) -> App + ) -> App where BankT: Bank, ApiT: Api, @@ -582,9 +547,9 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - AnygateT: Anygate, + StargateT: Stargate, F: FnOnce( - &mut Router, + &mut Router, &dyn Api, &mut dyn Storage, ), @@ -597,7 +562,7 @@ where distribution: self.distribution, ibc: self.ibc, gov: self.gov, - anygate: self.anygate, + stargate: self.stargate, }; let mut app = App { diff --git a/src/lib.rs b/src/lib.rs index 49dee462..e5d3f24c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -125,7 +125,6 @@ #![deny(rustdoc::missing_crate_level_docs)] mod addresses; -mod anygate; mod api; mod app; mod app_builder; @@ -149,7 +148,6 @@ mod wasm; pub use crate::addresses::{ AddressGenerator, IntoAddr, IntoBech32, IntoBech32m, SimpleAddressGenerator, }; -pub use crate::anygate::{AcceptingAnygate, Anygate, FailingAnygate}; pub use crate::api::{MockApiBech32, MockApiBech32m}; pub use crate::app::{ custom_app, next_block, no_init, App, BasicApp, CosmosRouter, Router, SudoMsg, @@ -165,5 +163,5 @@ pub use crate::module::{AcceptingModule, FailingModule, Module}; pub use crate::staking::{ Distribution, DistributionKeeper, StakeKeeper, Staking, StakingInfo, StakingSudo, }; -pub use crate::stargate::{Stargate, StargateAcceptingModule, StargateFailingModule}; +pub use crate::stargate::{Stargate, StargateAccepting, StargateFailing}; pub use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; diff --git a/src/staking.rs b/src/staking.rs index 490ed3fc..cb311cdc 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1025,8 +1025,8 @@ impl Module for DistributionKeeper { mod test { use super::*; use crate::{ - app::MockRouter, BankKeeper, FailingAnygate, FailingModule, GovFailingModule, - IbcFailingModule, Router, WasmKeeper, + app::MockRouter, BankKeeper, FailingModule, GovFailingModule, IbcFailingModule, Router, + StargateFailing, WasmKeeper, }; use cosmwasm_std::{ from_json, @@ -1043,7 +1043,7 @@ mod test { DistributionKeeper, IbcFailingModule, GovFailingModule, - FailingAnygate, + StargateFailing, >; fn mock_router() -> BasicRouter { @@ -1055,7 +1055,7 @@ mod test { distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), - anygate: FailingAnygate, + stargate: StargateFailing, } } diff --git a/src/stargate.rs b/src/stargate.rs index 9065a2b8..7228d8a4 100644 --- a/src/stargate.rs +++ b/src/stargate.rs @@ -1,15 +1,145 @@ -use crate::{AcceptingModule, FailingModule, Module}; -use cosmwasm_std::{AnyMsg, Empty, GrpcQuery}; +//! # Handler for `CosmosMsg::Stargate`, `CosmosMsg::Any`, `QueryRequest::Stargate` and `QueryRequest::Grpc` messages -/// Interface to module handling any messages and queries. -pub trait Stargate: Module {} +use crate::error::AnyResult; +use crate::{AppResponse, CosmosRouter}; +use anyhow::bail; +use cosmwasm_std::{ + to_json_binary, Addr, AnyMsg, Api, Binary, BlockInfo, CustomMsg, CustomQuery, Empty, GrpcQuery, + Querier, Storage, +}; +use serde::de::DeserializeOwned; -/// Always accepting stargate module. -pub type StargateAcceptingModule = AcceptingModule; +/// Interface of handlers for processing `Stargate`/`Any` message variants +/// and `Stargate`/`Grpc` queries. +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, + ) + } -impl Stargate for StargateAcceptingModule {} + /// 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 accepting stargate module. -pub type StargateFailingModule = FailingModule; + /// Processes `CosmosMsg::Any` message variant. + fn execute_any( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + sender: Addr, + msg: AnyMsg, + ) -> AnyResult + where + ExecC: CustomMsg + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + bail!("Unexpected any execute: msg={:?} from {}", msg, sender) + } -impl Stargate for StargateFailingModule {} + /// Processes `QueryRequest::Grpc` query. + fn query_grpc( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + request: GrpcQuery, + ) -> AnyResult { + bail!("Unexpected grpc query: request={:?}", request) + } +} + +/// Always failing handler for `Stargate`/`Any` message variants and `Stargate`/`Grpc` queries. +pub struct StargateFailing; + +impl Stargate for StargateFailing {} + +/// Always accepting handler for `Stargate`/`Any` message variants and `Stargate`/`Grpc` 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_json_binary(&Empty {}).map_err(Into::into) + } + + fn execute_any( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + _sender: Addr, + _msg: AnyMsg, + ) -> AnyResult + where + ExecC: CustomMsg + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + Ok(AppResponse::default()) + } + + fn query_grpc( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + _request: GrpcQuery, + ) -> AnyResult { + Ok(Binary::default()) + } +} diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 3a30c6ef..685234eb 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/tests/test_stargate.rs b/src/tests/test_stargate.rs index 94f19030..01f2f975 100644 --- a/src/tests/test_stargate.rs +++ b/src/tests/test_stargate.rs @@ -1,5 +1,5 @@ use crate::test_helpers::stargate; -use crate::{no_init, AcceptingAnygate, App, AppBuilder, Executor}; +use crate::{no_init, App, AppBuilder, Executor, StargateAccepting}; use cosmwasm_std::Empty; #[test] @@ -33,7 +33,7 @@ fn default_failing_stargate_handler_should_work() { #[test] fn accepting_stargate_handler_should_work() { let mut app = AppBuilder::default() - .with_anygate(AcceptingAnygate) + .with_stargate(StargateAccepting) .build(no_init); // store the contract diff --git a/src/wasm.rs b/src/wasm.rs index ab406f4a..a05134bb 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1258,7 +1258,7 @@ mod test { use crate::staking::{DistributionKeeper, StakeKeeper}; use crate::test_helpers::{caller, error, payout}; use crate::transactions::StorageTransaction; - use crate::{FailingAnygate, GovFailingModule, IbcFailingModule}; + use crate::{GovFailingModule, IbcFailingModule, StargateFailing}; use cosmwasm_std::testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage}; use cosmwasm_std::{ coin, from_json, to_json_vec, CanonicalAddr, CodeInfoResponse, CosmosMsg, Empty, HexBinary, @@ -1274,7 +1274,7 @@ mod test { DistributionKeeper, IbcFailingModule, GovFailingModule, - FailingAnygate, + StargateFailing, >; fn wasm_keeper() -> WasmKeeper { @@ -1290,7 +1290,7 @@ mod test { distribution: DistributionKeeper::new(), ibc: IbcFailingModule::new(), gov: GovFailingModule::new(), - anygate: FailingAnygate, + stargate: StargateFailing, } } diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index 9ff3c3e1..fcff3751 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -5,8 +5,8 @@ use cosmwasm_std::{ }; use cw_multi_test::error::AnyResult; use cw_multi_test::{ - no_init, AcceptingAnygate, Anygate, AppBuilder, AppResponse, CosmosRouter, Executor, - FailingAnygate, + no_init, AppBuilder, AppResponse, CosmosRouter, Executor, Stargate, StargateAccepting, + StargateFailing, }; use serde::de::DeserializeOwned; @@ -17,7 +17,7 @@ const MSG_GRPC_QUERY: &str = "grpc query called"; struct StargateKeeper; -impl Anygate for StargateKeeper { +impl Stargate for StargateKeeper { fn execute_stargate( &self, _api: &dyn Api, @@ -136,7 +136,7 @@ fn building_app_with_custom_stargate_should_work() { #[test] fn building_app_with_accepting_stargate_should_work() { let app_builder = AppBuilder::default(); - let mut app = app_builder.with_anygate(AcceptingAnygate).build(no_init); + let mut app = app_builder.with_stargate(StargateAccepting).build(no_init); // prepare user addresses let sender_addr = app.api().addr_make("sender"); @@ -185,7 +185,7 @@ fn building_app_with_accepting_stargate_should_work() { #[test] fn default_failing_stargate_should_work() { let app_builder = AppBuilder::default(); - let mut app = app_builder.with_stargate(FailingAnygate).build(no_init); + let mut app = app_builder.with_stargate(StargateFailing).build(no_init); // prepare user addresses let sender_addr = app.api().addr_make("sender"); From 03f143a844e50986f66c419d9fc84e007dbdd0d4 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 22 Apr 2024 16:35:23 +0200 Subject: [PATCH 192/250] Prepared version 2.0.1 --- CHANGELOG.md | 16 ++++++++++++++++ Cargo.lock | 14 +++++++------- Cargo.toml | 4 ++-- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b023d50..c2758683 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## [v2.0.1](https://github.com/CosmWasm/cw-multi-test/tree/v2.0.1) (2024-04-22) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v2.0.0...v2.0.1) + +**Closed issues:** + +- Restore support for `Stargate` messages [\#159](https://github.com/CosmWasm/cw-multi-test/issues/159) + +**Merged pull requests:** + +- Distinctive Stargate [\#163](https://github.com/CosmWasm/cw-multi-test/pull/163) ([DariuszDepta](https://github.com/DariuszDepta)) +- Expose contract storage [\#153](https://github.com/CosmWasm/cw-multi-test/pull/153) ([DariuszDepta](https://github.com/DariuszDepta)) +- Expose prefixed storage [\#154](https://github.com/CosmWasm/cw-multi-test/pull/154) ([DariuszDepta](https://github.com/DariuszDepta)) +- Upgraded dependencies [\#164](https://github.com/CosmWasm/cw-multi-test/pull/164) ([DariuszDepta](https://github.com/DariuszDepta)) +- Fixes typos [\#167](https://github.com/CosmWasm/cw-multi-test/pull/157) ([DariuszDepta](https://github.com/DariuszDepta)) + ## [v2.0.0](https://github.com/CosmWasm/cw-multi-test/tree/v2.0.0) (2024-03-22) [Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v1.0.0...v2.0.0) diff --git a/Cargo.lock b/Cargo.lock index b6dcc839..7ba9ef95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,9 +120,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" +checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" [[package]] name = "cfg-if" @@ -250,7 +250,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "2.0.0" +version = "2.0.1" dependencies = [ "anyhow", "bech32 0.11.0", @@ -808,18 +808,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 91bc8498..549c72b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "2.0.0" +version = "2.0.1" authors = ["Ethan Frey ", "Dariusz Depta "] description = "Testing tools for multi-contract interactions" repository = "https://github.com/CosmWasm/cw-multi-test" @@ -25,7 +25,7 @@ prost = "0.12.4" schemars = "0.8.16" serde = "1.0.198" sha2 = "0.10.8" -thiserror = "1.0.58" +thiserror = "1.0.59" [dev-dependencies] hex = "0.4.3" From 4922b7c668dbf11f0012db000dd9dd2a2862012f Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 29 Apr 2024 10:00:10 +0200 Subject: [PATCH 193/250] Upgraded dependencies. --- Cargo.lock | 44 ++++++++++++++++++++++---------------------- Cargo.toml | 11 +++++++---- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ba9ef95..28f23f33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -138,9 +138,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-crypto" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd7a367ebd007cb05fe17e9c449beeb3636b15160750f2c6226c7dfd46df37" +checksum = "d8b08e6670ab9e13a1a8a9cfad8fdad48bf0aaf88a6e81f39f2d9b2fc79b1890" dependencies = [ "digest 0.10.7", "ed25519-zebra", @@ -151,18 +151,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db01ae480b00f133b78830db3211ff63afe08093e78c77ee20e73f7134849a60" +checksum = "b8b0918fc1a24b2ee08142c8d99d03f4c8e6d74244bdb304dbb29c0dab8e77e9" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de6e530d13452b4e9d882008193ab165032307a31f197b45d7b4e2aeff7577b5" +checksum = "26dbdb5800ca67f2f2f938d67db59a7c5434af133c3e508779a4df7a9b5d533b" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -173,9 +173,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ef0d7a8ae8807b8e8f5c94333d12aa9a11efc05f7b864f362582a2b167c663" +checksum = "d8ee47cf29f7688ebfa6ade8ddabcf51fc153f1157a3b46f5b4b1ce7a0316fdf" dependencies = [ "proc-macro2", "quote", @@ -184,9 +184,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6201969327d8fe5e9596e8c36e376ab595a885bdfcaa6a0bf57748f9ea2be2b" +checksum = "88191bd0d4743613eb7a2f086acb0838404cb531bf658382effafc7ba91e8320" dependencies = [ "base64", "bech32 0.9.1", @@ -641,9 +641,9 @@ checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "schemars" -version = "0.8.16" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +checksum = "7f55c82c700538496bdc329bb4918a81f87cc8888811bd123cf325a0f2f8d309" dependencies = [ "dyn-clone", "schemars_derive", @@ -653,14 +653,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.16" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +checksum = "83263746fe5e32097f06356968a077f96089739c927a61450efa069905eec108" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 1.0.109", + "syn 2.0.60", ] [[package]] @@ -679,9 +679,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.198" +version = "1.0.199" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" dependencies = [ "serde_derive", ] @@ -697,9 +697,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.198" +version = "1.0.199" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" dependencies = [ "proc-macro2", "quote", @@ -708,13 +708,13 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.26.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.60", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 549c72b2..43e70a67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "cw-multi-test" version = "2.0.1" -authors = ["Ethan Frey ", "Dariusz Depta "] +authors = [ + "Ethan Frey ", + "Dariusz Depta " +] description = "Testing tools for multi-contract interactions" repository = "https://github.com/CosmWasm/cw-multi-test" homepage = "https://cosmwasm.com" @@ -16,14 +19,14 @@ cosmwasm_2_0 = ["cosmwasm-std/cosmwasm_2_0"] [dependencies] anyhow = "1.0.82" bech32 = "0.11.0" -cosmwasm-std = { version = "2.0.1", features = ["iterator", "staking", "stargate"] } +cosmwasm-std = { version = "2.0.2", features = ["iterator", "staking", "stargate"] } cw-storage-plus = "2.0.0" cw-utils = "2.0.0" derivative = "2.2.0" itertools = "0.12.1" prost = "0.12.4" -schemars = "0.8.16" -serde = "1.0.198" +schemars = "0.8.17" +serde = "1.0.199" sha2 = "0.10.8" thiserror = "1.0.59" From 68fcd0cf5d2b7f278e8008d6cf2dec8c85ce1862 Mon Sep 17 00:00:00 2001 From: Amit Prasad Date: Fri, 17 May 2024 22:33:51 -0400 Subject: [PATCH 194/250] CosmWasm 2.0 enum variants feature-gated correctly --- src/app.rs | 2 ++ src/contracts.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/src/app.rs b/src/app.rs index 25c65f56..eb59e5f9 100644 --- a/src/app.rs +++ b/src/app.rs @@ -663,6 +663,7 @@ where CosmosMsg::Stargate { type_url, value } => self .stargate .execute_stargate(api, storage, self, block, sender, type_url, value), + #[cfg(feature = "cosmwasm_2_0")] CosmosMsg::Any(msg) => self .stargate .execute_any(api, storage, self, block, sender, msg), @@ -691,6 +692,7 @@ where QueryRequest::Stargate { path, data } => self .stargate .query_stargate(api, storage, &querier, block, path, data), + #[cfg(feature = "cosmwasm_2_0")] QueryRequest::Grpc(req) => self.stargate.query_grpc(api, storage, &querier, block, req), _ => unimplemented!(), } diff --git a/src/contracts.rs b/src/contracts.rs index 7b7279d4..e3feb726 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -434,6 +434,7 @@ where CosmosMsg::Distribution(distribution) => CosmosMsg::Distribution(distribution), CosmosMsg::Custom(_) => unreachable!(), CosmosMsg::Ibc(ibc) => CosmosMsg::Ibc(ibc), + #[cfg(feature = "cosmwasm_2_0")] CosmosMsg::Any(any) => CosmosMsg::Any(any), _ => panic!("unknown message variant {:?}", msg), }, From 3cd435ce6a90523fd5917ffa3749058fdf75db18 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 20 May 2024 19:28:23 +0200 Subject: [PATCH 195/250] Rewrite essential parts of SECURITY.md The original text was written for cw-plus and does not match reality anymore --- SECURITY.md | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 830ec171..e5fc15ed 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,16 +1,11 @@ # Security Policy This repository is maintained by Confio as part of the CosmWasm stack. -Please see https://github.com/CosmWasm/advisories/blob/main/SECURITY.md -for our security policy. -## Supported Versions - -cw-plus is still pre v1.0. A best effort has been made that the contracts here are secure, and we have moved the more -experimental contracts into community repositories like [cw-nfts](https://github.com/CosmWasm/cw-nfts) and -[cw-tokens](https://github.com/CosmWasm/cw-tokens). That said, we have not done an audit on them (formal or informal) -and you can use them at your own risk. We highly suggest doing your own audit on any contract you plan to deploy -with significant token value, and please inform us if it detects any issues so we can upstream them. - -Until v1.0 APIs are subject to change. The contracts APIs are pretty much stable, most work is currently -in `storage-plus` and `multi-test`. +The code here is not intended to be used in production +(i.e. cw-multi-test should only be used as a [Development dependency](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#development-dependencies)). +Thus it is not covered by the Cosmos bug bounty program and is not treated as strict +as other components when it comes to bugs. +However, if you still think you found a security critical +issue please find the contact information at +https://github.com/CosmWasm/advisories/blob/main/SECURITY.md. From aec2c67caec144890a8a6af4243c288f45b510ae Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 4 Jun 2024 15:14:02 +0200 Subject: [PATCH 196/250] Removed default features, upgraded dependencies. --- Cargo.lock | 143 ++++++++++--------- Cargo.toml | 22 +-- src/bank.rs | 16 ++- src/executor.rs | 1 + src/tests/test_app.rs | 4 + src/wasm.rs | 38 +++-- tests/test_app/mod.rs | 2 + tests/test_app/test_store_code.rs | 4 +- tests/test_app_builder/test_with_stargate.rs | 141 +++++++++--------- tests/test_app_builder/test_with_wasm.rs | 10 +- tests/test_wasm/mod.rs | 1 + tests/test_wasm/test_with_addr_gen.rs | 2 + 12 files changed, 221 insertions(+), 163 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 28f23f33..04f17010 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -30,18 +30,18 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.82" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" dependencies = [ "backtrace", ] [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" dependencies = [ "addr2line", "cc", @@ -120,9 +120,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" [[package]] name = "cfg-if" @@ -138,9 +138,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-crypto" -version = "2.0.2" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b08e6670ab9e13a1a8a9cfad8fdad48bf0aaf88a6e81f39f2d9b2fc79b1890" +checksum = "c7a339f6b59ff7ad4ae05a70512a4f3c19bf8fcc845d46bfef90f4ec0810f72c" dependencies = [ "digest 0.10.7", "ed25519-zebra", @@ -151,18 +151,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "2.0.2" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b0918fc1a24b2ee08142c8d99d03f4c8e6d74244bdb304dbb29c0dab8e77e9" +checksum = "7d3bfea6af94a83880fb05478135ed0c256d9a2fcde58c595a10d64dcb9c925d" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "2.0.2" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26dbdb5800ca67f2f2f938d67db59a7c5434af133c3e508779a4df7a9b5d533b" +checksum = "101d0739564bd34cba9b84bf73665f0822487ae3b29b2dd59930608ed3aafd43" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -173,9 +173,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.0.2" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8ee47cf29f7688ebfa6ade8ddabcf51fc153f1157a3b46f5b4b1ce7a0316fdf" +checksum = "cf4be75f60158478da2c5d319ed59295bca1687ad50c18215a0485aa91a995ea" dependencies = [ "proc-macro2", "quote", @@ -184,9 +184,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "2.0.2" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88191bd0d4743613eb7a2f086acb0838404cb531bf658382effafc7ba91e8320" +checksum = "ded932165de44cd0717979c34fc3b84d8e8066b8dde4f5bd78f96a643b090f90" dependencies = [ "base64", "bech32 0.9.1", @@ -260,7 +260,7 @@ dependencies = [ "derivative", "hex", "hex-literal", - "itertools", + "itertools 0.13.0", "once_cell", "prost", "schemars", @@ -372,9 +372,9 @@ dependencies = [ [[package]] name = "either" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "elliptic-curve" @@ -424,9 +424,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -435,9 +435,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "group" @@ -489,6 +489,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -511,9 +520,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "memchr" @@ -523,18 +532,18 @@ checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" dependencies = [ "adler", ] [[package]] name = "object" -version = "0.32.2" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" dependencies = [ "memchr", ] @@ -563,18 +572,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", "prost-derive", @@ -582,15 +591,15 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools", + "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.66", ] [[package]] @@ -629,21 +638,21 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schemars" -version = "0.8.17" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f55c82c700538496bdc329bb4918a81f87cc8888811bd123cf325a0f2f8d309" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" dependencies = [ "dyn-clone", "schemars_derive", @@ -653,14 +662,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.17" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83263746fe5e32097f06356968a077f96089739c927a61450efa069905eec108" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.60", + "syn 2.0.66", ] [[package]] @@ -679,9 +688,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.199" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] @@ -697,31 +706,31 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.199" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.66", ] [[package]] name = "serde_derive_internals" -version = "0.29.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.66", ] [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -797,9 +806,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.60" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -808,22 +817,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.59" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.59" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.66", ] [[package]] @@ -852,6 +861,6 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml index 43e70a67..5635c814 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,23 +12,27 @@ license = "Apache-2.0" edition = "2021" [features] -default = ["cosmwasm_2_0"] +default = [] backtrace = ["anyhow/backtrace"] -cosmwasm_2_0 = ["cosmwasm-std/cosmwasm_2_0"] +cosmwasm_1_1 = ["cosmwasm-std/cosmwasm_1_1"] +cosmwasm_1_2 = ["cosmwasm_1_1", "cosmwasm-std/cosmwasm_1_2"] +cosmwasm_1_3 = ["cosmwasm_1_2", "cosmwasm-std/cosmwasm_1_3"] +cosmwasm_1_4 = ["cosmwasm_1_3", "cosmwasm-std/cosmwasm_1_4"] +cosmwasm_2_0 = ["cosmwasm_1_4", "cosmwasm-std/cosmwasm_2_0"] [dependencies] -anyhow = "1.0.82" +anyhow = "1.0.86" bech32 = "0.11.0" -cosmwasm-std = { version = "2.0.2", features = ["iterator", "staking", "stargate"] } +cosmwasm-std = { version = "2.0.4", features = ["staking", "stargate"] } cw-storage-plus = "2.0.0" cw-utils = "2.0.0" derivative = "2.2.0" -itertools = "0.12.1" -prost = "0.12.4" -schemars = "0.8.17" -serde = "1.0.199" +itertools = "0.13.0" +prost = "0.12.6" +schemars = "0.8.21" +serde = "1.0.203" sha2 = "0.10.8" -thiserror = "1.0.59" +thiserror = "1.0.61" [dev-dependencies] hex = "0.4.3" diff --git a/src/bank.rs b/src/bank.rs index 4586e93f..756254ef 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -4,10 +4,13 @@ use crate::executor::AppResponse; use crate::module::Module; use crate::prefixed_storage::{prefixed, prefixed_read}; use cosmwasm_std::{ - coin, to_json_binary, Addr, AllBalanceResponse, AllDenomMetadataResponse, Api, BalanceResponse, - BankMsg, BankQuery, Binary, BlockInfo, Coin, DenomMetadata, DenomMetadataResponse, Event, - Order, Querier, StdResult, Storage, SupplyResponse, Uint128, + coin, to_json_binary, Addr, AllBalanceResponse, Api, BalanceResponse, BankMsg, BankQuery, + Binary, BlockInfo, Coin, DenomMetadata, Event, Querier, Storage, }; +#[cfg(feature = "cosmwasm_1_3")] +use cosmwasm_std::{AllDenomMetadataResponse, DenomMetadataResponse}; +#[cfg(feature = "cosmwasm_1_1")] +use cosmwasm_std::{Order, StdResult, SupplyResponse, Uint128}; use cw_storage_plus::Map; use cw_utils::NativeBalance; use itertools::Itertools; @@ -98,6 +101,7 @@ impl BankKeeper { Ok(val.unwrap_or_default().into_vec()) } + #[cfg(feature = "cosmwasm_1_1")] fn get_supply(&self, bank_storage: &dyn Storage, denom: String) -> AnyResult { let supply: Uint128 = BALANCES .range(bank_storage, None, None, Order::Ascending) @@ -236,16 +240,19 @@ impl Module for BankKeeper { let res = BalanceResponse::new(amount); to_json_binary(&res).map_err(Into::into) } + #[cfg(feature = "cosmwasm_1_1")] BankQuery::Supply { denom } => { let amount = self.get_supply(&bank_storage, denom)?; let res = SupplyResponse::new(amount); to_json_binary(&res).map_err(Into::into) } + #[cfg(feature = "cosmwasm_1_3")] BankQuery::DenomMetadata { denom } => { let meta = DENOM_METADATA.may_load(storage, denom)?.unwrap_or_default(); let res = DenomMetadataResponse::new(meta); to_json_binary(&res).map_err(Into::into) } + #[cfg(feature = "cosmwasm_1_3")] BankQuery::AllDenomMetadata { pagination: _ } => { let mut metadata = vec![]; for key in DENOM_METADATA.keys(storage, None, None, Order::Ascending) { @@ -303,6 +310,7 @@ mod test { } #[test] + #[cfg(feature = "cosmwasm_1_1")] fn get_set_balance() { let api = MockApi::default(); let mut store = MockStorage::new(); @@ -496,6 +504,7 @@ mod test { } #[test] + #[cfg(feature = "cosmwasm_1_3")] fn set_get_denom_metadata_should_work() { let api = MockApi::default(); let mut store = MockStorage::new(); @@ -523,6 +532,7 @@ mod test { } #[test] + #[cfg(feature = "cosmwasm_1_3")] fn set_get_all_denom_metadata_should_work() { let api = MockApi::default(); let mut store = MockStorage::new(); diff --git a/src/executor.rs b/src/executor.rs index ed2a5fad..5269276b 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -107,6 +107,7 @@ where /// Instantiates a new contract and returns its predictable address. /// This is a helper function around [execute][Self::execute] function /// with `WasmMsg::Instantiate2` message. + #[cfg(feature = "cosmwasm_1_2")] fn instantiate2_contract( &mut self, code_id: u64, diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 685234eb..c2b0e965 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -169,6 +169,7 @@ fn multi_level_bank_cache() { } #[test] +#[cfg(feature = "cosmwasm_1_2")] fn duplicate_contract_code() { // set up the multi-test application let mut app = App::default(); @@ -1586,6 +1587,7 @@ mod response_validation { mod contract_instantiation { #[test] + #[cfg(feature = "cosmwasm_1_2")] fn instantiate2_works() { use super::*; @@ -1626,6 +1628,7 @@ mod contract_instantiation { mod wasm_queries { #[test] + #[cfg(feature = "cosmwasm_1_2")] fn query_existing_code_info() { use super::*; let mut app = App::default(); @@ -1638,6 +1641,7 @@ mod wasm_queries { } #[test] + #[cfg(feature = "cosmwasm_1_2")] fn query_non_existing_code_info() { use super::*; let app = App::default(); diff --git a/src/wasm.rs b/src/wasm.rs index a05134bb..2ebc154a 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -246,6 +246,7 @@ where ); to_json_binary(&res).map_err(Into::into) } + #[cfg(feature = "cosmwasm_1_2")] WasmQuery::CodeInfo { code_id } => { let code_data = self.code_data(code_id)?; let res = cosmwasm_std::CodeInfoResponse::new( @@ -655,6 +656,7 @@ where } => self.process_wasm_msg_instantiate( api, storage, router, block, sender, admin, code_id, msg, funds, label, None, ), + #[cfg(feature = "cosmwasm_1_2")] WasmMsg::Instantiate2 { admin, code_id, @@ -1259,10 +1261,11 @@ mod test { use crate::test_helpers::{caller, error, payout}; use crate::transactions::StorageTransaction; use crate::{GovFailingModule, IbcFailingModule, StargateFailing}; - use cosmwasm_std::testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage}; + use cosmwasm_std::testing::{message_info, mock_env, MockApi, MockQuerier, MockStorage}; + #[cfg(feature = "cosmwasm_1_2")] + use cosmwasm_std::CodeInfoResponse; use cosmwasm_std::{ - coin, from_json, to_json_vec, CanonicalAddr, CodeInfoResponse, CosmosMsg, Empty, HexBinary, - StdError, + coin, from_json, to_json_vec, CanonicalAddr, CosmosMsg, Empty, HexBinary, StdError, }; /// Type alias for default build `Router` to make its reference in typical scenario @@ -1357,7 +1360,7 @@ mod test { let err = transactional(&mut wasm_storage, |cache, _| { // now, we call this contract and see the error message from the contract - let info = mock_info(user_addr.as_str(), &[]); + let info = message_info(&user_addr, &[]); wasm_keeper.call_instantiate( contract_addr.clone(), &api, @@ -1378,7 +1381,7 @@ mod test { let err = transactional(&mut wasm_storage, |cache, _| { // and the error for calling an unregistered contract - let info = mock_info(user_addr.as_str(), &[]); + let info = message_info(&user_addr, &[]); wasm_keeper.call_instantiate( unregistered_addr, &api, @@ -1438,6 +1441,7 @@ mod test { } #[test] + #[cfg(feature = "cosmwasm_1_2")] fn query_code_info() { let api = MockApi::default(); let wasm_storage = MockStorage::new(); @@ -1457,6 +1461,7 @@ mod test { } #[test] + #[cfg(feature = "cosmwasm_1_2")] fn different_contracts_must_have_different_checksum() { let api = MockApi::default(); let creator_addr = api.addr_make("creator"); @@ -1488,6 +1493,7 @@ mod test { } #[test] + #[cfg(feature = "cosmwasm_1_2")] fn querying_invalid_code_info_must_fail() { let api = MockApi::default(); let wasm_storage = MockStorage::new(); @@ -1522,7 +1528,7 @@ mod test { &api, &mut wasm_storage, code_id, - user_addr, + user_addr.clone(), admin_addr, "label".to_owned(), 1000, @@ -1542,7 +1548,7 @@ mod test { &mut wasm_storage, &mock_router(), &block, - mock_info("foobar", &[]), + message_info(&user_addr, &[]), to_json_vec(&msg).unwrap(), ) .unwrap(); @@ -1592,7 +1598,7 @@ mod test { let payout = coin(100, "TGD"); // init the contract - let info = mock_info(user_addr.as_str(), &[]); + let info = message_info(&user_addr, &[]); let init_msg = to_json_vec(&payout::InstantiateMessage { payout: payout.clone(), }) @@ -1611,7 +1617,7 @@ mod test { assert_eq!(0, res.messages.len()); // execute the contract - let info = mock_info(user_addr.as_str(), &[]); + let info = message_info(&user_addr, &[]); let res = wasm_keeper .call_execute( &api, @@ -1652,7 +1658,8 @@ mod test { payout: &Coin, ) { let api = MockApi::default(); - let info = mock_info("silly", &[]); + let user_addr = api.addr_make("silly"); + let info = message_info(&user_addr, &[]); let res = router .call_execute( &api, @@ -1667,7 +1674,7 @@ mod test { assert_eq!(1, res.messages.len()); match &res.messages[0].msg { CosmosMsg::Bank(BankMsg::Send { to_address, amount }) => { - assert_eq!(to_address.as_str(), "silly"); + assert_eq!(to_address.as_str(), user_addr.as_str()); assert_eq!(amount.as_slice(), &[payout.clone()]); } m => panic!("Unexpected message {:?}", m), @@ -1686,6 +1693,7 @@ mod test { // prepare user addresses let creator_addr = api.addr_make("creator"); let user_addr = api.addr_make("foobar"); + let user_addr_1 = api.addr_make("johnny"); let mut wasm_keeper = wasm_keeper(); let block = mock_env().block; @@ -1709,7 +1717,7 @@ mod test { None, ) .unwrap(); - let info = mock_info(user_addr.as_str(), &[]); + let info = message_info(&user_addr, &[]); let init_msg = to_json_vec(&payout::InstantiateMessage { payout: payout1.clone(), }) @@ -1750,7 +1758,7 @@ mod test { None, ) .unwrap(); - let info = mock_info(user_addr.as_str(), &[]); + let info = message_info(&user_addr, &[]); let init_msg = to_json_vec(&payout::InstantiateMessage { payout: payout2.clone(), }) @@ -1786,7 +1794,7 @@ mod test { None, ) .unwrap(); - let info = mock_info("johnny", &[]); + let info = message_info(&user_addr_1, &[]); let init_msg = to_json_vec(&payout::InstantiateMessage { payout: payout3.clone(), }) @@ -1882,7 +1890,7 @@ mod test { .unwrap(); // init the contract - let info = mock_info("admin", &[]); + let info = message_info(&admin, &[]); let init_msg = to_json_vec(&Empty {}).unwrap(); let res = wasm_keeper .call_instantiate( diff --git a/tests/test_app/mod.rs b/tests/test_app/mod.rs index 3bcc0d98..49b7a7a0 100644 --- a/tests/test_app/mod.rs +++ b/tests/test_app/mod.rs @@ -1,4 +1,6 @@ +#[cfg(feature = "cosmwasm_1_2")] mod test_instantiate2; mod test_store_code; +#[cfg(feature = "cosmwasm_1_2")] mod test_store_code_with_creator; mod test_store_code_with_id; diff --git a/tests/test_app/test_store_code.rs b/tests/test_app/test_store_code.rs index 765d0c2f..ef3123c7 100644 --- a/tests/test_app/test_store_code.rs +++ b/tests/test_app/test_store_code.rs @@ -1,5 +1,4 @@ use crate::test_contracts::counter; -use cosmwasm_std::testing::MockApi; use cw_multi_test::App; #[test] @@ -14,7 +13,10 @@ fn storing_code_assigns_consecutive_identifiers() { } #[test] +#[cfg(feature = "cosmwasm_1_2")] fn store_code_generates_default_address_for_creator() { + use cosmwasm_std::testing::MockApi; + // prepare the application let mut app = App::default(); diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index fcff3751..1fd6bf2f 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -1,7 +1,7 @@ use anyhow::bail; use cosmwasm_std::{ - to_json_vec, Addr, AnyMsg, Api, Binary, BlockInfo, CosmosMsg, CustomMsg, CustomQuery, Empty, - Event, GrpcQuery, Querier, QueryRequest, Storage, + Addr, AnyMsg, Api, Binary, BlockInfo, CosmosMsg, CustomMsg, CustomQuery, Empty, Event, + GrpcQuery, Querier, QueryRequest, Storage, }; use cw_multi_test::error::AnyResult; use cw_multi_test::{ @@ -110,27 +110,30 @@ fn building_app_with_custom_stargate_should_work() { .to_string() .ends_with(MSG_STARGATE_QUERY)); - // executing `any` message should return an error defined in custom stargate keeper - let msg = CosmosMsg::Any(AnyMsg { - type_url: "test".to_string(), - value: Default::default(), - }); - assert_eq!( - app.execute(sender_addr, msg).unwrap_err().to_string(), - MSG_ANY_EXECUTE, - ); - - // executing `grpc` query should return an error defined in custom stargate keeper - let request: QueryRequest = QueryRequest::Grpc(GrpcQuery { - path: "test".to_string(), - data: Default::default(), - }); - assert!(app - .wrap() - .query::(&request) - .unwrap_err() - .to_string() - .ends_with(MSG_GRPC_QUERY)); + #[cfg(feature = "cosmwasm_2_0")] + { + // executing `any` message should return an error defined in custom stargate keeper + let msg = CosmosMsg::Any(AnyMsg { + type_url: "test".to_string(), + value: Default::default(), + }); + assert_eq!( + app.execute(sender_addr, msg).unwrap_err().to_string(), + MSG_ANY_EXECUTE, + ); + + // executing `grpc` query should return an error defined in custom stargate keeper + let request: QueryRequest = QueryRequest::Grpc(GrpcQuery { + path: "test".to_string(), + data: Default::default(), + }); + assert!(app + .wrap() + .query::(&request) + .unwrap_err() + .to_string() + .ends_with(MSG_GRPC_QUERY)); + } } #[test] @@ -159,27 +162,32 @@ fn building_app_with_accepting_stargate_should_work() { }; assert_eq!(app.wrap().query::(&request).unwrap(), Empty {}); - // executing `any` message should success and return empty values - let msg = CosmosMsg::Any(AnyMsg { - type_url: "test".to_string(), - value: Default::default(), - }); - let AppResponse { events, data } = app.execute(sender_addr, msg).unwrap(); - assert_eq!(events, Vec::::new()); - assert_eq!(data, None); - - // executing `grpc` query should success and return empty binary - let request: QueryRequest = QueryRequest::Grpc(GrpcQuery { - path: "test".to_string(), - data: Default::default(), - }); - assert_eq!( - app.wrap() - .raw_query(to_json_vec(&request).unwrap().as_slice()) - .unwrap() - .unwrap(), - Binary::default() - ); + #[cfg(feature = "cosmwasm_2_0")] + { + use cosmwasm_std::to_json_vec; + + // executing `any` message should success and return empty values + let msg = CosmosMsg::Any(AnyMsg { + type_url: "test".to_string(), + value: Default::default(), + }); + let AppResponse { events, data } = app.execute(sender_addr, msg).unwrap(); + assert_eq!(events, Vec::::new()); + assert_eq!(data, None); + + // executing `grpc` query should success and return empty binary + let request: QueryRequest = QueryRequest::Grpc(GrpcQuery { + path: "test".to_string(), + data: Default::default(), + }); + assert_eq!( + app.wrap() + .raw_query(to_json_vec(&request).unwrap().as_slice()) + .unwrap() + .unwrap(), + Binary::default() + ); + } } #[test] @@ -213,24 +221,29 @@ fn default_failing_stargate_should_work() { .to_string() .contains("Unexpected stargate query")); - let msg = CosmosMsg::Any(AnyMsg { - type_url: "test".to_string(), - value: Default::default(), - }); - assert!(app - .execute(sender_addr, msg) - .unwrap_err() - .to_string() - .starts_with("Unexpected any execute")); - - let request: QueryRequest = QueryRequest::Grpc(GrpcQuery { - path: "test".to_string(), - data: Default::default(), - }); - assert!(app - .wrap() - .raw_query(to_json_vec(&request).unwrap().as_slice()) - .unwrap() - .unwrap_err() - .starts_with("Unexpected grpc query")); + #[cfg(feature = "cosmwasm_2_0")] + { + use cosmwasm_std::to_json_vec; + + let msg = CosmosMsg::Any(AnyMsg { + type_url: "test".to_string(), + value: Default::default(), + }); + assert!(app + .execute(sender_addr, msg) + .unwrap_err() + .to_string() + .starts_with("Unexpected any execute")); + + let request: QueryRequest = QueryRequest::Grpc(GrpcQuery { + path: "test".to_string(), + data: Default::default(), + }); + assert!(app + .wrap() + .raw_query(to_json_vec(&request).unwrap().as_slice()) + .unwrap() + .unwrap_err() + .starts_with("Unexpected grpc query")); + } } diff --git a/tests/test_app_builder/test_with_wasm.rs b/tests/test_app_builder/test_with_wasm.rs index 390c8684..b9c67f54 100644 --- a/tests/test_app_builder/test_with_wasm.rs +++ b/tests/test_app_builder/test_with_wasm.rs @@ -5,8 +5,8 @@ use cosmwasm_std::{ }; use cw_multi_test::error::{bail, AnyResult}; use cw_multi_test::{ - no_init, AppBuilder, AppResponse, Contract, ContractData, CosmosRouter, Executor, Wasm, - WasmKeeper, WasmSudo, + no_init, AppBuilder, AppResponse, Contract, ContractData, CosmosRouter, Wasm, WasmKeeper, + WasmSudo, }; use once_cell::sync::Lazy; @@ -87,6 +87,8 @@ impl Wasm for MyWasmKeeper { #[test] fn building_app_with_custom_wasm_should_work() { + use cw_multi_test::Executor; + // build custom wasm keeper let wasm_keeper = MyWasmKeeper::new(EXECUTE_MSG, QUERY_MSG, SUDO_MSG); @@ -139,7 +141,7 @@ fn building_app_with_custom_wasm_should_work() { SUDO_MSG, app.sudo( WasmSudo { - contract_addr, + contract_addr: contract_addr.clone(), message: Default::default() } .into() @@ -152,7 +154,7 @@ fn building_app_with_custom_wasm_should_work() { assert_eq!( format!("Generic error: Querier contract error: {}", QUERY_MSG), app.wrap() - .query_wasm_code_info(CODE_ID) + .query_wasm_contract_info(&contract_addr) .unwrap_err() .to_string() ); diff --git a/tests/test_wasm/mod.rs b/tests/test_wasm/mod.rs index bc053f73..df641335 100644 --- a/tests/test_wasm/mod.rs +++ b/tests/test_wasm/mod.rs @@ -1,2 +1,3 @@ mod test_with_addr_gen; +#[cfg(feature = "cosmwasm_1_2")] mod test_with_checksum_gen; diff --git a/tests/test_wasm/test_with_addr_gen.rs b/tests/test_wasm/test_with_addr_gen.rs index 2863fed0..4ec6c829 100644 --- a/tests/test_wasm/test_with_addr_gen.rs +++ b/tests/test_wasm/test_with_addr_gen.rs @@ -88,6 +88,7 @@ fn custom_address_generator_should_work() { } #[test] +#[cfg(feature = "cosmwasm_1_2")] fn predictable_contract_address_should_work() { // prepare application with custom api let mut app = AppBuilder::default() @@ -140,6 +141,7 @@ fn predictable_contract_address_should_work() { } #[test] +#[cfg(feature = "cosmwasm_1_2")] fn creating_contract_with_the_same_predictable_address_should_fail() { // prepare application with custom api let mut app = AppBuilder::default() From deb74f247df0e28b2570796cb49509de7994060b Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 4 Jun 2024 16:56:24 +0200 Subject: [PATCH 197/250] Fixed tests. --- tests/test_app_builder/test_with_stargate.rs | 180 ++++++++++--------- 1 file changed, 100 insertions(+), 80 deletions(-) diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index 1fd6bf2f..51b10b80 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -91,9 +91,7 @@ fn building_app_with_custom_stargate_should_work() { value: Default::default(), }; assert_eq!( - app.execute(sender_addr.clone(), msg) - .unwrap_err() - .to_string(), + app.execute(sender_addr, msg).unwrap_err().to_string(), MSG_STARGATE_EXECUTE, ); @@ -109,31 +107,39 @@ fn building_app_with_custom_stargate_should_work() { .unwrap_err() .to_string() .ends_with(MSG_STARGATE_QUERY)); +} - #[cfg(feature = "cosmwasm_2_0")] - { - // executing `any` message should return an error defined in custom stargate keeper - let msg = CosmosMsg::Any(AnyMsg { - type_url: "test".to_string(), - value: Default::default(), - }); - assert_eq!( - app.execute(sender_addr, msg).unwrap_err().to_string(), - MSG_ANY_EXECUTE, - ); - - // executing `grpc` query should return an error defined in custom stargate keeper - let request: QueryRequest = QueryRequest::Grpc(GrpcQuery { - path: "test".to_string(), - data: Default::default(), - }); - assert!(app - .wrap() - .query::(&request) - .unwrap_err() - .to_string() - .ends_with(MSG_GRPC_QUERY)); - } +#[test] +#[cfg(feature = "cosmwasm_2_0")] +fn building_app_with_custom_any_grpc_should_work() { + // build the application with custom stargate keeper + let app_builder = AppBuilder::default(); + let mut app = app_builder.with_stargate(StargateKeeper).build(no_init); + + // prepare user addresses + let sender_addr = app.api().addr_make("sender"); + + // executing `any` message should return an error defined in custom stargate keeper + let msg = CosmosMsg::Any(AnyMsg { + type_url: "test".to_string(), + value: Default::default(), + }); + assert_eq!( + app.execute(sender_addr, msg).unwrap_err().to_string(), + MSG_ANY_EXECUTE, + ); + + // executing `grpc` query should return an error defined in custom stargate keeper + let request: QueryRequest = QueryRequest::Grpc(GrpcQuery { + path: "test".to_string(), + data: Default::default(), + }); + assert!(app + .wrap() + .query::(&request) + .unwrap_err() + .to_string() + .ends_with(MSG_GRPC_QUERY)); } #[test] @@ -150,7 +156,7 @@ fn building_app_with_accepting_stargate_should_work() { type_url: "test".to_string(), value: Default::default(), }; - let AppResponse { events, data } = app.execute(sender_addr.clone(), msg).unwrap(); + let AppResponse { events, data } = app.execute(sender_addr, msg).unwrap(); assert_eq!(events, Vec::::new()); assert_eq!(data, None); @@ -161,33 +167,40 @@ fn building_app_with_accepting_stargate_should_work() { data: Default::default(), }; assert_eq!(app.wrap().query::(&request).unwrap(), Empty {}); +} - #[cfg(feature = "cosmwasm_2_0")] - { - use cosmwasm_std::to_json_vec; - - // executing `any` message should success and return empty values - let msg = CosmosMsg::Any(AnyMsg { - type_url: "test".to_string(), - value: Default::default(), - }); - let AppResponse { events, data } = app.execute(sender_addr, msg).unwrap(); - assert_eq!(events, Vec::::new()); - assert_eq!(data, None); - - // executing `grpc` query should success and return empty binary - let request: QueryRequest = QueryRequest::Grpc(GrpcQuery { - path: "test".to_string(), - data: Default::default(), - }); - assert_eq!( - app.wrap() - .raw_query(to_json_vec(&request).unwrap().as_slice()) - .unwrap() - .unwrap(), - Binary::default() - ); - } +#[test] +#[cfg(feature = "cosmwasm_2_0")] +fn building_app_with_accepting_any_grpc_should_work() { + let app_builder = AppBuilder::default(); + let mut app = app_builder.with_stargate(StargateAccepting).build(no_init); + + // prepare user addresses + let sender_addr = app.api().addr_make("sender"); + + use cosmwasm_std::to_json_vec; + + // executing `any` message should success and return empty values + let msg = CosmosMsg::Any(AnyMsg { + type_url: "test".to_string(), + value: Default::default(), + }); + let AppResponse { events, data } = app.execute(sender_addr, msg).unwrap(); + assert_eq!(events, Vec::::new()); + assert_eq!(data, None); + + // executing `grpc` query should success and return empty binary + let request: QueryRequest = QueryRequest::Grpc(GrpcQuery { + path: "test".to_string(), + data: Default::default(), + }); + assert_eq!( + app.wrap() + .raw_query(to_json_vec(&request).unwrap().as_slice()) + .unwrap() + .unwrap(), + Binary::default() + ); } #[test] @@ -204,7 +217,7 @@ fn default_failing_stargate_should_work() { value: Default::default(), }; assert!(app - .execute(sender_addr.clone(), msg) + .execute(sender_addr, msg) .unwrap_err() .to_string() .starts_with("Unexpected stargate execute")); @@ -220,30 +233,37 @@ fn default_failing_stargate_should_work() { .unwrap_err() .to_string() .contains("Unexpected stargate query")); +} - #[cfg(feature = "cosmwasm_2_0")] - { - use cosmwasm_std::to_json_vec; - - let msg = CosmosMsg::Any(AnyMsg { - type_url: "test".to_string(), - value: Default::default(), - }); - assert!(app - .execute(sender_addr, msg) - .unwrap_err() - .to_string() - .starts_with("Unexpected any execute")); - - let request: QueryRequest = QueryRequest::Grpc(GrpcQuery { - path: "test".to_string(), - data: Default::default(), - }); - assert!(app - .wrap() - .raw_query(to_json_vec(&request).unwrap().as_slice()) - .unwrap() - .unwrap_err() - .starts_with("Unexpected grpc query")); - } +#[test] +#[cfg(feature = "cosmwasm_2_0")] +fn default_failing_any_grpc_should_work() { + let app_builder = AppBuilder::default(); + let mut app = app_builder.with_stargate(StargateFailing).build(no_init); + + // prepare user addresses + let sender_addr = app.api().addr_make("sender"); + + use cosmwasm_std::to_json_vec; + + let msg = CosmosMsg::Any(AnyMsg { + type_url: "test".to_string(), + value: Default::default(), + }); + assert!(app + .execute(sender_addr, msg) + .unwrap_err() + .to_string() + .starts_with("Unexpected any execute")); + + let request: QueryRequest = QueryRequest::Grpc(GrpcQuery { + path: "test".to_string(), + data: Default::default(), + }); + assert!(app + .wrap() + .raw_query(to_json_vec(&request).unwrap().as_slice()) + .unwrap() + .unwrap_err() + .starts_with("Unexpected grpc query")); } From 7b711fda1979bcb42eaa8689a96e5ca6808caf91 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 10 Jun 2024 11:30:17 +0200 Subject: [PATCH 198/250] Reverted unneeded changes in test. --- Cargo.lock | 4 ++-- tests/test_app_builder/mod.rs | 1 + tests/test_app_builder/test_with_wasm.rs | 10 ++++------ 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 04f17010..9b413df5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,9 +120,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" [[package]] name = "cfg-if" diff --git a/tests/test_app_builder/mod.rs b/tests/test_app_builder/mod.rs index d2dcc5c2..a19cf726 100644 --- a/tests/test_app_builder/mod.rs +++ b/tests/test_app_builder/mod.rs @@ -14,6 +14,7 @@ mod test_with_ibc; mod test_with_staking; mod test_with_stargate; mod test_with_storage; +#[cfg(feature = "cosmwasm_1_2")] mod test_with_wasm; const NO_MESSAGE: &str = ""; diff --git a/tests/test_app_builder/test_with_wasm.rs b/tests/test_app_builder/test_with_wasm.rs index b9c67f54..390c8684 100644 --- a/tests/test_app_builder/test_with_wasm.rs +++ b/tests/test_app_builder/test_with_wasm.rs @@ -5,8 +5,8 @@ use cosmwasm_std::{ }; use cw_multi_test::error::{bail, AnyResult}; use cw_multi_test::{ - no_init, AppBuilder, AppResponse, Contract, ContractData, CosmosRouter, Wasm, WasmKeeper, - WasmSudo, + no_init, AppBuilder, AppResponse, Contract, ContractData, CosmosRouter, Executor, Wasm, + WasmKeeper, WasmSudo, }; use once_cell::sync::Lazy; @@ -87,8 +87,6 @@ impl Wasm for MyWasmKeeper { #[test] fn building_app_with_custom_wasm_should_work() { - use cw_multi_test::Executor; - // build custom wasm keeper let wasm_keeper = MyWasmKeeper::new(EXECUTE_MSG, QUERY_MSG, SUDO_MSG); @@ -141,7 +139,7 @@ fn building_app_with_custom_wasm_should_work() { SUDO_MSG, app.sudo( WasmSudo { - contract_addr: contract_addr.clone(), + contract_addr, message: Default::default() } .into() @@ -154,7 +152,7 @@ fn building_app_with_custom_wasm_should_work() { assert_eq!( format!("Generic error: Querier contract error: {}", QUERY_MSG), app.wrap() - .query_wasm_contract_info(&contract_addr) + .query_wasm_code_info(CODE_ID) .unwrap_err() .to_string() ); From c0640a0abbcdd7b50272f1e106e67b563ba3fb90 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 10 Jun 2024 11:35:15 +0200 Subject: [PATCH 199/250] Refactored function order in module implementation. --- tests/test_app_builder/mod.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/test_app_builder/mod.rs b/tests/test_app_builder/mod.rs index a19cf726..6c8bf260 100644 --- a/tests/test_app_builder/mod.rs +++ b/tests/test_app_builder/mod.rs @@ -58,6 +58,17 @@ where bail!(self.1); } + fn query( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + _request: Self::QueryT, + ) -> AnyResult { + bail!(self.2); + } + fn sudo( &self, _api: &dyn Api, @@ -72,15 +83,4 @@ where { bail!(self.3); } - - fn query( - &self, - _api: &dyn Api, - _storage: &dyn Storage, - _querier: &dyn Querier, - _block: &BlockInfo, - _request: Self::QueryT, - ) -> AnyResult { - bail!(self.2); - } } From b5e0fa8b58372939f7fdbc8e268c208bd9156b67 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 11 Jun 2024 09:38:30 +0200 Subject: [PATCH 200/250] Added test. --- tests/mod.rs | 1 + tests/test_staking/mod.rs | 1 + tests/test_staking/test_stake_unstake.rs | 38 ++++++++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 tests/test_staking/mod.rs create mode 100644 tests/test_staking/test_stake_unstake.rs diff --git a/tests/mod.rs b/tests/mod.rs index edf9910d..21ad4ffa 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -6,6 +6,7 @@ mod test_app_builder; mod test_contract_storage; mod test_module; mod test_prefixed_storage; +mod test_staking; mod test_wasm; mod test_contracts { diff --git a/tests/test_staking/mod.rs b/tests/test_staking/mod.rs new file mode 100644 index 00000000..39c2edb2 --- /dev/null +++ b/tests/test_staking/mod.rs @@ -0,0 +1 @@ +mod test_stake_unstake; diff --git a/tests/test_staking/test_stake_unstake.rs b/tests/test_staking/test_stake_unstake.rs new file mode 100644 index 00000000..738c4ace --- /dev/null +++ b/tests/test_staking/test_stake_unstake.rs @@ -0,0 +1,38 @@ +use cosmwasm_std::testing::mock_env; +use cosmwasm_std::{BlockInfo, Decimal, Validator}; +use cw_multi_test::{no_init, App, AppBuilder, IntoBech32, StakingInfo}; + +#[test] +fn stake_unstake_should_work() { + let validator_addr = "oper1".into_bech32(); + let validator_interest_rate: Decimal = Decimal::percent(10); + let validator_commission: Decimal = Decimal::percent(10); + + let valoper1 = Validator::new( + validator_addr.to_string(), + validator_commission, + Decimal::percent(100), + Decimal::percent(1), + ); + + let block = mock_env().block; + + let app_builder = AppBuilder::default(); + let mut app = app_builder.build(|router, api, storage| { + router + .staking + .setup( + storage, + StakingInfo { + bonded_denom: "TOKEN".to_string(), + unbonding_time: 60, + apr: validator_interest_rate, + }, + ) + .unwrap(); + router + .staking + .add_validator(api, storage, &block, valoper1) + .unwrap(); + }); +} From 1ff8951ab5b5425b5b5f3cfe1795d8295fa597e5 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 11 Jun 2024 13:56:35 +0200 Subject: [PATCH 201/250] Implemented proper unbonding. --- src/app.rs | 4 +- tests/test_staking/test_stake_unstake.rs | 123 ++++++++++++++++++++--- 2 files changed, 110 insertions(+), 17 deletions(-) diff --git a/src/app.rs b/src/app.rs index eb59e5f9..2770caf8 100644 --- a/src/app.rs +++ b/src/app.rs @@ -405,20 +405,20 @@ where { /// Sets the initial block properties. pub fn set_block(&mut self, block: BlockInfo) { + self.block = block; self.router .staking .process_queue(&self.api, &mut self.storage, &self.router, &self.block) .unwrap(); - self.block = block; } /// Updates the current block applying the specified closure, usually [next_block]. pub fn update_block(&mut self, action: F) { + action(&mut self.block); self.router .staking .process_queue(&self.api, &mut self.storage, &self.router, &self.block) .unwrap(); - action(&mut self.block); } /// Returns a copy of the current block_info diff --git a/tests/test_staking/test_stake_unstake.rs b/tests/test_staking/test_stake_unstake.rs index 738c4ace..92ab74ac 100644 --- a/tests/test_staking/test_stake_unstake.rs +++ b/tests/test_staking/test_stake_unstake.rs @@ -1,38 +1,131 @@ use cosmwasm_std::testing::mock_env; -use cosmwasm_std::{BlockInfo, Decimal, Validator}; -use cw_multi_test::{no_init, App, AppBuilder, IntoBech32, StakingInfo}; +use cosmwasm_std::{coin, Decimal, StakingMsg, Validator}; +use cw_multi_test::{AppBuilder, Executor, IntoBech32, StakingInfo}; #[test] fn stake_unstake_should_work() { - let validator_addr = "oper1".into_bech32(); - let validator_interest_rate: Decimal = Decimal::percent(10); - let validator_commission: Decimal = Decimal::percent(10); + const BONDED_DENOM: &str = "stake"; // denominator of the staking token + const UNBONDING_TIME: u64 = 60; // time between unbonding and receiving tokens back (in seconds) + const DELEGATION_AMOUNT: u128 = 100; // amount of tokens to be (re)delegated + const INITIAL_AMOUNT: u128 = 1000; // initial amount of tokens for delegator + const FEWER_AMOUNT: u128 = INITIAL_AMOUNT - DELEGATION_AMOUNT; // amount of tokens after delegation - let valoper1 = Validator::new( + let delegator_addr = "delegator".into_bech32(); + let validator_addr = "valoper".into_bech32(); + + let valoper = Validator::new( validator_addr.to_string(), - validator_commission, - Decimal::percent(100), + Decimal::percent(10), + Decimal::percent(90), Decimal::percent(1), ); + // prepare the blockchain configuration let block = mock_env().block; - - let app_builder = AppBuilder::default(); - let mut app = app_builder.build(|router, api, storage| { + let mut app = AppBuilder::default().build(|router, api, storage| { + // set initial balance for the delegator + router + .bank + .init_balance( + storage, + &delegator_addr, + vec![coin(INITIAL_AMOUNT, BONDED_DENOM)], + ) + .unwrap(); + // setup staking parameters router .staking .setup( storage, StakingInfo { - bonded_denom: "TOKEN".to_string(), - unbonding_time: 60, - apr: validator_interest_rate, + bonded_denom: BONDED_DENOM.to_string(), + unbonding_time: UNBONDING_TIME, + apr: Decimal::percent(10), }, ) .unwrap(); + // add a validator router .staking - .add_validator(api, storage, &block, valoper1) + .add_validator(api, storage, &block, valoper) .unwrap(); }); + + // delegate tokens to validator + app.execute( + delegator_addr.clone(), + StakingMsg::Delegate { + validator: validator_addr.to_string(), + amount: coin(DELEGATION_AMOUNT, BONDED_DENOM), + } + .into(), + ) + .unwrap(); + + // delegation works immediately, so delegator should have now fewer tokens + let delegator_balance = app + .wrap() + .query_balance(delegator_addr.clone(), BONDED_DENOM) + .unwrap(); + assert_eq!(FEWER_AMOUNT, delegator_balance.amount.u128()); + + // validator should have now DELEGATION_AMOUNT of tokens assigned + let delegation = app + .wrap() + .query_delegation(delegator_addr.clone(), validator_addr.clone()) + .unwrap() + .unwrap(); + assert_eq!(DELEGATION_AMOUNT, delegation.amount.amount.u128()); + + // now, undelegate all bonded tokens + app.execute( + delegator_addr.clone(), + StakingMsg::Undelegate { + validator: validator_addr.to_string(), + amount: coin(DELEGATION_AMOUNT, BONDED_DENOM), + } + .into(), + ) + .unwrap(); + + // unbonding works with timeout, so tokens will be given back after unbonding time; + // while we do not change the block size or time, delegator should still have fewer tokens + let delegator_balance = app + .wrap() + .query_balance(delegator_addr.clone(), BONDED_DENOM) + .unwrap(); + assert_eq!(FEWER_AMOUNT, delegator_balance.amount.u128()); + + // now we update the block but with time that is shorter than unbonding time + app.update_block(|block| { + block.height += 1; + block.time = block.time.plus_seconds(UNBONDING_TIME - 1); + }); + + // delegator should still have fewer tokens + let delegator_balance = app + .wrap() + .query_balance(delegator_addr.clone(), BONDED_DENOM) + .unwrap(); + assert_eq!(FEWER_AMOUNT, delegator_balance.amount.u128()); + + // now we update the block so unbonding time is reached + app.update_block(|block| { + block.height += 1; + block.time = block.time.plus_seconds(1); + }); + + // delegator should have back the initial amount of tokens + let delegator_balance = app + .wrap() + .query_balance(delegator_addr.clone(), BONDED_DENOM) + .unwrap(); + assert_eq!(INITIAL_AMOUNT, delegator_balance.amount.u128()); + + // there should be no more delegations + let delegation = app + .wrap() + .query_delegation(delegator_addr, validator_addr) + .unwrap(); + assert_eq!(None, delegation); } From 61393c4c7fffc1c740758a63bbc14565fdc2b3ef Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 11 Jun 2024 14:11:28 +0200 Subject: [PATCH 202/250] Added tests. --- src/app.rs | 2 +- tests/test_app/mod.rs | 1 + tests/test_app/test_block_info.rs | 39 +++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 tests/test_app/test_block_info.rs diff --git a/src/app.rs b/src/app.rs index 2770caf8..39540a69 100644 --- a/src/app.rs +++ b/src/app.rs @@ -421,7 +421,7 @@ where .unwrap(); } - /// Returns a copy of the current block_info + /// Returns a copy of the current block info. pub fn block_info(&self) -> BlockInfo { self.block.clone() } diff --git a/tests/test_app/mod.rs b/tests/test_app/mod.rs index 49b7a7a0..6592434b 100644 --- a/tests/test_app/mod.rs +++ b/tests/test_app/mod.rs @@ -1,3 +1,4 @@ +mod test_block_info; #[cfg(feature = "cosmwasm_1_2")] mod test_instantiate2; mod test_store_code; diff --git a/tests/test_app/test_block_info.rs b/tests/test_app/test_block_info.rs new file mode 100644 index 00000000..0dd18119 --- /dev/null +++ b/tests/test_app/test_block_info.rs @@ -0,0 +1,39 @@ +use cosmwasm_std::testing::mock_env; +use cosmwasm_std::{BlockInfo, Timestamp}; +use cw_multi_test::{App, next_block}; + +#[test] +fn default_block_info_should_work() { + let env = mock_env(); + let app = App::default(); + let block = app.block_info(); + assert_eq!(env.block.chain_id, block.chain_id); + assert_eq!(env.block.height, block.height); + assert_eq!(env.block.time, block.time); +} + +#[test] +fn setting_block_info_should_work() { + let initial_block = BlockInfo { + chain_id: "mainnet-fermentation".to_string(), + height: 273_094, + time: Timestamp::default().plus_days(366), + }; + let mut app = App::default(); + app.set_block(initial_block.clone()); + let block = app.block_info(); + assert_eq!(initial_block.chain_id, block.chain_id); + assert_eq!(initial_block.height, block.height); + assert_eq!(initial_block.time, block.time); +} + +#[test] +fn incrementing_block_info_should_work() { + let env = mock_env(); + let mut app = App::default(); + app.update_block(next_block); + let block = app.block_info(); + assert_eq!(env.block.chain_id, block.chain_id); + assert_eq!(env.block.height + 1, block.height); + assert_eq!(env.block.time.plus_seconds(5), block.time); +} From eb6d5ebfc3f998f95a6ae2832a002633cd6a039f Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 11 Jun 2024 14:13:39 +0200 Subject: [PATCH 203/250] Updates. --- tests/test_app/test_block_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_app/test_block_info.rs b/tests/test_app/test_block_info.rs index 0dd18119..9ddee51c 100644 --- a/tests/test_app/test_block_info.rs +++ b/tests/test_app/test_block_info.rs @@ -1,6 +1,6 @@ use cosmwasm_std::testing::mock_env; use cosmwasm_std::{BlockInfo, Timestamp}; -use cw_multi_test::{App, next_block}; +use cw_multi_test::{next_block, App}; #[test] fn default_block_info_should_work() { From ada5902a55f7bd875a404f1873e5565d23a19aee Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 12 Jun 2024 10:58:58 +0200 Subject: [PATCH 204/250] Removed validation of empty attribute value. --- Cargo.lock | 8 +- src/tests/test_app.rs | 64 +++++++--------- src/wasm.rs | 12 ++- tests/mod.rs | 1 + tests/test_attributes/mod.rs | 1 + tests/test_attributes/test_empty_attribute.rs | 73 +++++++++++++++++++ 6 files changed, 112 insertions(+), 47 deletions(-) create mode 100644 tests/test_attributes/mod.rs create mode 100644 tests/test_attributes/test_empty_attribute.rs diff --git a/Cargo.lock b/Cargo.lock index 9b413df5..66622ae9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,9 +39,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.72" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -541,9 +541,9 @@ dependencies = [ [[package]] name = "object" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" dependencies = [ "memchr", ] diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index c2b0e965..c59390eb 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -1465,34 +1465,30 @@ mod response_validation { } #[test] - fn empty_attribute_value() { + fn empty_attribute_value_should_work() { let mut app = App::default(); let owner = app.api().addr_make("owner"); - let code_id = app.store_code(echo::contract()); let contract = app .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None) .unwrap(); - let err = app - .execute_contract( - owner, - contract, - &echo::Message:: { - data: None, - attributes: vec![ - Attribute::new("key", " "), - Attribute::new("proper", "proper_val"), - ], - ..echo::Message::default() - }, - &[], - ) - .unwrap_err(); - - assert_eq!(Error::empty_attribute_value("key"), err.downcast().unwrap()); + app.execute_contract( + owner, + contract, + &echo::Message:: { + data: None, + attributes: vec![ + Attribute::new("key", " "), + Attribute::new("proper", "proper_val"), + ], + ..echo::Message::default() + }, + &[], + ) + .unwrap(); } #[test] @@ -1530,29 +1526,25 @@ mod response_validation { let mut app = App::default(); let owner = app.api().addr_make("owner"); - let code_id = app.store_code(echo::contract()); let contract = app .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None) .unwrap(); - let err = app - .execute_contract( - owner, - contract, - &echo::Message:: { - data: None, - events: vec![Event::new("event") - .add_attribute("key", " ") - .add_attribute("proper", "proper_val")], - ..echo::Message::default() - }, - &[], - ) - .unwrap_err(); - - assert_eq!(Error::empty_attribute_value("key"), err.downcast().unwrap()); + app.execute_contract( + owner, + contract, + &echo::Message:: { + data: None, + events: vec![Event::new("event") + .add_attribute("key", " ") + .add_attribute("proper", "proper_val")], + ..echo::Message::default() + }, + &[], + ) + .unwrap(); } #[test] diff --git a/src/wasm.rs b/src/wasm.rs index 2ebc154a..04493cd2 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -357,24 +357,22 @@ impl WasmKeeper { .ok_or_else(|| Error::unregistered_code_id(code_id))?) } + /// Validates all attributes. + /// + /// In `wasmd`, before version v0.45.0 empty attribute values were not allowed. + /// Since `wasmd` v0.45.0 empty attribute values are allowed, + /// so the value is not validated anymore. fn verify_attributes(attributes: &[Attribute]) -> AnyResult<()> { for attr in attributes { let key = attr.key.trim(); let val = attr.value.trim(); - if key.is_empty() { bail!(Error::empty_attribute_key(val)); } - - if val.is_empty() { - bail!(Error::empty_attribute_value(key)); - } - if key.starts_with('_') { bail!(Error::reserved_attribute_key(key)); } } - Ok(()) } diff --git a/tests/mod.rs b/tests/mod.rs index 21ad4ffa..9001d161 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -3,6 +3,7 @@ mod test_api; mod test_app; mod test_app_builder; +mod test_attributes; mod test_contract_storage; mod test_module; mod test_prefixed_storage; diff --git a/tests/test_attributes/mod.rs b/tests/test_attributes/mod.rs new file mode 100644 index 00000000..94c1e819 --- /dev/null +++ b/tests/test_attributes/mod.rs @@ -0,0 +1 @@ +mod test_empty_attribute; diff --git a/tests/test_attributes/test_empty_attribute.rs b/tests/test_attributes/test_empty_attribute.rs new file mode 100644 index 00000000..137b9b21 --- /dev/null +++ b/tests/test_attributes/test_empty_attribute.rs @@ -0,0 +1,73 @@ +use cosmwasm_std::Empty; +use cw_multi_test::{App, Contract, ContractWrapper, Executor}; + +mod test_contract { + use cosmwasm_std::{Binary, Deps, DepsMut, Empty, Env, Event, MessageInfo, Response, StdError}; + + pub fn instantiate( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + _msg: Empty, + ) -> Result { + Ok(Response::default()) + } + + pub fn execute( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + _msg: Empty, + ) -> Result { + Ok(Response::::new() + .add_attribute("city", " ") + .add_attribute("street", "") + .add_event( + Event::new("location") + .add_attribute("longitude", " ") + .add_attribute("latitude", ""), + )) + } + + pub fn query(_deps: Deps, _env: Env, _msg: Empty) -> Result { + Ok(Binary::default()) + } +} + +fn contract() -> Box> { + Box::new(ContractWrapper::new_with_empty( + test_contract::execute, + test_contract::instantiate, + test_contract::query, + )) +} + +#[test] +fn empty_string_attribute_should_work() { + // prepare the blockchain + let mut app = App::default(); + + // prepare address for creator=owner=sender + let sender_addr = app.api().addr_make("sender"); + + // store the contract's code + let code_id = app.store_code_with_creator(sender_addr.clone(), contract()); + + // instantiate the contract + let contract_addr = app + .instantiate_contract( + code_id, + sender_addr.clone(), + &Empty {}, + &[], + "attributed", + None, + ) + .unwrap(); + + // execute message on the contract, this returns response + // with attributes having empty string values, which should not fail + assert!(app + .execute_contract(sender_addr, contract_addr, &Empty {}, &[]) + .is_ok()); +} From 50e6126a7033e6292915fc29bddbbd68b8581b41 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 12 Jun 2024 11:04:39 +0200 Subject: [PATCH 205/250] Removed unused error variant. --- src/error.rs | 9 --------- src/tests/test_error.rs | 4 ---- 2 files changed, 13 deletions(-) diff --git a/src/error.rs b/src/error.rs index fce588b2..9e32029b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -11,10 +11,6 @@ pub enum Error { #[error("Empty attribute key. Value: {0}")] EmptyAttributeKey(String), - /// Error variant for reporting an empty attribute value. - #[error("Empty attribute value. Key: {0}")] - EmptyAttributeValue(String), - /// Error variant for reporting a usage of reserved key prefix. #[error("Attribute key starts with reserved prefix _: {0}")] ReservedAttributeKey(String), @@ -58,11 +54,6 @@ impl Error { Self::EmptyAttributeKey(value.into()) } - /// Creates an instance of the [Error](Self) for empty attribute value. - pub fn empty_attribute_value(key: impl Into) -> Self { - Self::EmptyAttributeValue(key.into()) - } - /// Creates an instance of the [Error](Self) when reserved attribute key was used. pub fn reserved_attribute_key(key: impl Into) -> Self { Self::ReservedAttributeKey(key.into()) diff --git a/src/tests/test_error.rs b/src/tests/test_error.rs index 91292f4e..d3f16290 100644 --- a/src/tests/test_error.rs +++ b/src/tests/test_error.rs @@ -7,10 +7,6 @@ fn instantiating_error_should_work() { "Empty attribute key. Value: alpha", Error::empty_attribute_key("alpha").to_string() ); - assert_eq!( - "Empty attribute value. Key: beta", - Error::empty_attribute_value("beta").to_string() - ); assert_eq!( "Attribute key starts with reserved prefix _: gamma", Error::reserved_attribute_key("gamma").to_string() From affc2cdc755b5b3d8c4eff5ab5aaffdc164333b5 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 12 Jun 2024 11:17:21 +0200 Subject: [PATCH 206/250] Added explicit assertions. --- src/tests/test_app.rs | 58 ++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index c59390eb..2c459e76 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -1475,20 +1475,21 @@ mod response_validation { .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None) .unwrap(); - app.execute_contract( - owner, - contract, - &echo::Message:: { - data: None, - attributes: vec![ - Attribute::new("key", " "), - Attribute::new("proper", "proper_val"), - ], - ..echo::Message::default() - }, - &[], - ) - .unwrap(); + assert!(app + .execute_contract( + owner, + contract, + &echo::Message:: { + data: None, + attributes: vec![ + Attribute::new("key", " "), + Attribute::new("proper", "proper_val"), + ], + ..echo::Message::default() + }, + &[], + ) + .is_ok()); } #[test] @@ -1522,7 +1523,7 @@ mod response_validation { } #[test] - fn empty_event_attribute_value() { + fn empty_event_attribute_value_should_work() { let mut app = App::default(); let owner = app.api().addr_make("owner"); @@ -1532,19 +1533,20 @@ mod response_validation { .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None) .unwrap(); - app.execute_contract( - owner, - contract, - &echo::Message:: { - data: None, - events: vec![Event::new("event") - .add_attribute("key", " ") - .add_attribute("proper", "proper_val")], - ..echo::Message::default() - }, - &[], - ) - .unwrap(); + assert!(app + .execute_contract( + owner, + contract, + &echo::Message:: { + data: None, + events: vec![Event::new("event") + .add_attribute("key", " ") + .add_attribute("proper", "proper_val")], + ..echo::Message::default() + }, + &[], + ) + .is_ok()); } #[test] From f4bedffbcbd0512336841782d5950866f0dad0d2 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Wed, 12 Jun 2024 13:32:29 +0200 Subject: [PATCH 207/250] Reverted breaking change. --- src/error.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/error.rs b/src/error.rs index 9e32029b..b5c3c09a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -11,6 +11,11 @@ pub enum Error { #[error("Empty attribute key. Value: {0}")] EmptyAttributeKey(String), + /// Error variant for reporting an empty attribute value. + #[deprecated(note = "This error is not reported anymore. Will be removed in next release.")] + #[error("Empty attribute value. Key: {0}")] + EmptyAttributeValue(String), + /// Error variant for reporting a usage of reserved key prefix. #[error("Attribute key starts with reserved prefix _: {0}")] ReservedAttributeKey(String), @@ -54,6 +59,13 @@ impl Error { Self::EmptyAttributeKey(value.into()) } + #[deprecated(note = "This error is not reported anymore. Will be removed in next release.")] + /// Creates an instance of the [Error](Self) for empty attribute value. + pub fn empty_attribute_value(key: impl Into) -> Self { + #[allow(deprecated)] + Self::EmptyAttributeValue(key.into()) + } + /// Creates an instance of the [Error](Self) when reserved attribute key was used. pub fn reserved_attribute_key(key: impl Into) -> Self { Self::ReservedAttributeKey(key.into()) From e2fdc9426cffb745f6f318cd253b7b0f85ffb358 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 13 Jun 2024 15:59:23 +0200 Subject: [PATCH 208/250] Introduced common constants. --- src/staking.rs | 199 +++++++++++++++++++++++++++++++------------------ 1 file changed, 126 insertions(+), 73 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index cb311cdc..2b6c3655 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -14,14 +14,18 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::collections::{BTreeSet, VecDeque}; +/// Default denominator of the staking token. +pub const BONDED_DENOM: &str = "TOKEN"; + /// A structure containing some general staking parameters. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct StakingInfo { - /// The denominator of the staking token + /// The denominator of the staking token. pub bonded_denom: String, - /// Time between unbonding and receiving tokens in seconds + /// Time between unbonding and receiving tokens back (in seconds). pub unbonding_time: u64, - /// Interest rate per year (60 * 60 * 24 * 365 seconds) + /// Annual percentage rate (interest rate and any additional fees associated with bonding). + /// 1 year = 60 * 60 * 24 * 365 seconds. pub apr: Decimal, } @@ -29,7 +33,7 @@ impl Default for StakingInfo { /// Creates staking info with default settings. fn default() -> Self { StakingInfo { - bonded_denom: "TOKEN".to_string(), + bonded_denom: BONDED_DENOM.to_string(), unbonding_time: 60, apr: Decimal::percent(10), } @@ -53,7 +57,7 @@ impl Shares { } } -/// Holds some operational data about a validator +/// Holds some operational data about a validator. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] struct ValidatorInfo { /// The stakers that have staked with this validator. @@ -1034,7 +1038,13 @@ mod test { BalanceResponse, BankQuery, }; - /// Type alias for default build `Router` to make its reference in typical scenario + /// One year expressed in seconds. + const YEAR: u64 = 60 * 60 * 24 * 365; + + /// Half a year expressed in seconds. + const HALF_YEAR: u64 = YEAR / 2; + + /// Type alias for default build of [Router], to make its reference in typical test scenario. type BasicRouter = Router< BankKeeper, FailingModule, @@ -1075,7 +1085,7 @@ mod test { .setup( &mut store, StakingInfo { - bonded_denom: "TOKEN".to_string(), + bonded_denom: BONDED_DENOM.to_string(), unbonding_time: 60, apr, }, @@ -1176,7 +1186,7 @@ mod test { &block, &delegator_addr, &validator_addr, - coin(100, "TOKEN"), + coin(100, BONDED_DENOM), ) .unwrap(); @@ -1244,12 +1254,12 @@ mod test { &block, &delegator_addr, &validator_addr, - coin(200, "TOKEN"), + coin(200, BONDED_DENOM), ) .unwrap(); // wait 1/2 year - block.time = block.time.plus_seconds(60 * 60 * 24 * 365 / 2); + block.time = block.time.plus_seconds(HALF_YEAR); // should now have 200 * 10% / 2 - 10% commission = 9 tokens reward let rewards = stake @@ -1280,7 +1290,7 @@ mod test { assert_eq!(rewards.amount.u128(), 0); // wait another 1/2 year - block.time = block.time.plus_seconds(60 * 60 * 24 * 365 / 2); + block.time = block.time.plus_seconds(HALF_YEAR); // should now have 9 tokens again let rewards = stake .get_rewards(&store, &block, &delegator_addr, &validator_addr) @@ -1309,7 +1319,7 @@ mod test { &block, &delegator1, &validator, - coin(100, "TOKEN"), + coin(100, BONDED_DENOM), ) .unwrap(); stake @@ -1319,12 +1329,12 @@ mod test { &block, &delegator2, &validator, - coin(200, "TOKEN"), + coin(200, BONDED_DENOM), ) .unwrap(); // wait 1 year - block.time = block.time.plus_seconds(60 * 60 * 24 * 365); + block.time = block.time.plus_seconds(YEAR); // delegator1 should now have 100 * 10% - 10% commission = 9 tokens let rewards = stake @@ -1349,12 +1359,12 @@ mod test { &block, &delegator1, &validator, - coin(100, "TOKEN"), + coin(100, BONDED_DENOM), ) .unwrap(); // wait another year - block.time = block.time.plus_seconds(60 * 60 * 24 * 365); + block.time = block.time.plus_seconds(YEAR); // delegator1 should now have 9 + 200 * 10% - 10% commission = 27 tokens let rewards = stake @@ -1379,7 +1389,7 @@ mod test { &block, &delegator2, &validator, - coin(100, "TOKEN"), + coin(100, BONDED_DENOM), ) .unwrap(); @@ -1405,7 +1415,7 @@ mod test { &block, BankQuery::Balance { address: delegator1.to_string(), - denom: "TOKEN".to_string(), + denom: BONDED_DENOM.to_string(), }, ) .unwrap(), @@ -1427,7 +1437,7 @@ mod test { ); // wait another year - block.time = block.time.plus_seconds(60 * 60 * 24 * 365); + block.time = block.time.plus_seconds(YEAR); // delegator1 should now have 0 + 200 * 10% - 10% commission = 18 tokens let rewards = stake @@ -1528,7 +1538,7 @@ mod test { env, BankQuery::Balance { address: addr.to_string(), - denom: "TOKEN".to_string(), + denom: BONDED_DENOM.to_string(), }, ) .unwrap(); @@ -1549,7 +1559,11 @@ mod test { test_env .router .bank - .init_balance(&mut test_env.store, &delegator1, vec![coin(1000, "TOKEN")]) + .init_balance( + &mut test_env.store, + &delegator1, + vec![coin(1000, BONDED_DENOM)], + ) .unwrap(); // add second validator @@ -1576,7 +1590,7 @@ mod test { delegator1.clone(), StakingMsg::Delegate { validator: validator1.to_string(), - amount: coin(100, "TOKEN"), + amount: coin(100, BONDED_DENOM), }, ) .unwrap(); @@ -1585,7 +1599,7 @@ mod test { assert_balances(&test_env, vec![(delegator1.clone(), 900)]); // wait a year - test_env.block.time = test_env.block.time.plus_seconds(60 * 60 * 24 * 365); + test_env.block.time = test_env.block.time.plus_seconds(YEAR); // change the withdrawal address execute_distr( @@ -1621,7 +1635,7 @@ mod test { StakingMsg::Redelegate { src_validator: validator1.to_string(), dst_validator: validator2.to_string(), - amount: coin(100, "TOKEN"), + amount: coin(100, BONDED_DENOM), }, ) .unwrap(); @@ -1641,7 +1655,7 @@ mod test { [Delegation::new( delegator1.clone(), validator2.to_string(), - coin(100, "TOKEN"), + coin(100, BONDED_DENOM), )] ); @@ -1651,7 +1665,7 @@ mod test { delegator1.clone(), StakingMsg::Undelegate { validator: validator2.to_string(), - amount: coin(100, "TOKEN"), + amount: coin(100, BONDED_DENOM), }, ) .unwrap(); @@ -1686,7 +1700,7 @@ mod test { test_env .router .bank - .init_balance(&mut test_env.store, &delegator, coins(100, "TOKEN")) + .init_balance(&mut test_env.store, &delegator, coins(100, BONDED_DENOM)) .unwrap(); // Stake 100 tokens to the validator. @@ -1695,7 +1709,7 @@ mod test { delegator.clone(), StakingMsg::Delegate { validator: validator.to_string(), - amount: coin(100, "TOKEN"), + amount: coin(100, BONDED_DENOM), }, ) .unwrap(); @@ -1766,7 +1780,11 @@ mod test { test_env .router .bank - .init_balance(&mut test_env.store, &delegator1, vec![coin(100, "TOKEN")]) + .init_balance( + &mut test_env.store, + &delegator1, + vec![coin(100, BONDED_DENOM)], + ) .unwrap(); // delegate 100 tokens to validator1 @@ -1775,7 +1793,7 @@ mod test { delegator1.clone(), StakingMsg::Delegate { validator: validator1.to_string(), - amount: coin(100, "TOKEN"), + amount: coin(100, BONDED_DENOM), }, ) .unwrap(); @@ -1786,7 +1804,7 @@ mod test { delegator1.clone(), StakingMsg::Undelegate { validator: validator1.to_string(), - amount: coin(200, "TOKEN"), + amount: coin(200, BONDED_DENOM), }, ) .unwrap_err(); @@ -1818,7 +1836,7 @@ mod test { StakingMsg::Redelegate { src_validator: validator1.to_string(), dst_validator: validator2.to_string(), - amount: coin(200, "TOKEN"), + amount: coin(200, BONDED_DENOM), }, ) .unwrap_err(); @@ -1830,7 +1848,7 @@ mod test { delegator1.clone(), StakingMsg::Undelegate { validator: validator2.to_string(), - amount: coin(100, "TOKEN"), + amount: coin(100, BONDED_DENOM), }, ) .unwrap_err(); @@ -1920,7 +1938,11 @@ mod test { test_env .router .bank - .init_balance(&mut test_env.store, &delegator, vec![coin(100, "TOKEN")]) + .init_balance( + &mut test_env.store, + &delegator, + vec![coin(100, BONDED_DENOM)], + ) .unwrap(); // try to delegate @@ -1929,7 +1951,7 @@ mod test { delegator.clone(), StakingMsg::Delegate { validator: validator.to_string(), - amount: coin(100, "TOKEN"), + amount: coin(100, BONDED_DENOM), }, ) .unwrap_err(); @@ -1941,7 +1963,7 @@ mod test { delegator.clone(), StakingMsg::Undelegate { validator: validator.to_string(), - amount: coin(100, "TOKEN"), + amount: coin(100, BONDED_DENOM), }, ) .unwrap_err(); @@ -1961,7 +1983,7 @@ mod test { delegator_addr.clone(), StakingMsg::Delegate { validator: validator.to_string(), - amount: coin(0, "TOKEN"), + amount: coin(0, BONDED_DENOM), }, ) .unwrap_err(); @@ -1973,7 +1995,7 @@ mod test { delegator_addr, StakingMsg::Undelegate { validator: validator.to_string(), - amount: coin(0, "TOKEN"), + amount: coin(0, BONDED_DENOM), }, ) .unwrap_err(); @@ -1994,12 +2016,20 @@ mod test { test_env .router .bank - .init_balance(&mut test_env.store, &delegator1, vec![coin(260, "TOKEN")]) + .init_balance( + &mut test_env.store, + &delegator1, + vec![coin(260, BONDED_DENOM)], + ) .unwrap(); test_env .router .bank - .init_balance(&mut test_env.store, &delegator2, vec![coin(150, "TOKEN")]) + .init_balance( + &mut test_env.store, + &delegator2, + vec![coin(150, BONDED_DENOM)], + ) .unwrap(); // add another validator @@ -2047,7 +2077,7 @@ mod test { // query bonded denom let response: BondedDenomResponse = query_stake(&test_env, StakingQuery::BondedDenom {}).unwrap(); - assert_eq!(response.denom, "TOKEN"); + assert_eq!(response.denom, BONDED_DENOM); // delegate some tokens with delegator1 and delegator2 execute_stake( @@ -2055,7 +2085,7 @@ mod test { delegator1.clone(), StakingMsg::Delegate { validator: validator1.to_string(), - amount: coin(100, "TOKEN"), + amount: coin(100, BONDED_DENOM), }, ) .unwrap(); @@ -2064,7 +2094,7 @@ mod test { delegator1.clone(), StakingMsg::Delegate { validator: validator2.to_string(), - amount: coin(160, "TOKEN"), + amount: coin(160, BONDED_DENOM), }, ) .unwrap(); @@ -2073,7 +2103,7 @@ mod test { delegator2.clone(), StakingMsg::Delegate { validator: validator1.to_string(), - amount: coin(150, "TOKEN"), + amount: coin(150, BONDED_DENOM), }, ) .unwrap(); @@ -2083,7 +2113,7 @@ mod test { delegator1.clone(), StakingMsg::Undelegate { validator: validator1.to_string(), - amount: coin(50, "TOKEN"), + amount: coin(50, BONDED_DENOM), }, ) .unwrap(); @@ -2092,7 +2122,7 @@ mod test { delegator2.clone(), StakingMsg::Undelegate { validator: validator1.to_string(), - amount: coin(50, "TOKEN"), + amount: coin(50, BONDED_DENOM), }, ) .unwrap(); @@ -2111,12 +2141,12 @@ mod test { Delegation::new( delegator1.clone(), validator1.to_string(), - coin(50, "TOKEN"), + coin(50, BONDED_DENOM), ), Delegation::new( delegator1.clone(), validator2.to_string(), - coin(160, "TOKEN"), + coin(160, BONDED_DENOM), ), ] ); @@ -2133,8 +2163,8 @@ mod test { FullDelegation::new( delegator2.clone(), validator1.to_string(), - coin(100, "TOKEN"), - coin(100, "TOKEN"), + coin(100, BONDED_DENOM), + coin(100, BONDED_DENOM), vec![], ), ); @@ -2152,12 +2182,20 @@ mod test { test_env .router .bank - .init_balance(&mut test_env.store, &delegator1, vec![coin(100, "TOKEN")]) + .init_balance( + &mut test_env.store, + &delegator1, + vec![coin(100, BONDED_DENOM)], + ) .unwrap(); test_env .router .bank - .init_balance(&mut test_env.store, &delegator2, vec![coin(150, "TOKEN")]) + .init_balance( + &mut test_env.store, + &delegator2, + vec![coin(150, BONDED_DENOM)], + ) .unwrap(); // delegate some tokens with delegator1 and delegator2 @@ -2166,7 +2204,7 @@ mod test { delegator1.clone(), StakingMsg::Delegate { validator: validator.to_string(), - amount: coin(100, "TOKEN"), + amount: coin(100, BONDED_DENOM), }, ) .unwrap(); @@ -2175,7 +2213,7 @@ mod test { delegator2.clone(), StakingMsg::Delegate { validator: validator.to_string(), - amount: coin(150, "TOKEN"), + amount: coin(150, BONDED_DENOM), }, ) .unwrap(); @@ -2185,7 +2223,7 @@ mod test { delegator1.clone(), StakingMsg::Undelegate { validator: validator.to_string(), - amount: coin(50, "TOKEN"), + amount: coin(50, BONDED_DENOM), }, ) .unwrap(); @@ -2195,7 +2233,7 @@ mod test { delegator2.clone(), StakingMsg::Undelegate { validator: validator.to_string(), - amount: coin(150, "TOKEN"), + amount: coin(150, BONDED_DENOM), }, ) .unwrap(); @@ -2213,7 +2251,7 @@ mod test { vec![Delegation::new( delegator1.clone(), validator.to_string(), - coin(50, "TOKEN"), + coin(50, BONDED_DENOM), )] ); let response2: DelegationResponse = query_stake( @@ -2232,7 +2270,7 @@ mod test { delegator1.clone(), StakingMsg::Undelegate { validator: validator.to_string(), - amount: coin(25, "TOKEN"), + amount: coin(25, BONDED_DENOM), }, ) .unwrap(); @@ -2242,7 +2280,7 @@ mod test { delegator1.clone(), StakingMsg::Undelegate { validator: validator.to_string(), - amount: coin(25, "TOKEN"), + amount: coin(25, BONDED_DENOM), }, ) .unwrap(); @@ -2280,7 +2318,11 @@ mod test { test_env .router .bank - .init_balance(&mut test_env.store, &delegator, vec![coin(100, "TOKEN")]) + .init_balance( + &mut test_env.store, + &delegator, + vec![coin(100, BONDED_DENOM)], + ) .unwrap(); // delegate all tokens @@ -2289,7 +2331,7 @@ mod test { delegator.clone(), StakingMsg::Delegate { validator: validator.to_string(), - amount: coin(100, "TOKEN"), + amount: coin(100, BONDED_DENOM), }, ) .unwrap(); @@ -2299,7 +2341,7 @@ mod test { delegator.clone(), StakingMsg::Undelegate { validator: validator.to_string(), - amount: coin(50, "TOKEN"), + amount: coin(50, BONDED_DENOM), }, ) .unwrap(); @@ -2309,7 +2351,7 @@ mod test { delegator.clone(), StakingMsg::Undelegate { validator: validator.to_string(), - amount: coin(30, "TOKEN"), + amount: coin(30, BONDED_DENOM), }, ) .unwrap(); @@ -2319,7 +2361,7 @@ mod test { delegator.clone(), StakingMsg::Undelegate { validator: validator.to_string(), - amount: coin(20, "TOKEN"), + amount: coin(20, BONDED_DENOM), }, ) .unwrap(); @@ -2404,7 +2446,11 @@ mod test { test_env .router .bank - .init_balance(&mut test_env.store, &delegator, vec![coin(333, "TOKEN")]) + .init_balance( + &mut test_env.store, + &delegator, + vec![coin(333, BONDED_DENOM)], + ) .unwrap(); // delegate some tokens @@ -2413,7 +2459,7 @@ mod test { delegator.clone(), StakingMsg::Delegate { validator: validator.to_string(), - amount: coin(333, "TOKEN"), + amount: coin(333, BONDED_DENOM), }, ) .unwrap(); @@ -2423,7 +2469,7 @@ mod test { delegator.clone(), StakingMsg::Undelegate { validator: validator.to_string(), - amount: coin(111, "TOKEN"), + amount: coin(111, BONDED_DENOM), }, ) .unwrap(); @@ -2454,7 +2500,11 @@ mod test { .unwrap(); assert_eq!( response1.delegations[0], - Delegation::new(delegator.clone(), validator.to_string(), coin(111, "TOKEN"),) + Delegation::new( + delegator.clone(), + validator.to_string(), + coin(111, BONDED_DENOM), + ) ); // wait until unbonding is complete and check if amount was slashed @@ -2474,7 +2524,7 @@ mod test { &test_env.store, &test_env.block, )) - .query_balance(delegator, "TOKEN") + .query_balance(delegator, BONDED_DENOM) .unwrap(); assert_eq!(balance.amount.u128(), 55); } @@ -2489,11 +2539,14 @@ mod test { test_env .router .bank - .init_balance(&mut test_env.store, &delegator, vec![coin(100, "TOKEN")]) + .init_balance( + &mut test_env.store, + &delegator, + vec![coin(100, BONDED_DENOM)], + ) .unwrap(); // wait a year before staking - const YEAR: u64 = 60 * 60 * 24 * 365; test_env.block.time = test_env.block.time.plus_seconds(YEAR); // delegate some tokens @@ -2502,7 +2555,7 @@ mod test { delegator.clone(), StakingMsg::Delegate { validator: validator.to_string(), - amount: coin(100, "TOKEN"), + amount: coin(100, BONDED_DENOM), }, ) .unwrap(); @@ -2521,7 +2574,7 @@ mod test { .unwrap(); assert_eq!( response.delegation.unwrap().accumulated_rewards, - vec![coin(10, "TOKEN")] // 10% of 100 + vec![coin(10, BONDED_DENOM)] // 10% of 100 ); } } From 15a22be6773d345080b841a346e5851f52551b19 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 13 Jun 2024 16:03:54 +0200 Subject: [PATCH 209/250] Simplified constants. --- src/staking.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 2b6c3655..1dbd743f 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1041,9 +1041,6 @@ mod test { /// One year expressed in seconds. const YEAR: u64 = 60 * 60 * 24 * 365; - /// Half a year expressed in seconds. - const HALF_YEAR: u64 = YEAR / 2; - /// Type alias for default build of [Router], to make its reference in typical test scenario. type BasicRouter = Router< BankKeeper, @@ -1259,7 +1256,7 @@ mod test { .unwrap(); // wait 1/2 year - block.time = block.time.plus_seconds(HALF_YEAR); + block.time = block.time.plus_seconds(YEAR / 2); // should now have 200 * 10% / 2 - 10% commission = 9 tokens reward let rewards = stake @@ -1290,7 +1287,7 @@ mod test { assert_eq!(rewards.amount.u128(), 0); // wait another 1/2 year - block.time = block.time.plus_seconds(HALF_YEAR); + block.time = block.time.plus_seconds(YEAR / 2); // should now have 9 tokens again let rewards = stake .get_rewards(&store, &block, &delegator_addr, &validator_addr) From 4720bbc73e02e47b197dd2ea634753004e6066dc Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 13 Jun 2024 16:11:58 +0200 Subject: [PATCH 210/250] Refactored setup_test_env helper function. --- src/staking.rs | 50 ++++++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 1dbd743f..78215b4e 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1067,8 +1067,8 @@ mod test { } fn setup_test_env( - apr: Decimal, - validator_commission: Decimal, + apr: u64, + validator_commission: u64, ) -> (MockApi, MockStorage, BasicRouter, BlockInfo, Addr) { let api = MockApi::default(); let router = mock_router(); @@ -1084,7 +1084,7 @@ mod test { StakingInfo { bonded_denom: BONDED_DENOM.to_string(), unbonding_time: 60, - apr, + apr: Decimal::percent(apr), }, ) .unwrap(); @@ -1092,7 +1092,7 @@ mod test { // add validator let valoper1 = Validator::new( validator_addr.to_string(), - validator_commission, + Decimal::percent(validator_commission), Decimal::percent(100), Decimal::percent(1), ); @@ -1236,8 +1236,7 @@ mod test { #[test] fn rewards_work_for_single_delegator() { - let (api, mut store, router, mut block, validator_addr) = - setup_test_env(Decimal::percent(10), Decimal::percent(10)); + let (api, mut store, router, mut block, validator_addr) = setup_test_env(10, 10); let stake = &router.staking; let distr = &router.distribution; let delegator_addr = api.addr_make("delegator"); @@ -1298,8 +1297,7 @@ mod test { #[test] fn rewards_work_for_multiple_delegators() { - let (api, mut store, router, mut block, validator) = - setup_test_env(Decimal::percent(10), Decimal::percent(10)); + let (api, mut store, router, mut block, validator) = setup_test_env(10, 10); let stake = &router.staking; let distr = &router.distribution; let bank = &router.bank; @@ -1546,8 +1544,7 @@ mod test { #[test] fn execute() { // test all execute msgs - let (mut test_env, validator1) = - TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + let (mut test_env, validator1) = TestEnv::wrap(setup_test_env(10, 10)); let delegator1 = test_env.api.addr_make("delegator1"); let reward_receiver = test_env.api.addr_make("rewardreceiver"); @@ -1688,8 +1685,7 @@ mod test { #[test] fn can_set_withdraw_address() { - let (mut test_env, validator) = - TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + let (mut test_env, validator) = TestEnv::wrap(setup_test_env(10, 10)); let delegator = test_env.api.addr_make("delegator"); let reward_receiver = test_env.api.addr_make("rewardreceiver"); @@ -1768,8 +1764,7 @@ mod test { #[test] fn cannot_steal() { - let (mut test_env, validator1) = - TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + let (mut test_env, validator1) = TestEnv::wrap(setup_test_env(10, 10)); let delegator1 = test_env.api.addr_make("delegator1"); @@ -1857,8 +1852,7 @@ mod test { #[test] fn denom_validation() { - let (mut test_env, validator_addr) = - TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + let (mut test_env, validator_addr) = TestEnv::wrap(setup_test_env(10, 10)); let delegator_addr = test_env.api.addr_make("delegator"); @@ -1892,8 +1886,7 @@ mod test { #[test] fn cannot_slash_nonexistent() { - let (mut test_env, _) = - TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + let (mut test_env, _) = TestEnv::wrap(setup_test_env(10, 10)); let delegator = test_env.api.addr_make("delegator"); let non_existing_validator = test_env.api.addr_make("nonexistingvaloper"); @@ -1925,8 +1918,7 @@ mod test { #[test] fn non_existent_validator() { - let (mut test_env, _) = - TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + let (mut test_env, _) = TestEnv::wrap(setup_test_env(10, 10)); let delegator = test_env.api.addr_make("delegator1"); let validator = test_env.api.addr_make("testvaloper2"); @@ -1969,8 +1961,7 @@ mod test { #[test] fn zero_staking_forbidden() { - let (mut test_env, validator) = - TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + let (mut test_env, validator) = TestEnv::wrap(setup_test_env(10, 10)); let delegator_addr = test_env.api.addr_make("delegator"); @@ -2002,8 +1993,7 @@ mod test { #[test] fn query_staking() { // run all staking queries - let (mut test_env, validator1) = - TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + let (mut test_env, validator1) = TestEnv::wrap(setup_test_env(10, 10)); let delegator1 = test_env.api.addr_make("delegator1"); let delegator2 = test_env.api.addr_make("delegator2"); let validator2 = test_env.api.addr_make("testvaloper2"); @@ -2170,8 +2160,7 @@ mod test { #[test] fn delegation_queries_unbonding() { // run all staking queries - let (mut test_env, validator) = - TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + let (mut test_env, validator) = TestEnv::wrap(setup_test_env(10, 10)); let delegator1 = test_env.api.addr_make("delegator1"); let delegator2 = test_env.api.addr_make("delegator2"); @@ -2307,8 +2296,7 @@ mod test { #[test] fn partial_unbonding_reduces_stake() { - let (mut test_env, validator) = - TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + let (mut test_env, validator) = TestEnv::wrap(setup_test_env(10, 10)); let delegator = test_env.api.addr_make("delegator1"); // init balance @@ -2435,8 +2423,7 @@ mod test { #[test] fn delegations_slashed() { // run all staking queries - let (mut test_env, validator) = - TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + let (mut test_env, validator) = TestEnv::wrap(setup_test_env(10, 10)); let delegator = test_env.api.addr_make("delegator"); // init balance @@ -2528,8 +2515,7 @@ mod test { #[test] fn rewards_initial_wait() { - let (mut test_env, validator) = - TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::zero())); + let (mut test_env, validator) = TestEnv::wrap(setup_test_env(10, 0)); let delegator = test_env.api.addr_make("delegator"); // init balance From 01d8857d649113dee29f57540011c093827a1252 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 13 Jun 2024 16:22:34 +0200 Subject: [PATCH 211/250] Renamed test_env variable in tests. --- src/staking.rs | 428 +++++++++++++++++++------------------------------ 1 file changed, 168 insertions(+), 260 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 78215b4e..157dd6a0 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1543,32 +1543,25 @@ mod test { #[test] fn execute() { - // test all execute msgs - let (mut test_env, validator1) = TestEnv::wrap(setup_test_env(10, 10)); + let (mut env, validator1) = TestEnv::wrap(setup_test_env(10, 10)); - let delegator1 = test_env.api.addr_make("delegator1"); - let reward_receiver = test_env.api.addr_make("rewardreceiver"); + let delegator1 = env.api.addr_make("delegator1"); + let reward_receiver = env.api.addr_make("rewardreceiver"); // fund delegator1 account - test_env - .router + env.router .bank - .init_balance( - &mut test_env.store, - &delegator1, - vec![coin(1000, BONDED_DENOM)], - ) + .init_balance(&mut env.store, &delegator1, vec![coin(1000, BONDED_DENOM)]) .unwrap(); // add second validator - let validator2 = test_env.api.addr_make("validator2"); - test_env - .router + let validator2 = env.api.addr_make("validator2"); + env.router .staking .add_validator( - &test_env.api, - &mut test_env.store, - &test_env.block, + &env.api, + &mut env.store, + &env.block, Validator::new( validator2.to_string(), Decimal::zero(), @@ -1580,7 +1573,7 @@ mod test { // delegate 100 tokens to validator1 execute_stake( - &mut test_env, + &mut env, delegator1.clone(), StakingMsg::Delegate { validator: validator1.to_string(), @@ -1590,14 +1583,14 @@ mod test { .unwrap(); // should now have 100 tokens less - assert_balances(&test_env, vec![(delegator1.clone(), 900)]); + assert_balances(&env, vec![(delegator1.clone(), 900)]); // wait a year - test_env.block.time = test_env.block.time.plus_seconds(YEAR); + env.block.time = env.block.time.plus_seconds(YEAR); // change the withdrawal address execute_distr( - &mut test_env, + &mut env, delegator1.clone(), DistributionMsg::SetWithdrawAddress { address: reward_receiver.to_string(), @@ -1607,7 +1600,7 @@ mod test { // withdraw rewards execute_distr( - &mut test_env, + &mut env, delegator1.clone(), DistributionMsg::WithdrawDelegatorReward { validator: validator1.to_string(), @@ -1617,14 +1610,14 @@ mod test { // withdrawal address received rewards. assert_balances( - &test_env, + &env, // one year, 10%apr, 10% commission, 100 tokens staked vec![(reward_receiver, 100 / 10 * 9 / 10)], ); // redelegate to validator2 execute_stake( - &mut test_env, + &mut env, delegator1.clone(), StakingMsg::Redelegate { src_validator: validator1.to_string(), @@ -1635,10 +1628,10 @@ mod test { .unwrap(); // should have same amount as before (rewards receiver received rewards). - assert_balances(&test_env, vec![(delegator1.clone(), 900)]); + assert_balances(&env, vec![(delegator1.clone(), 900)]); let delegations: AllDelegationsResponse = query_stake( - &test_env, + &env, StakingQuery::AllDelegations { delegator: delegator1.to_string(), }, @@ -1655,7 +1648,7 @@ mod test { // undelegate all tokens execute_stake( - &mut test_env, + &mut env, delegator1.clone(), StakingMsg::Undelegate { validator: validator2.to_string(), @@ -1665,40 +1658,33 @@ mod test { .unwrap(); // wait for unbonding period (60 seconds in default config) - test_env.block.time = test_env.block.time.plus_seconds(60); + env.block.time = env.block.time.plus_seconds(60); // need to manually cause queue to get processed - test_env - .router + env.router .staking - .process_queue( - &test_env.api, - &mut test_env.store, - &test_env.router, - &test_env.block, - ) + .process_queue(&env.api, &mut env.store, &env.router, &env.block) .unwrap(); // check bank balance - assert_balances(&test_env, vec![(delegator1.clone(), 1000)]); + assert_balances(&env, vec![(delegator1.clone(), 1000)]); } #[test] fn can_set_withdraw_address() { - let (mut test_env, validator) = TestEnv::wrap(setup_test_env(10, 10)); + let (mut env, validator) = TestEnv::wrap(setup_test_env(10, 10)); - let delegator = test_env.api.addr_make("delegator"); - let reward_receiver = test_env.api.addr_make("rewardreceiver"); + let delegator = env.api.addr_make("delegator"); + let reward_receiver = env.api.addr_make("rewardreceiver"); - test_env - .router + env.router .bank - .init_balance(&mut test_env.store, &delegator, coins(100, BONDED_DENOM)) + .init_balance(&mut env.store, &delegator, coins(100, BONDED_DENOM)) .unwrap(); // Stake 100 tokens to the validator. execute_stake( - &mut test_env, + &mut env, delegator.clone(), StakingMsg::Delegate { validator: validator.to_string(), @@ -1709,7 +1695,7 @@ mod test { // Change rewards receiver. execute_distr( - &mut test_env, + &mut env, delegator.clone(), DistributionMsg::SetWithdrawAddress { address: reward_receiver.to_string(), @@ -1718,11 +1704,11 @@ mod test { .unwrap(); // A year passes. - test_env.block.time = test_env.block.time.plus_seconds(60 * 60 * 24 * 365); + env.block.time = env.block.time.plus_seconds(60 * 60 * 24 * 365); // Withdraw rewards to reward receiver. execute_distr( - &mut test_env, + &mut env, delegator.clone(), DistributionMsg::WithdrawDelegatorReward { validator: validator.to_string(), @@ -1732,7 +1718,7 @@ mod test { // Change reward receiver back to delegator. execute_distr( - &mut test_env, + &mut env, delegator.clone(), DistributionMsg::SetWithdrawAddress { address: delegator.to_string(), @@ -1741,11 +1727,11 @@ mod test { .unwrap(); // Another year passes. - test_env.block.time = test_env.block.time.plus_seconds(60 * 60 * 24 * 365); + env.block.time = env.block.time.plus_seconds(60 * 60 * 24 * 365); // Withdraw rewards to delegator. execute_distr( - &mut test_env, + &mut env, delegator.clone(), DistributionMsg::WithdrawDelegatorReward { validator: validator.to_string(), @@ -1757,31 +1743,26 @@ mod test { let rewards_yr = 100 / 10 * 9 / 10; assert_balances( - &test_env, + &env, vec![(reward_receiver, rewards_yr), (delegator, rewards_yr)], ); } #[test] fn cannot_steal() { - let (mut test_env, validator1) = TestEnv::wrap(setup_test_env(10, 10)); + let (mut env, validator1) = TestEnv::wrap(setup_test_env(10, 10)); - let delegator1 = test_env.api.addr_make("delegator1"); + let delegator1 = env.api.addr_make("delegator1"); // fund delegator1 account - test_env - .router + env.router .bank - .init_balance( - &mut test_env.store, - &delegator1, - vec![coin(100, BONDED_DENOM)], - ) + .init_balance(&mut env.store, &delegator1, vec![coin(100, BONDED_DENOM)]) .unwrap(); // delegate 100 tokens to validator1 execute_stake( - &mut test_env, + &mut env, delegator1.clone(), StakingMsg::Delegate { validator: validator1.to_string(), @@ -1792,7 +1773,7 @@ mod test { // undelegate more tokens than we have let e = execute_stake( - &mut test_env, + &mut env, delegator1.clone(), StakingMsg::Undelegate { validator: validator1.to_string(), @@ -1804,14 +1785,13 @@ mod test { assert_eq!(e.to_string(), "invalid shares amount"); // add second validator - let validator2 = test_env.api.addr_make("validator2"); - test_env - .router + let validator2 = env.api.addr_make("validator2"); + env.router .staking .add_validator( - &test_env.api, - &mut test_env.store, - &test_env.block, + &env.api, + &mut env.store, + &env.block, Validator::new( validator2.to_string(), Decimal::zero(), @@ -1823,7 +1803,7 @@ mod test { // redelegate more tokens than we have let e = execute_stake( - &mut test_env, + &mut env, delegator1.clone(), StakingMsg::Redelegate { src_validator: validator1.to_string(), @@ -1836,7 +1816,7 @@ mod test { // undelegate from non-existing delegation let e = execute_stake( - &mut test_env, + &mut env, delegator1.clone(), StakingMsg::Undelegate { validator: validator2.to_string(), @@ -1852,24 +1832,19 @@ mod test { #[test] fn denom_validation() { - let (mut test_env, validator_addr) = TestEnv::wrap(setup_test_env(10, 10)); + let (mut env, validator_addr) = TestEnv::wrap(setup_test_env(10, 10)); - let delegator_addr = test_env.api.addr_make("delegator"); + let delegator_addr = env.api.addr_make("delegator"); // fund delegator1 account - test_env - .router + env.router .bank - .init_balance( - &mut test_env.store, - &delegator_addr, - vec![coin(100, "FAKE")], - ) + .init_balance(&mut env.store, &delegator_addr, vec![coin(100, "FAKE")]) .unwrap(); // try to delegate 100 to validator let e = execute_stake( - &mut test_env, + &mut env, delegator_addr.clone(), StakingMsg::Delegate { validator: validator_addr.to_string(), @@ -1886,27 +1861,26 @@ mod test { #[test] fn cannot_slash_nonexistent() { - let (mut test_env, _) = TestEnv::wrap(setup_test_env(10, 10)); + let (mut env, _) = TestEnv::wrap(setup_test_env(10, 10)); - let delegator = test_env.api.addr_make("delegator"); - let non_existing_validator = test_env.api.addr_make("nonexistingvaloper"); + let delegator = env.api.addr_make("delegator"); + let non_existing_validator = env.api.addr_make("nonexistingvaloper"); // fund delegator1 account - test_env - .router + env.router .bank - .init_balance(&mut test_env.store, &delegator, vec![coin(100, "FAKE")]) + .init_balance(&mut env.store, &delegator, vec![coin(100, "FAKE")]) .unwrap(); // try to delegate 100 to validator1 - let e = test_env + let e = env .router .staking .sudo( - &test_env.api, - &mut test_env.store, - &test_env.router, - &test_env.block, + &env.api, + &mut env.store, + &env.router, + &env.block, StakingSudo::Slash { validator: non_existing_validator.to_string(), percentage: Decimal::percent(50), @@ -1918,25 +1892,20 @@ mod test { #[test] fn non_existent_validator() { - let (mut test_env, _) = TestEnv::wrap(setup_test_env(10, 10)); + let (mut env, _) = TestEnv::wrap(setup_test_env(10, 10)); - let delegator = test_env.api.addr_make("delegator1"); - let validator = test_env.api.addr_make("testvaloper2"); + let delegator = env.api.addr_make("delegator1"); + let validator = env.api.addr_make("testvaloper2"); // init balances - test_env - .router + env.router .bank - .init_balance( - &mut test_env.store, - &delegator, - vec![coin(100, BONDED_DENOM)], - ) + .init_balance(&mut env.store, &delegator, vec![coin(100, BONDED_DENOM)]) .unwrap(); // try to delegate let err = execute_stake( - &mut test_env, + &mut env, delegator.clone(), StakingMsg::Delegate { validator: validator.to_string(), @@ -1948,7 +1917,7 @@ mod test { // try to undelegate let err = execute_stake( - &mut test_env, + &mut env, delegator.clone(), StakingMsg::Undelegate { validator: validator.to_string(), @@ -1961,13 +1930,13 @@ mod test { #[test] fn zero_staking_forbidden() { - let (mut test_env, validator) = TestEnv::wrap(setup_test_env(10, 10)); + let (mut env, validator) = TestEnv::wrap(setup_test_env(10, 10)); - let delegator_addr = test_env.api.addr_make("delegator"); + let delegator_addr = env.api.addr_make("delegator"); // delegate 0 let err = execute_stake( - &mut test_env, + &mut env, delegator_addr.clone(), StakingMsg::Delegate { validator: validator.to_string(), @@ -1979,7 +1948,7 @@ mod test { // undelegate 0 let err = execute_stake( - &mut test_env, + &mut env, delegator_addr, StakingMsg::Undelegate { validator: validator.to_string(), @@ -1992,31 +1961,21 @@ mod test { #[test] fn query_staking() { - // run all staking queries - let (mut test_env, validator1) = TestEnv::wrap(setup_test_env(10, 10)); - let delegator1 = test_env.api.addr_make("delegator1"); - let delegator2 = test_env.api.addr_make("delegator2"); - let validator2 = test_env.api.addr_make("testvaloper2"); - let not_validator = test_env.api.addr_make("notvaloper"); + let (mut env, validator1) = TestEnv::wrap(setup_test_env(10, 10)); + + let delegator1 = env.api.addr_make("delegator1"); + let delegator2 = env.api.addr_make("delegator2"); + let validator2 = env.api.addr_make("testvaloper2"); + let not_validator = env.api.addr_make("notvaloper"); // init balances - test_env - .router + env.router .bank - .init_balance( - &mut test_env.store, - &delegator1, - vec![coin(260, BONDED_DENOM)], - ) + .init_balance(&mut env.store, &delegator1, vec![coin(260, BONDED_DENOM)]) .unwrap(); - test_env - .router + env.router .bank - .init_balance( - &mut test_env.store, - &delegator2, - vec![coin(150, BONDED_DENOM)], - ) + .init_balance(&mut env.store, &delegator2, vec![coin(150, BONDED_DENOM)]) .unwrap(); // add another validator @@ -2026,34 +1985,28 @@ mod test { Decimal::percent(1), Decimal::percent(1), ); - test_env - .router + env.router .staking - .add_validator( - &test_env.api, - &mut test_env.store, - &test_env.block, - valoper2.clone(), - ) + .add_validator(&env.api, &mut env.store, &env.block, valoper2.clone()) .unwrap(); // query validators let valoper1: ValidatorResponse = query_stake( - &test_env, + &env, StakingQuery::Validator { address: validator1.to_string(), }, ) .unwrap(); let validators: AllValidatorsResponse = - query_stake(&test_env, StakingQuery::AllValidators {}).unwrap(); + query_stake(&env, StakingQuery::AllValidators {}).unwrap(); assert_eq!( validators.validators, [valoper1.validator.unwrap(), valoper2] ); // query non-existent validator let response = query_stake::( - &test_env, + &env, StakingQuery::Validator { address: not_validator.to_string(), }, @@ -2063,12 +2016,12 @@ mod test { // query bonded denom let response: BondedDenomResponse = - query_stake(&test_env, StakingQuery::BondedDenom {}).unwrap(); + query_stake(&env, StakingQuery::BondedDenom {}).unwrap(); assert_eq!(response.denom, BONDED_DENOM); // delegate some tokens with delegator1 and delegator2 execute_stake( - &mut test_env, + &mut env, delegator1.clone(), StakingMsg::Delegate { validator: validator1.to_string(), @@ -2077,7 +2030,7 @@ mod test { ) .unwrap(); execute_stake( - &mut test_env, + &mut env, delegator1.clone(), StakingMsg::Delegate { validator: validator2.to_string(), @@ -2086,7 +2039,7 @@ mod test { ) .unwrap(); execute_stake( - &mut test_env, + &mut env, delegator2.clone(), StakingMsg::Delegate { validator: validator1.to_string(), @@ -2096,7 +2049,7 @@ mod test { .unwrap(); // unstake some again execute_stake( - &mut test_env, + &mut env, delegator1.clone(), StakingMsg::Undelegate { validator: validator1.to_string(), @@ -2105,7 +2058,7 @@ mod test { ) .unwrap(); execute_stake( - &mut test_env, + &mut env, delegator2.clone(), StakingMsg::Undelegate { validator: validator1.to_string(), @@ -2116,7 +2069,7 @@ mod test { // query all delegations let response1: AllDelegationsResponse = query_stake( - &test_env, + &env, StakingQuery::AllDelegations { delegator: delegator1.to_string(), }, @@ -2138,7 +2091,7 @@ mod test { ] ); let response2: DelegationResponse = query_stake( - &test_env, + &env, StakingQuery::Delegation { delegator: delegator2.to_string(), validator: validator1.to_string(), @@ -2159,34 +2112,24 @@ mod test { #[test] fn delegation_queries_unbonding() { - // run all staking queries - let (mut test_env, validator) = TestEnv::wrap(setup_test_env(10, 10)); - let delegator1 = test_env.api.addr_make("delegator1"); - let delegator2 = test_env.api.addr_make("delegator2"); + let (mut env, validator) = TestEnv::wrap(setup_test_env(10, 10)); + + let delegator1 = env.api.addr_make("delegator1"); + let delegator2 = env.api.addr_make("delegator2"); // init balances - test_env - .router + env.router .bank - .init_balance( - &mut test_env.store, - &delegator1, - vec![coin(100, BONDED_DENOM)], - ) + .init_balance(&mut env.store, &delegator1, vec![coin(100, BONDED_DENOM)]) .unwrap(); - test_env - .router + env.router .bank - .init_balance( - &mut test_env.store, - &delegator2, - vec![coin(150, BONDED_DENOM)], - ) + .init_balance(&mut env.store, &delegator2, vec![coin(150, BONDED_DENOM)]) .unwrap(); // delegate some tokens with delegator1 and delegator2 execute_stake( - &mut test_env, + &mut env, delegator1.clone(), StakingMsg::Delegate { validator: validator.to_string(), @@ -2195,7 +2138,7 @@ mod test { ) .unwrap(); execute_stake( - &mut test_env, + &mut env, delegator2.clone(), StakingMsg::Delegate { validator: validator.to_string(), @@ -2205,7 +2148,7 @@ mod test { .unwrap(); // unstake some of delegator1's stake execute_stake( - &mut test_env, + &mut env, delegator1.clone(), StakingMsg::Undelegate { validator: validator.to_string(), @@ -2215,7 +2158,7 @@ mod test { .unwrap(); // unstake all of delegator2's stake execute_stake( - &mut test_env, + &mut env, delegator2.clone(), StakingMsg::Undelegate { validator: validator.to_string(), @@ -2226,7 +2169,7 @@ mod test { // query all delegations let response1: AllDelegationsResponse = query_stake( - &test_env, + &env, StakingQuery::AllDelegations { delegator: delegator1.to_string(), }, @@ -2241,7 +2184,7 @@ mod test { )] ); let response2: DelegationResponse = query_stake( - &test_env, + &env, StakingQuery::Delegation { delegator: delegator2.to_string(), validator: validator.to_string(), @@ -2252,7 +2195,7 @@ mod test { // unstake rest of delegator1's stake in two steps execute_stake( - &mut test_env, + &mut env, delegator1.clone(), StakingMsg::Undelegate { validator: validator.to_string(), @@ -2260,9 +2203,9 @@ mod test { }, ) .unwrap(); - test_env.block.time = test_env.block.time.plus_seconds(10); + env.block.time = env.block.time.plus_seconds(10); execute_stake( - &mut test_env, + &mut env, delegator1.clone(), StakingMsg::Undelegate { validator: validator.to_string(), @@ -2273,7 +2216,7 @@ mod test { // query all delegations again let response1: DelegationResponse = query_stake( - &test_env, + &env, StakingQuery::Delegation { delegator: delegator1.to_string(), validator: validator.to_string(), @@ -2281,7 +2224,7 @@ mod test { ) .unwrap(); let response2: AllDelegationsResponse = query_stake( - &test_env, + &env, StakingQuery::AllDelegations { delegator: delegator1.to_string(), }, @@ -2296,23 +2239,19 @@ mod test { #[test] fn partial_unbonding_reduces_stake() { - let (mut test_env, validator) = TestEnv::wrap(setup_test_env(10, 10)); - let delegator = test_env.api.addr_make("delegator1"); + let (mut env, validator) = TestEnv::wrap(setup_test_env(10, 10)); + + let delegator = env.api.addr_make("delegator1"); // init balance - test_env - .router + env.router .bank - .init_balance( - &mut test_env.store, - &delegator, - vec![coin(100, BONDED_DENOM)], - ) + .init_balance(&mut env.store, &delegator, vec![coin(100, BONDED_DENOM)]) .unwrap(); // delegate all tokens execute_stake( - &mut test_env, + &mut env, delegator.clone(), StakingMsg::Delegate { validator: validator.to_string(), @@ -2322,7 +2261,7 @@ mod test { .unwrap(); // unstake in multiple steps execute_stake( - &mut test_env, + &mut env, delegator.clone(), StakingMsg::Undelegate { validator: validator.to_string(), @@ -2330,9 +2269,9 @@ mod test { }, ) .unwrap(); - test_env.block.time = test_env.block.time.plus_seconds(10); + env.block.time = env.block.time.plus_seconds(10); execute_stake( - &mut test_env, + &mut env, delegator.clone(), StakingMsg::Undelegate { validator: validator.to_string(), @@ -2340,9 +2279,9 @@ mod test { }, ) .unwrap(); - test_env.block.time = test_env.block.time.plus_seconds(10); + env.block.time = env.block.time.plus_seconds(10); execute_stake( - &mut test_env, + &mut env, delegator.clone(), StakingMsg::Undelegate { validator: validator.to_string(), @@ -2352,22 +2291,16 @@ mod test { .unwrap(); // wait for first unbonding to complete (but not the others) and process queue - test_env.block.time = test_env.block.time.plus_seconds(40); - test_env - .router + env.block.time = env.block.time.plus_seconds(40); + env.router .staking - .process_queue( - &test_env.api, - &mut test_env.store, - &test_env.router, - &test_env.block, - ) + .process_queue(&env.api, &mut env.store, &env.router, &env.block) .unwrap(); // query delegations // we now have 0 stake, 50 unbonding and 50 completed unbonding let response1: DelegationResponse = query_stake( - &test_env, + &env, StakingQuery::Delegation { delegator: delegator.to_string(), validator: validator.to_string(), @@ -2375,7 +2308,7 @@ mod test { ) .unwrap(); let response2: AllDelegationsResponse = query_stake( - &test_env, + &env, StakingQuery::AllDelegations { delegator: delegator.to_string(), }, @@ -2385,21 +2318,15 @@ mod test { assert_eq!(response2.delegations, vec![]); // wait for the rest to complete - test_env.block.time = test_env.block.time.plus_seconds(20); - test_env - .router + env.block.time = env.block.time.plus_seconds(20); + env.router .staking - .process_queue( - &test_env.api, - &mut test_env.store, - &test_env.router, - &test_env.block, - ) + .process_queue(&env.api, &mut env.store, &env.router, &env.block) .unwrap(); // query delegations again let response1: DelegationResponse = query_stake( - &test_env, + &env, StakingQuery::Delegation { delegator: delegator.to_string(), validator: validator.to_string(), @@ -2407,7 +2334,7 @@ mod test { ) .unwrap(); let response2: AllDelegationsResponse = query_stake( - &test_env, + &env, StakingQuery::AllDelegations { delegator: delegator.to_string(), }, @@ -2422,24 +2349,19 @@ mod test { #[test] fn delegations_slashed() { - // run all staking queries - let (mut test_env, validator) = TestEnv::wrap(setup_test_env(10, 10)); - let delegator = test_env.api.addr_make("delegator"); + let (mut env, validator) = TestEnv::wrap(setup_test_env(10, 10)); + + let delegator = env.api.addr_make("delegator"); // init balance - test_env - .router + env.router .bank - .init_balance( - &mut test_env.store, - &delegator, - vec![coin(333, BONDED_DENOM)], - ) + .init_balance(&mut env.store, &delegator, vec![coin(333, BONDED_DENOM)]) .unwrap(); // delegate some tokens execute_stake( - &mut test_env, + &mut env, delegator.clone(), StakingMsg::Delegate { validator: validator.to_string(), @@ -2449,7 +2371,7 @@ mod test { .unwrap(); // unstake some execute_stake( - &mut test_env, + &mut env, delegator.clone(), StakingMsg::Undelegate { validator: validator.to_string(), @@ -2459,14 +2381,13 @@ mod test { .unwrap(); // slash validator - test_env - .router + env.router .staking .sudo( - &test_env.api, - &mut test_env.store, - &test_env.router, - &test_env.block, + &env.api, + &mut env.store, + &env.router, + &env.block, StakingSudo::Slash { validator: validator.to_string(), percentage: Decimal::percent(50), @@ -2476,7 +2397,7 @@ mod test { // query all delegations let response1: AllDelegationsResponse = query_stake( - &test_env, + &env, StakingQuery::AllDelegations { delegator: delegator.to_string(), }, @@ -2492,49 +2413,36 @@ mod test { ); // wait until unbonding is complete and check if amount was slashed - test_env.block.time = test_env.block.time.plus_seconds(60); - test_env - .router + env.block.time = env.block.time.plus_seconds(60); + env.router .staking - .process_queue( - &test_env.api, - &mut test_env.store, - &test_env.router, - &test_env.block, - ) + .process_queue(&env.api, &mut env.store, &env.router, &env.block) .unwrap(); - let balance = QuerierWrapper::::new(&test_env.router.querier( - &test_env.api, - &test_env.store, - &test_env.block, - )) - .query_balance(delegator, BONDED_DENOM) - .unwrap(); + let balance = + QuerierWrapper::::new(&env.router.querier(&env.api, &env.store, &env.block)) + .query_balance(delegator, BONDED_DENOM) + .unwrap(); assert_eq!(balance.amount.u128(), 55); } #[test] fn rewards_initial_wait() { - let (mut test_env, validator) = TestEnv::wrap(setup_test_env(10, 0)); - let delegator = test_env.api.addr_make("delegator"); + let (mut env, validator) = TestEnv::wrap(setup_test_env(10, 0)); + + let delegator = env.api.addr_make("delegator"); // init balance - test_env - .router + env.router .bank - .init_balance( - &mut test_env.store, - &delegator, - vec![coin(100, BONDED_DENOM)], - ) + .init_balance(&mut env.store, &delegator, vec![coin(100, BONDED_DENOM)]) .unwrap(); // wait a year before staking - test_env.block.time = test_env.block.time.plus_seconds(YEAR); + env.block.time = env.block.time.plus_seconds(YEAR); // delegate some tokens execute_stake( - &mut test_env, + &mut env, delegator.clone(), StakingMsg::Delegate { validator: validator.to_string(), @@ -2544,11 +2452,11 @@ mod test { .unwrap(); // wait another year - test_env.block.time = test_env.block.time.plus_seconds(YEAR); + env.block.time = env.block.time.plus_seconds(YEAR); // query rewards let response: DelegationResponse = query_stake( - &test_env, + &env, StakingQuery::Delegation { delegator: delegator.to_string(), validator: validator.to_string(), From a6c70631ec26a7c0bc98a71bbf327163b9068ab8 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Thu, 13 Jun 2024 17:10:38 +0200 Subject: [PATCH 212/250] Unified variable names in tests. --- src/staking.rs | 464 +++++++++++++++++++++++++++++-------------------- 1 file changed, 278 insertions(+), 186 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 157dd6a0..e259511d 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -15,7 +15,7 @@ use serde::{Deserialize, Serialize}; use std::collections::{BTreeSet, VecDeque}; /// Default denominator of the staking token. -pub const BONDED_DENOM: &str = "TOKEN"; +const BONDED_DENOM: &str = "TOKEN"; /// A structure containing some general staking parameters. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] @@ -1075,7 +1075,7 @@ mod test { let mut store = MockStorage::new(); let block = mock_env().block; - let validator_addr = api.addr_make("testvaloper1"); + let validator_addr = api.addr_make("validator1"); router .staking @@ -1461,19 +1461,56 @@ mod test { store: MockStorage, router: BasicRouter, block: BlockInfo, + validator_addr_1: Addr, + validator_addr_2: Addr, + delegator_addr_1: Addr, + delegator_addr_2: Addr, + user_addr_1: Addr, } impl TestEnv { - fn wrap(tuple: (MockApi, MockStorage, BasicRouter, BlockInfo, Addr)) -> (Self, Addr) { - ( - Self { - api: tuple.0, - store: tuple.1, - router: tuple.2, - block: tuple.3, - }, - tuple.4, - ) + fn wrap(tuple: (MockApi, MockStorage, BasicRouter, BlockInfo, Addr)) -> Self { + let api = tuple.0; + let validator_addr_2 = api.addr_make("validator2"); + let delegator_addr_1 = api.addr_make("delegator1"); + let delegator_addr_2 = api.addr_make("delegator2"); + let user_addr_1 = api.addr_make("user1"); + Self { + api: tuple.0, + store: tuple.1, + router: tuple.2, + block: tuple.3, + validator_addr_1: tuple.4, + validator_addr_2, + delegator_addr_1, + delegator_addr_2, + user_addr_1, + } + } + + #[inline(always)] + fn validator_addr_1(&self) -> Addr { + self.validator_addr_1.clone() + } + + #[inline(always)] + fn validator_addr_2(&self) -> Addr { + self.validator_addr_2.clone() + } + + #[inline(always)] + fn delegator_addr_1(&self) -> Addr { + self.delegator_addr_1.clone() + } + + #[inline(always)] + fn delegator_addr_2(&self) -> Addr { + self.delegator_addr_2.clone() + } + + #[inline(always)] + fn user_addr_1(&self) -> Addr { + self.user_addr_1.clone() } } @@ -1543,19 +1580,24 @@ mod test { #[test] fn execute() { - let (mut env, validator1) = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(setup_test_env(10, 10)); - let delegator1 = env.api.addr_make("delegator1"); - let reward_receiver = env.api.addr_make("rewardreceiver"); + let validator_addr_1 = env.validator_addr_1(); + let validator_addr_2 = env.validator_addr_2(); + let delegator_addr_1 = env.delegator_addr_2(); + let reward_receiver_addr = env.user_addr_1(); // fund delegator1 account env.router .bank - .init_balance(&mut env.store, &delegator1, vec![coin(1000, BONDED_DENOM)]) + .init_balance( + &mut env.store, + &delegator_addr_1, + vec![coin(1000, BONDED_DENOM)], + ) .unwrap(); // add second validator - let validator2 = env.api.addr_make("validator2"); env.router .staking .add_validator( @@ -1563,7 +1605,7 @@ mod test { &mut env.store, &env.block, Validator::new( - validator2.to_string(), + validator_addr_2.to_string(), Decimal::zero(), Decimal::percent(20), Decimal::percent(1), @@ -1574,16 +1616,16 @@ mod test { // delegate 100 tokens to validator1 execute_stake( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator1.to_string(), + validator: validator_addr_1.to_string(), amount: coin(100, BONDED_DENOM), }, ) .unwrap(); // should now have 100 tokens less - assert_balances(&env, vec![(delegator1.clone(), 900)]); + assert_balances(&env, vec![(delegator_addr_1.clone(), 900)]); // wait a year env.block.time = env.block.time.plus_seconds(YEAR); @@ -1591,9 +1633,9 @@ mod test { // change the withdrawal address execute_distr( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), DistributionMsg::SetWithdrawAddress { - address: reward_receiver.to_string(), + address: reward_receiver_addr.to_string(), }, ) .unwrap(); @@ -1601,9 +1643,9 @@ mod test { // withdraw rewards execute_distr( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), DistributionMsg::WithdrawDelegatorReward { - validator: validator1.to_string(), + validator: validator_addr_1.to_string(), }, ) .unwrap(); @@ -1612,36 +1654,36 @@ mod test { assert_balances( &env, // one year, 10%apr, 10% commission, 100 tokens staked - vec![(reward_receiver, 100 / 10 * 9 / 10)], + vec![(reward_receiver_addr, 100 / 10 * 9 / 10)], ); // redelegate to validator2 execute_stake( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), StakingMsg::Redelegate { - src_validator: validator1.to_string(), - dst_validator: validator2.to_string(), + src_validator: validator_addr_1.to_string(), + dst_validator: validator_addr_2.to_string(), amount: coin(100, BONDED_DENOM), }, ) .unwrap(); // should have same amount as before (rewards receiver received rewards). - assert_balances(&env, vec![(delegator1.clone(), 900)]); + assert_balances(&env, vec![(delegator_addr_1.clone(), 900)]); let delegations: AllDelegationsResponse = query_stake( &env, StakingQuery::AllDelegations { - delegator: delegator1.to_string(), + delegator: delegator_addr_1.to_string(), }, ) .unwrap(); assert_eq!( delegations.delegations, [Delegation::new( - delegator1.clone(), - validator2.to_string(), + delegator_addr_1.clone(), + validator_addr_2.to_string(), coin(100, BONDED_DENOM), )] ); @@ -1649,9 +1691,9 @@ mod test { // undelegate all tokens execute_stake( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator2.to_string(), + validator: validator_addr_2.to_string(), amount: coin(100, BONDED_DENOM), }, ) @@ -1667,27 +1709,28 @@ mod test { .unwrap(); // check bank balance - assert_balances(&env, vec![(delegator1.clone(), 1000)]); + assert_balances(&env, vec![(delegator_addr_1.clone(), 1000)]); } #[test] fn can_set_withdraw_address() { - let (mut env, validator) = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(setup_test_env(10, 10)); - let delegator = env.api.addr_make("delegator"); - let reward_receiver = env.api.addr_make("rewardreceiver"); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); + let reward_receiver_addr = env.user_addr_1(); env.router .bank - .init_balance(&mut env.store, &delegator, coins(100, BONDED_DENOM)) + .init_balance(&mut env.store, &delegator_addr_1, coins(100, BONDED_DENOM)) .unwrap(); // Stake 100 tokens to the validator. execute_stake( &mut env, - delegator.clone(), + delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(100, BONDED_DENOM), }, ) @@ -1696,9 +1739,9 @@ mod test { // Change rewards receiver. execute_distr( &mut env, - delegator.clone(), + delegator_addr_1.clone(), DistributionMsg::SetWithdrawAddress { - address: reward_receiver.to_string(), + address: reward_receiver_addr.to_string(), }, ) .unwrap(); @@ -1709,9 +1752,9 @@ mod test { // Withdraw rewards to reward receiver. execute_distr( &mut env, - delegator.clone(), + delegator_addr_1.clone(), DistributionMsg::WithdrawDelegatorReward { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), }, ) .unwrap(); @@ -1719,9 +1762,9 @@ mod test { // Change reward receiver back to delegator. execute_distr( &mut env, - delegator.clone(), + delegator_addr_1.clone(), DistributionMsg::SetWithdrawAddress { - address: delegator.to_string(), + address: delegator_addr_1.to_string(), }, ) .unwrap(); @@ -1732,9 +1775,9 @@ mod test { // Withdraw rewards to delegator. execute_distr( &mut env, - delegator.clone(), + delegator_addr_1.clone(), DistributionMsg::WithdrawDelegatorReward { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), }, ) .unwrap(); @@ -1744,28 +1787,37 @@ mod test { assert_balances( &env, - vec![(reward_receiver, rewards_yr), (delegator, rewards_yr)], + vec![ + (reward_receiver_addr, rewards_yr), + (delegator_addr_1, rewards_yr), + ], ); } #[test] fn cannot_steal() { - let (mut env, validator1) = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(setup_test_env(10, 10)); - let delegator1 = env.api.addr_make("delegator1"); + let validator_addr_1 = env.validator_addr_1(); + let validator_addr_2 = env.validator_addr_2(); + let delegator_addr_1 = env.delegator_addr_1(); - // fund delegator1 account + // fund delegator account env.router .bank - .init_balance(&mut env.store, &delegator1, vec![coin(100, BONDED_DENOM)]) + .init_balance( + &mut env.store, + &delegator_addr_1, + vec![coin(100, BONDED_DENOM)], + ) .unwrap(); // delegate 100 tokens to validator1 execute_stake( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator1.to_string(), + validator: validator_addr_1.to_string(), amount: coin(100, BONDED_DENOM), }, ) @@ -1774,9 +1826,9 @@ mod test { // undelegate more tokens than we have let e = execute_stake( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator1.to_string(), + validator: validator_addr_1.to_string(), amount: coin(200, BONDED_DENOM), }, ) @@ -1785,7 +1837,6 @@ mod test { assert_eq!(e.to_string(), "invalid shares amount"); // add second validator - let validator2 = env.api.addr_make("validator2"); env.router .staking .add_validator( @@ -1793,7 +1844,7 @@ mod test { &mut env.store, &env.block, Validator::new( - validator2.to_string(), + validator_addr_2.to_string(), Decimal::zero(), Decimal::percent(20), Decimal::percent(1), @@ -1804,10 +1855,10 @@ mod test { // redelegate more tokens than we have let e = execute_stake( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), StakingMsg::Redelegate { - src_validator: validator1.to_string(), - dst_validator: validator2.to_string(), + src_validator: validator_addr_1.to_string(), + dst_validator: validator_addr_2.to_string(), amount: coin(200, BONDED_DENOM), }, ) @@ -1817,9 +1868,9 @@ mod test { // undelegate from non-existing delegation let e = execute_stake( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator2.to_string(), + validator: validator_addr_2.to_string(), amount: coin(100, BONDED_DENOM), }, ) @@ -1832,22 +1883,23 @@ mod test { #[test] fn denom_validation() { - let (mut env, validator_addr) = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(setup_test_env(10, 10)); - let delegator_addr = env.api.addr_make("delegator"); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); - // fund delegator1 account + // fund delegator account env.router .bank - .init_balance(&mut env.store, &delegator_addr, vec![coin(100, "FAKE")]) + .init_balance(&mut env.store, &delegator_addr_1, vec![coin(100, "FAKE")]) .unwrap(); // try to delegate 100 to validator let e = execute_stake( &mut env, - delegator_addr.clone(), + delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator_addr.to_string(), + validator: validator_addr_1.to_string(), amount: coin(100, "FAKE"), }, ) @@ -1861,18 +1913,18 @@ mod test { #[test] fn cannot_slash_nonexistent() { - let (mut env, _) = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(setup_test_env(10, 10)); - let delegator = env.api.addr_make("delegator"); - let non_existing_validator = env.api.addr_make("nonexistingvaloper"); + let non_existing_validator_addr = env.validator_addr_2(); + let delegator_addr_1 = env.delegator_addr_1(); - // fund delegator1 account + // fund delegator account env.router .bank - .init_balance(&mut env.store, &delegator, vec![coin(100, "FAKE")]) + .init_balance(&mut env.store, &delegator_addr_1, vec![coin(100, "FAKE")]) .unwrap(); - // try to delegate 100 to validator1 + // try to delegate 100 to non existing validator let e = env .router .staking @@ -1882,33 +1934,38 @@ mod test { &env.router, &env.block, StakingSudo::Slash { - validator: non_existing_validator.to_string(), + validator: non_existing_validator_addr.to_string(), percentage: Decimal::percent(50), }, ) .unwrap_err(); + assert_eq!(e.to_string(), "validator does not exist"); } #[test] fn non_existent_validator() { - let (mut env, _) = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(setup_test_env(10, 10)); - let delegator = env.api.addr_make("delegator1"); - let validator = env.api.addr_make("testvaloper2"); + let non_existing_validator_addr = env.validator_addr_2(); + let delegator_addr_1 = env.delegator_addr_1(); // init balances env.router .bank - .init_balance(&mut env.store, &delegator, vec![coin(100, BONDED_DENOM)]) + .init_balance( + &mut env.store, + &delegator_addr_1, + vec![coin(100, BONDED_DENOM)], + ) .unwrap(); // try to delegate let err = execute_stake( &mut env, - delegator.clone(), + delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator.to_string(), + validator: non_existing_validator_addr.to_string(), amount: coin(100, BONDED_DENOM), }, ) @@ -1918,9 +1975,9 @@ mod test { // try to undelegate let err = execute_stake( &mut env, - delegator.clone(), + delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator.to_string(), + validator: non_existing_validator_addr.to_string(), amount: coin(100, BONDED_DENOM), }, ) @@ -1930,16 +1987,17 @@ mod test { #[test] fn zero_staking_forbidden() { - let (mut env, validator) = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(setup_test_env(10, 10)); - let delegator_addr = env.api.addr_make("delegator"); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); // delegate 0 let err = execute_stake( &mut env, - delegator_addr.clone(), + delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(0, BONDED_DENOM), }, ) @@ -1949,9 +2007,9 @@ mod test { // undelegate 0 let err = execute_stake( &mut env, - delegator_addr, + delegator_addr_1, StakingMsg::Undelegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(0, BONDED_DENOM), }, ) @@ -1961,26 +2019,35 @@ mod test { #[test] fn query_staking() { - let (mut env, validator1) = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(setup_test_env(10, 10)); - let delegator1 = env.api.addr_make("delegator1"); - let delegator2 = env.api.addr_make("delegator2"); - let validator2 = env.api.addr_make("testvaloper2"); - let not_validator = env.api.addr_make("notvaloper"); + let validator_addr_1 = env.validator_addr_1(); + let validator_addr_2 = env.validator_addr_2(); + let delegator_addr_1 = env.delegator_addr_1(); + let delegator_addr_2 = env.delegator_addr_2(); + let not_validator_addr = env.user_addr_1(); // init balances env.router .bank - .init_balance(&mut env.store, &delegator1, vec![coin(260, BONDED_DENOM)]) + .init_balance( + &mut env.store, + &delegator_addr_1, + vec![coin(260, BONDED_DENOM)], + ) .unwrap(); env.router .bank - .init_balance(&mut env.store, &delegator2, vec![coin(150, BONDED_DENOM)]) + .init_balance( + &mut env.store, + &delegator_addr_2, + vec![coin(150, BONDED_DENOM)], + ) .unwrap(); // add another validator let valoper2 = Validator::new( - validator2.to_string(), + validator_addr_2.to_string(), Decimal::percent(0), Decimal::percent(1), Decimal::percent(1), @@ -1994,7 +2061,7 @@ mod test { let valoper1: ValidatorResponse = query_stake( &env, StakingQuery::Validator { - address: validator1.to_string(), + address: validator_addr_1.to_string(), }, ) .unwrap(); @@ -2008,7 +2075,7 @@ mod test { let response = query_stake::( &env, StakingQuery::Validator { - address: not_validator.to_string(), + address: not_validator_addr.to_string(), }, ) .unwrap(); @@ -2022,27 +2089,27 @@ mod test { // delegate some tokens with delegator1 and delegator2 execute_stake( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator1.to_string(), + validator: validator_addr_1.to_string(), amount: coin(100, BONDED_DENOM), }, ) .unwrap(); execute_stake( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator2.to_string(), + validator: validator_addr_2.to_string(), amount: coin(160, BONDED_DENOM), }, ) .unwrap(); execute_stake( &mut env, - delegator2.clone(), + delegator_addr_2.clone(), StakingMsg::Delegate { - validator: validator1.to_string(), + validator: validator_addr_1.to_string(), amount: coin(150, BONDED_DENOM), }, ) @@ -2050,18 +2117,18 @@ mod test { // unstake some again execute_stake( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator1.to_string(), + validator: validator_addr_1.to_string(), amount: coin(50, BONDED_DENOM), }, ) .unwrap(); execute_stake( &mut env, - delegator2.clone(), + delegator_addr_2.clone(), StakingMsg::Undelegate { - validator: validator1.to_string(), + validator: validator_addr_1.to_string(), amount: coin(50, BONDED_DENOM), }, ) @@ -2071,7 +2138,7 @@ mod test { let response1: AllDelegationsResponse = query_stake( &env, StakingQuery::AllDelegations { - delegator: delegator1.to_string(), + delegator: delegator_addr_1.to_string(), }, ) .unwrap(); @@ -2079,13 +2146,13 @@ mod test { response1.delegations, vec![ Delegation::new( - delegator1.clone(), - validator1.to_string(), + delegator_addr_1.clone(), + validator_addr_1.to_string(), coin(50, BONDED_DENOM), ), Delegation::new( - delegator1.clone(), - validator2.to_string(), + delegator_addr_1.clone(), + validator_addr_2.to_string(), coin(160, BONDED_DENOM), ), ] @@ -2093,16 +2160,16 @@ mod test { let response2: DelegationResponse = query_stake( &env, StakingQuery::Delegation { - delegator: delegator2.to_string(), - validator: validator1.to_string(), + delegator: delegator_addr_2.to_string(), + validator: validator_addr_1.to_string(), }, ) .unwrap(); assert_eq!( response2.delegation.unwrap(), FullDelegation::new( - delegator2.clone(), - validator1.to_string(), + delegator_addr_2.clone(), + validator_addr_1.to_string(), coin(100, BONDED_DENOM), coin(100, BONDED_DENOM), vec![], @@ -2112,36 +2179,45 @@ mod test { #[test] fn delegation_queries_unbonding() { - let (mut env, validator) = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(setup_test_env(10, 10)); - let delegator1 = env.api.addr_make("delegator1"); - let delegator2 = env.api.addr_make("delegator2"); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); + let delegator_addr_2 = env.delegator_addr_2(); // init balances env.router .bank - .init_balance(&mut env.store, &delegator1, vec![coin(100, BONDED_DENOM)]) + .init_balance( + &mut env.store, + &delegator_addr_1, + vec![coin(100, BONDED_DENOM)], + ) .unwrap(); env.router .bank - .init_balance(&mut env.store, &delegator2, vec![coin(150, BONDED_DENOM)]) + .init_balance( + &mut env.store, + &delegator_addr_2, + vec![coin(150, BONDED_DENOM)], + ) .unwrap(); // delegate some tokens with delegator1 and delegator2 execute_stake( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(100, BONDED_DENOM), }, ) .unwrap(); execute_stake( &mut env, - delegator2.clone(), + delegator_addr_2.clone(), StakingMsg::Delegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(150, BONDED_DENOM), }, ) @@ -2149,9 +2225,9 @@ mod test { // unstake some of delegator1's stake execute_stake( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(50, BONDED_DENOM), }, ) @@ -2159,9 +2235,9 @@ mod test { // unstake all of delegator2's stake execute_stake( &mut env, - delegator2.clone(), + delegator_addr_2.clone(), StakingMsg::Undelegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(150, BONDED_DENOM), }, ) @@ -2171,23 +2247,23 @@ mod test { let response1: AllDelegationsResponse = query_stake( &env, StakingQuery::AllDelegations { - delegator: delegator1.to_string(), + delegator: delegator_addr_1.to_string(), }, ) .unwrap(); assert_eq!( response1.delegations, vec![Delegation::new( - delegator1.clone(), - validator.to_string(), + delegator_addr_1.clone(), + validator_addr_1.to_string(), coin(50, BONDED_DENOM), )] ); let response2: DelegationResponse = query_stake( &env, StakingQuery::Delegation { - delegator: delegator2.to_string(), - validator: validator.to_string(), + delegator: delegator_addr_2.to_string(), + validator: validator_addr_1.to_string(), }, ) .unwrap(); @@ -2196,9 +2272,9 @@ mod test { // unstake rest of delegator1's stake in two steps execute_stake( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(25, BONDED_DENOM), }, ) @@ -2206,9 +2282,9 @@ mod test { env.block.time = env.block.time.plus_seconds(10); execute_stake( &mut env, - delegator1.clone(), + delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(25, BONDED_DENOM), }, ) @@ -2218,15 +2294,15 @@ mod test { let response1: DelegationResponse = query_stake( &env, StakingQuery::Delegation { - delegator: delegator1.to_string(), - validator: validator.to_string(), + delegator: delegator_addr_1.to_string(), + validator: validator_addr_1.to_string(), }, ) .unwrap(); let response2: AllDelegationsResponse = query_stake( &env, StakingQuery::AllDelegations { - delegator: delegator1.to_string(), + delegator: delegator_addr_1.to_string(), }, ) .unwrap(); @@ -2239,22 +2315,27 @@ mod test { #[test] fn partial_unbonding_reduces_stake() { - let (mut env, validator) = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(setup_test_env(10, 10)); - let delegator = env.api.addr_make("delegator1"); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); // init balance env.router .bank - .init_balance(&mut env.store, &delegator, vec![coin(100, BONDED_DENOM)]) + .init_balance( + &mut env.store, + &delegator_addr_1, + vec![coin(100, BONDED_DENOM)], + ) .unwrap(); // delegate all tokens execute_stake( &mut env, - delegator.clone(), + delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(100, BONDED_DENOM), }, ) @@ -2262,9 +2343,9 @@ mod test { // unstake in multiple steps execute_stake( &mut env, - delegator.clone(), + delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(50, BONDED_DENOM), }, ) @@ -2272,9 +2353,9 @@ mod test { env.block.time = env.block.time.plus_seconds(10); execute_stake( &mut env, - delegator.clone(), + delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(30, BONDED_DENOM), }, ) @@ -2282,9 +2363,9 @@ mod test { env.block.time = env.block.time.plus_seconds(10); execute_stake( &mut env, - delegator.clone(), + delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(20, BONDED_DENOM), }, ) @@ -2302,15 +2383,15 @@ mod test { let response1: DelegationResponse = query_stake( &env, StakingQuery::Delegation { - delegator: delegator.to_string(), - validator: validator.to_string(), + delegator: delegator_addr_1.to_string(), + validator: validator_addr_1.to_string(), }, ) .unwrap(); let response2: AllDelegationsResponse = query_stake( &env, StakingQuery::AllDelegations { - delegator: delegator.to_string(), + delegator: delegator_addr_1.to_string(), }, ) .unwrap(); @@ -2328,15 +2409,15 @@ mod test { let response1: DelegationResponse = query_stake( &env, StakingQuery::Delegation { - delegator: delegator.to_string(), - validator: validator.to_string(), + delegator: delegator_addr_1.to_string(), + validator: validator_addr_1.to_string(), }, ) .unwrap(); let response2: AllDelegationsResponse = query_stake( &env, StakingQuery::AllDelegations { - delegator: delegator.to_string(), + delegator: delegator_addr_1.to_string(), }, ) .unwrap(); @@ -2349,22 +2430,27 @@ mod test { #[test] fn delegations_slashed() { - let (mut env, validator) = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(setup_test_env(10, 10)); - let delegator = env.api.addr_make("delegator"); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); // init balance env.router .bank - .init_balance(&mut env.store, &delegator, vec![coin(333, BONDED_DENOM)]) + .init_balance( + &mut env.store, + &delegator_addr_1, + vec![coin(333, BONDED_DENOM)], + ) .unwrap(); // delegate some tokens execute_stake( &mut env, - delegator.clone(), + delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(333, BONDED_DENOM), }, ) @@ -2372,9 +2458,9 @@ mod test { // unstake some execute_stake( &mut env, - delegator.clone(), + delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(111, BONDED_DENOM), }, ) @@ -2389,7 +2475,7 @@ mod test { &env.router, &env.block, StakingSudo::Slash { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), percentage: Decimal::percent(50), }, ) @@ -2399,15 +2485,15 @@ mod test { let response1: AllDelegationsResponse = query_stake( &env, StakingQuery::AllDelegations { - delegator: delegator.to_string(), + delegator: delegator_addr_1.to_string(), }, ) .unwrap(); assert_eq!( response1.delegations[0], Delegation::new( - delegator.clone(), - validator.to_string(), + delegator_addr_1.clone(), + validator_addr_1.to_string(), coin(111, BONDED_DENOM), ) ); @@ -2420,32 +2506,37 @@ mod test { .unwrap(); let balance = QuerierWrapper::::new(&env.router.querier(&env.api, &env.store, &env.block)) - .query_balance(delegator, BONDED_DENOM) + .query_balance(delegator_addr_1, BONDED_DENOM) .unwrap(); assert_eq!(balance.amount.u128(), 55); } #[test] fn rewards_initial_wait() { - let (mut env, validator) = TestEnv::wrap(setup_test_env(10, 0)); + let mut env = TestEnv::wrap(setup_test_env(10, 0)); - let delegator = env.api.addr_make("delegator"); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); - // init balance + // initialize balances for delegator env.router .bank - .init_balance(&mut env.store, &delegator, vec![coin(100, BONDED_DENOM)]) + .init_balance( + &mut env.store, + &delegator_addr_1, + vec![coin(100, BONDED_DENOM)], + ) .unwrap(); - // wait a year before staking + // wait one year before staking env.block.time = env.block.time.plus_seconds(YEAR); - // delegate some tokens + // stake (delegate) some tokens to validator execute_stake( &mut env, - delegator.clone(), + delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), amount: coin(100, BONDED_DENOM), }, ) @@ -2458,11 +2549,12 @@ mod test { let response: DelegationResponse = query_stake( &env, StakingQuery::Delegation { - delegator: delegator.to_string(), - validator: validator.to_string(), + delegator: delegator_addr_1.to_string(), + validator: validator_addr_1.to_string(), }, ) .unwrap(); + assert_eq!( response.delegation.unwrap().accumulated_rewards, vec![coin(10, BONDED_DENOM)] // 10% of 100 From baf1d23d496ac491e046a9a95016d4b711efb87e Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 14 Jun 2024 10:45:02 +0200 Subject: [PATCH 213/250] Replaced remaining year calculations with a constant. --- Cargo.lock | 4 ++-- src/staking.rs | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 66622ae9..416b5955 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -526,9 +526,9 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" diff --git a/src/staking.rs b/src/staking.rs index e259511d..727df2b0 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -17,6 +17,9 @@ use std::collections::{BTreeSet, VecDeque}; /// Default denominator of the staking token. const BONDED_DENOM: &str = "TOKEN"; +/// One year expressed in seconds. +const YEAR: u64 = 60 * 60 * 24 * 365; + /// A structure containing some general staking parameters. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct StakingInfo { @@ -25,7 +28,6 @@ pub struct StakingInfo { /// Time between unbonding and receiving tokens back (in seconds). pub unbonding_time: u64, /// Annual percentage rate (interest rate and any additional fees associated with bonding). - /// 1 year = 60 * 60 * 24 * 365 seconds. pub apr: Decimal, } @@ -276,7 +278,7 @@ impl StakeKeeper { let reward = Decimal::from_ratio(stake, 1u128) * interest_rate * Decimal::from_ratio(time_diff, 1u128) - / Decimal::from_ratio(60u128 * 60 * 24 * 365, 1u128); + / Decimal::from_ratio(YEAR, 1u128); let commission = reward * validator_commission; reward - commission @@ -1038,9 +1040,6 @@ mod test { BalanceResponse, BankQuery, }; - /// One year expressed in seconds. - const YEAR: u64 = 60 * 60 * 24 * 365; - /// Type alias for default build of [Router], to make its reference in typical test scenario. type BasicRouter = Router< BankKeeper, @@ -1747,7 +1746,7 @@ mod test { .unwrap(); // A year passes. - env.block.time = env.block.time.plus_seconds(60 * 60 * 24 * 365); + env.block.time = env.block.time.plus_seconds(YEAR); // Withdraw rewards to reward receiver. execute_distr( @@ -1770,7 +1769,7 @@ mod test { .unwrap(); // Another year passes. - env.block.time = env.block.time.plus_seconds(60 * 60 * 24 * 365); + env.block.time = env.block.time.plus_seconds(YEAR); // Withdraw rewards to delegator. execute_distr( From 95f2a89db2c95a3335d42b133e5f90928b3f56a1 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 14 Jun 2024 13:20:01 +0200 Subject: [PATCH 214/250] Refactored test env. --- src/staking.rs | 313 ++++++++++++++++++++++++------------------------- 1 file changed, 152 insertions(+), 161 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 727df2b0..8390c755 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1065,42 +1065,126 @@ mod test { } } - fn setup_test_env( - apr: u64, - validator_commission: u64, - ) -> (MockApi, MockStorage, BasicRouter, BlockInfo, Addr) { - let api = MockApi::default(); - let router = mock_router(); - let mut store = MockStorage::new(); - let block = mock_env().block; + type TestTuple = (MockApi, MockStorage, BasicRouter, BlockInfo, Addr, Addr); + + // shortens tests a bit + struct TestEnv { + api: MockApi, + store: MockStorage, + router: BasicRouter, + block: BlockInfo, + validator_addr_1: Addr, + validator_addr_2: Addr, + validator_addr_3: Addr, + delegator_addr_1: Addr, + delegator_addr_2: Addr, + user_addr_1: Addr, + } - let validator_addr = api.addr_make("validator1"); + impl TestEnv { + fn setup(apr: u64, validator1: (u64, u64, u64), validator2: (u64, u64, u64)) -> TestTuple { + let api = MockApi::default(); + let router = mock_router(); + let mut store = MockStorage::new(); + let block = mock_env().block; - router - .staking - .setup( - &mut store, - StakingInfo { - bonded_denom: BONDED_DENOM.to_string(), - unbonding_time: 60, - apr: Decimal::percent(apr), - }, + let validator_addr_1 = api.addr_make("validator1"); + let validator_addr_2 = api.addr_make("validator2"); + + router + .staking + .setup( + &mut store, + StakingInfo { + bonded_denom: BONDED_DENOM.to_string(), + unbonding_time: 60, + apr: Decimal::percent(apr), + }, + ) + .unwrap(); + + // add first validator + let valoper1 = Validator::new( + validator_addr_1.to_string(), + Decimal::percent(validator1.0), + Decimal::percent(validator1.1), + Decimal::percent(validator1.2), + ); + router + .staking + .add_validator(&api, &mut store, &block, valoper1) + .unwrap(); + + // add second validator + let valoper2 = Validator::new( + validator_addr_2.to_string(), + Decimal::percent(validator2.0), + Decimal::percent(validator2.1), + Decimal::percent(validator2.2), + ); + router + .staking + .add_validator(&api, &mut store, &block, valoper2) + .unwrap(); + + ( + api, + store, + router, + block, + validator_addr_1, + validator_addr_2, ) - .unwrap(); + } - // add validator - let valoper1 = Validator::new( - validator_addr.to_string(), - Decimal::percent(validator_commission), - Decimal::percent(100), - Decimal::percent(1), - ); - router - .staking - .add_validator(&api, &mut store, &block, valoper1) - .unwrap(); + fn wrap(tuple: TestTuple) -> Self { + let api = tuple.0; + Self { + api, + store: tuple.1, + router: tuple.2, + block: tuple.3, + validator_addr_1: tuple.4, + validator_addr_2: tuple.5, + validator_addr_3: api.addr_make("validator3"), + delegator_addr_1: api.addr_make("delegator1"), + delegator_addr_2: api.addr_make("delegator2"), + user_addr_1: api.addr_make("user1"), + } + } + + /// Returns an address of EXISTING validator no. 1. + #[inline(always)] + fn validator_addr_1(&self) -> Addr { + self.validator_addr_1.clone() + } + + /// Returns an address of EXISTING validator no. 2. + #[inline(always)] + fn validator_addr_2(&self) -> Addr { + self.validator_addr_2.clone() + } - (api, store, router, block, validator_addr) + /// Returns an address of NON-EXISTING validator no. 3. + #[inline(always)] + fn validator_addr_3(&self) -> Addr { + self.validator_addr_3.clone() + } + + #[inline(always)] + fn delegator_addr_1(&self) -> Addr { + self.delegator_addr_1.clone() + } + + #[inline(always)] + fn delegator_addr_2(&self) -> Addr { + self.delegator_addr_2.clone() + } + + #[inline(always)] + fn user_addr_1(&self) -> Addr { + self.user_addr_1.clone() + } } #[test] @@ -1235,7 +1319,8 @@ mod test { #[test] fn rewards_work_for_single_delegator() { - let (api, mut store, router, mut block, validator_addr) = setup_test_env(10, 10); + let (api, mut store, router, mut block, validator_addr, _) = + TestEnv::setup(10, (10, 100, 1), (10, 100, 1)); let stake = &router.staking; let distr = &router.distribution; let delegator_addr = api.addr_make("delegator"); @@ -1296,7 +1381,8 @@ mod test { #[test] fn rewards_work_for_multiple_delegators() { - let (api, mut store, router, mut block, validator) = setup_test_env(10, 10); + let (api, mut store, router, mut block, validator, _) = + TestEnv::setup(10, (10, 100, 1), (10, 100, 1)); let stake = &router.staking; let distr = &router.distribution; let bank = &router.bank; @@ -1449,70 +1535,10 @@ mod test { } mod msg { + use super::*; use cosmwasm_std::{coins, QuerierWrapper}; use serde::de::DeserializeOwned; - use super::*; - - // shortens tests a bit - struct TestEnv { - api: MockApi, - store: MockStorage, - router: BasicRouter, - block: BlockInfo, - validator_addr_1: Addr, - validator_addr_2: Addr, - delegator_addr_1: Addr, - delegator_addr_2: Addr, - user_addr_1: Addr, - } - - impl TestEnv { - fn wrap(tuple: (MockApi, MockStorage, BasicRouter, BlockInfo, Addr)) -> Self { - let api = tuple.0; - let validator_addr_2 = api.addr_make("validator2"); - let delegator_addr_1 = api.addr_make("delegator1"); - let delegator_addr_2 = api.addr_make("delegator2"); - let user_addr_1 = api.addr_make("user1"); - Self { - api: tuple.0, - store: tuple.1, - router: tuple.2, - block: tuple.3, - validator_addr_1: tuple.4, - validator_addr_2, - delegator_addr_1, - delegator_addr_2, - user_addr_1, - } - } - - #[inline(always)] - fn validator_addr_1(&self) -> Addr { - self.validator_addr_1.clone() - } - - #[inline(always)] - fn validator_addr_2(&self) -> Addr { - self.validator_addr_2.clone() - } - - #[inline(always)] - fn delegator_addr_1(&self) -> Addr { - self.delegator_addr_1.clone() - } - - #[inline(always)] - fn delegator_addr_2(&self) -> Addr { - self.delegator_addr_2.clone() - } - - #[inline(always)] - fn user_addr_1(&self) -> Addr { - self.user_addr_1.clone() - } - } - fn execute_stake( env: &mut TestEnv, sender: Addr, @@ -1579,14 +1605,14 @@ mod test { #[test] fn execute() { - let mut env = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (0, 20, 1))); let validator_addr_1 = env.validator_addr_1(); let validator_addr_2 = env.validator_addr_2(); let delegator_addr_1 = env.delegator_addr_2(); let reward_receiver_addr = env.user_addr_1(); - // fund delegator1 account + // initialize delegator account env.router .bank .init_balance( @@ -1596,23 +1622,7 @@ mod test { ) .unwrap(); - // add second validator - env.router - .staking - .add_validator( - &env.api, - &mut env.store, - &env.block, - Validator::new( - validator_addr_2.to_string(), - Decimal::zero(), - Decimal::percent(20), - Decimal::percent(1), - ), - ) - .unwrap(); - - // delegate 100 tokens to validator1 + // delegate 100 tokens to validator 1 execute_stake( &mut env, delegator_addr_1.clone(), @@ -1649,14 +1659,14 @@ mod test { ) .unwrap(); - // withdrawal address received rewards. + // withdrawal address received rewards assert_balances( &env, // one year, 10%apr, 10% commission, 100 tokens staked vec![(reward_receiver_addr, 100 / 10 * 9 / 10)], ); - // redelegate to validator2 + // redelegate to validator 2 execute_stake( &mut env, delegator_addr_1.clone(), @@ -1668,7 +1678,7 @@ mod test { ) .unwrap(); - // should have same amount as before (rewards receiver received rewards). + // should have same amount as before (rewards receiver received rewards) assert_balances(&env, vec![(delegator_addr_1.clone(), 900)]); let delegations: AllDelegationsResponse = query_stake( @@ -1713,7 +1723,7 @@ mod test { #[test] fn can_set_withdraw_address() { - let mut env = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1795,13 +1805,13 @@ mod test { #[test] fn cannot_steal() { - let mut env = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (0, 20, 1))); let validator_addr_1 = env.validator_addr_1(); let validator_addr_2 = env.validator_addr_2(); let delegator_addr_1 = env.delegator_addr_1(); - // fund delegator account + // initialize delegator account env.router .bank .init_balance( @@ -1811,7 +1821,7 @@ mod test { ) .unwrap(); - // delegate 100 tokens to validator1 + // delegate 100 tokens to validator 1 execute_stake( &mut env, delegator_addr_1.clone(), @@ -1835,23 +1845,7 @@ mod test { assert_eq!(e.to_string(), "invalid shares amount"); - // add second validator - env.router - .staking - .add_validator( - &env.api, - &mut env.store, - &env.block, - Validator::new( - validator_addr_2.to_string(), - Decimal::zero(), - Decimal::percent(20), - Decimal::percent(1), - ), - ) - .unwrap(); - - // redelegate more tokens than we have + // redelegate more tokens than we have from validator 1 to validator 2 let e = execute_stake( &mut env, delegator_addr_1.clone(), @@ -1882,7 +1876,7 @@ mod test { #[test] fn denom_validation() { - let mut env = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1912,9 +1906,9 @@ mod test { #[test] fn cannot_slash_nonexistent() { - let mut env = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); - let non_existing_validator_addr = env.validator_addr_2(); + let non_existing_validator_addr = env.validator_addr_3(); let delegator_addr_1 = env.delegator_addr_1(); // fund delegator account @@ -1944,9 +1938,9 @@ mod test { #[test] fn non_existent_validator() { - let mut env = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); - let non_existing_validator_addr = env.validator_addr_2(); + let non_existing_validator_addr = env.validator_addr_3(); let delegator_addr_1 = env.delegator_addr_1(); // init balances @@ -1986,7 +1980,7 @@ mod test { #[test] fn zero_staking_forbidden() { - let mut env = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2018,7 +2012,7 @@ mod test { #[test] fn query_staking() { - let mut env = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (0, 1, 1))); let validator_addr_1 = env.validator_addr_1(); let validator_addr_2 = env.validator_addr_2(); @@ -2044,18 +2038,6 @@ mod test { ) .unwrap(); - // add another validator - let valoper2 = Validator::new( - validator_addr_2.to_string(), - Decimal::percent(0), - Decimal::percent(1), - Decimal::percent(1), - ); - env.router - .staking - .add_validator(&env.api, &mut env.store, &env.block, valoper2.clone()) - .unwrap(); - // query validators let valoper1: ValidatorResponse = query_stake( &env, @@ -2064,12 +2046,21 @@ mod test { }, ) .unwrap(); + let valoper2: ValidatorResponse = query_stake( + &env, + StakingQuery::Validator { + address: validator_addr_2.to_string(), + }, + ) + .unwrap(); + let validators: AllValidatorsResponse = query_stake(&env, StakingQuery::AllValidators {}).unwrap(); assert_eq!( validators.validators, - [valoper1.validator.unwrap(), valoper2] + [valoper1.validator.unwrap(), valoper2.validator.unwrap()] ); + // query non-existent validator let response = query_stake::( &env, @@ -2178,7 +2169,7 @@ mod test { #[test] fn delegation_queries_unbonding() { - let mut env = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2314,7 +2305,7 @@ mod test { #[test] fn partial_unbonding_reduces_stake() { - let mut env = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2429,7 +2420,7 @@ mod test { #[test] fn delegations_slashed() { - let mut env = TestEnv::wrap(setup_test_env(10, 10)); + let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2512,7 +2503,7 @@ mod test { #[test] fn rewards_initial_wait() { - let mut env = TestEnv::wrap(setup_test_env(10, 0)); + let mut env = TestEnv::wrap(TestEnv::setup(10, (0, 100, 1), (10, 100, 1))); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); From a464f9388e5eb4e524d9a3b15e966dd7c34fa897 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 14 Jun 2024 13:27:23 +0200 Subject: [PATCH 215/250] Refactoried add/get validator test case. --- src/staking.rs | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 8390c755..805fc318 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1189,46 +1189,49 @@ mod test { #[test] fn add_get_validators() { - let api = MockApi::default(); - let mut store = MockStorage::new(); - let stake = StakeKeeper::default(); - let block = mock_env().block; + let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (0, 20, 1))); - let validator_addr = api.addr_make("test-validator"); + let validator_addr = env.validator_addr_3(); - // add validator + // add a new validator (validator no. 3 does not exist yet) let validator = Validator::new( validator_addr.to_string(), Decimal::percent(10), Decimal::percent(20), Decimal::percent(1), ); - stake - .add_validator(&api, &mut store, &block, validator.clone()) + env.router + .staking + .add_validator(&env.api, &mut env.store, &env.block, validator.clone()) .unwrap(); - // get it - let staking_storage = prefixed_read(&store, NAMESPACE_STAKING); - let val = stake + // get the newly created validator + let staking_storage = prefixed_read(&env.store, NAMESPACE_STAKING); + let val = env + .router + .staking .get_validator(&staking_storage, &validator_addr) .unwrap() .unwrap(); assert_eq!(val, validator); - // try to add with same address + // try to add a validator with same address (validator no. 3) let validator_fake = Validator::new( validator_addr.to_string(), Decimal::percent(1), Decimal::percent(10), Decimal::percent(100), ); - stake - .add_validator(&api, &mut store, &block, validator_fake) + env.router + .staking + .add_validator(&env.api, &mut env.store, &env.block, validator_fake) .unwrap_err(); - // should still be original value - let staking_storage = prefixed_read(&store, NAMESPACE_STAKING); - let val = stake + // validator no. 3 should be still like the original value + let staking_storage = prefixed_read(&env.store, NAMESPACE_STAKING); + let val = env + .router + .staking .get_validator(&staking_storage, &validator_addr) .unwrap() .unwrap(); From 0092b7d791ef7c7b75143e8ea30973809e3797ce Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 14 Jun 2024 13:37:20 +0200 Subject: [PATCH 216/250] Called default from new for StakeKeeper. --- src/staking.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 805fc318..67a07c35 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -154,17 +154,17 @@ pub struct StakeKeeper { impl Default for StakeKeeper { /// Creates a new stake keeper with default settings. fn default() -> Self { - Self::new() + StakeKeeper { + // The address of the staking module. This holds all staked tokens. + module_addr: Addr::unchecked("staking_module"), + } } } impl StakeKeeper { /// Creates a new stake keeper with default module address. pub fn new() -> Self { - StakeKeeper { - // The address of the staking module. This holds all staked tokens. - module_addr: Addr::unchecked("staking_module"), - } + Self::default() } /// Provides some general parameters to the stake keeper From f8ed66aff55185ab8ca1de141876098fa9b1630a Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 14 Jun 2024 14:11:46 +0200 Subject: [PATCH 217/250] Refactored slashing test case. --- src/staking.rs | 126 +++++++++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 72 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 67a07c35..1cd4be28 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1031,8 +1031,8 @@ impl Module for DistributionKeeper { mod test { use super::*; use crate::{ - app::MockRouter, BankKeeper, FailingModule, GovFailingModule, IbcFailingModule, Router, - StargateFailing, WasmKeeper, + BankKeeper, FailingModule, GovFailingModule, IbcFailingModule, Router, StargateFailing, + WasmKeeper, }; use cosmwasm_std::{ from_json, @@ -1082,7 +1082,7 @@ mod test { } impl TestEnv { - fn setup(apr: u64, validator1: (u64, u64, u64), validator2: (u64, u64, u64)) -> TestTuple { + fn setup(validator1: (u64, u64, u64), validator2: (u64, u64, u64)) -> TestTuple { let api = MockApi::default(); let router = mock_router(); let mut store = MockStorage::new(); @@ -1093,14 +1093,7 @@ mod test { router .staking - .setup( - &mut store, - StakingInfo { - bonded_denom: BONDED_DENOM.to_string(), - unbonding_time: 60, - apr: Decimal::percent(apr), - }, - ) + .setup(&mut store, StakingInfo::default()) .unwrap(); // add first validator @@ -1189,7 +1182,7 @@ mod test { #[test] fn add_get_validators() { - let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (0, 20, 1))); + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 20, 1))); let validator_addr = env.validator_addr_3(); @@ -1240,46 +1233,33 @@ mod test { #[test] fn validator_slashing() { - let api = MockApi::default(); - let router = MockRouter::default(); - let mut store = MockStorage::new(); - let stake = StakeKeeper::new(); - let block = mock_env().block; - - let delegator_addr = api.addr_make("delegator"); - let validator_addr = api.addr_make("testvaloper1"); + let mut env = TestEnv::wrap(TestEnv::setup((10, 20, 1), (10, 20, 1))); - // add validator - let valoper1 = Validator::new( - validator_addr.to_string(), - Decimal::percent(10), - Decimal::percent(20), - Decimal::percent(1), - ); - stake - .add_validator(&api, &mut store, &block, valoper1) - .unwrap(); + let validator_addr = env.validator_addr_1(); + let delegator_addr = env.delegator_addr_1(); - // stake 100 tokens - let mut staking_storage = prefixed(&mut store, NAMESPACE_STAKING); - stake + // stake (delegate) 100 tokens from delegator to validator + let mut staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); + env.router + .staking .add_stake( - &api, + &env.api, &mut staking_storage, - &block, + &env.block, &delegator_addr, &validator_addr, coin(100, BONDED_DENOM), ) .unwrap(); - // slash 50% - stake + // slash 50% of the stake of the validator + env.router + .staking .sudo( - &api, - &mut store, - &router, - &block, + &env.api, + &mut env.store, + &env.router, + &env.block, StakingSudo::Slash { validator: validator_addr.to_string(), percentage: Decimal::percent(50), @@ -1287,24 +1267,24 @@ mod test { ) .unwrap(); - // check stake - let staking_storage = prefixed(&mut store, NAMESPACE_STAKING); - let stake_left = stake + // check the remaining stake + let staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); + let stake_left = env + .router + .staking .get_stake(&staking_storage, &delegator_addr, &validator_addr) + .unwrap() .unwrap(); - assert_eq!( - stake_left.unwrap().amount.u128(), - 50, - "should have slashed 50%" - ); + assert_eq!(50, stake_left.amount.u128()); // slash all - stake + env.router + .staking .sudo( - &api, - &mut store, - &router, - &block, + &env.api, + &mut env.store, + &env.router, + &env.block, StakingSudo::Slash { validator: validator_addr.to_string(), percentage: Decimal::percent(100), @@ -1312,18 +1292,20 @@ mod test { ) .unwrap(); - // check stake - let staking_storage = prefixed(&mut store, NAMESPACE_STAKING); - let stake_left = stake + // check the current stake + let staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); + let stake_left = env + .router + .staking .get_stake(&staking_storage, &delegator_addr, &validator_addr) .unwrap(); - assert_eq!(stake_left, None, "should have slashed whole stake"); + assert_eq!(None, stake_left); } #[test] fn rewards_work_for_single_delegator() { let (api, mut store, router, mut block, validator_addr, _) = - TestEnv::setup(10, (10, 100, 1), (10, 100, 1)); + TestEnv::setup((10, 100, 1), (10, 100, 1)); let stake = &router.staking; let distr = &router.distribution; let delegator_addr = api.addr_make("delegator"); @@ -1385,7 +1367,7 @@ mod test { #[test] fn rewards_work_for_multiple_delegators() { let (api, mut store, router, mut block, validator, _) = - TestEnv::setup(10, (10, 100, 1), (10, 100, 1)); + TestEnv::setup((10, 100, 1), (10, 100, 1)); let stake = &router.staking; let distr = &router.distribution; let bank = &router.bank; @@ -1608,7 +1590,7 @@ mod test { #[test] fn execute() { - let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (0, 20, 1))); + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 20, 1))); let validator_addr_1 = env.validator_addr_1(); let validator_addr_2 = env.validator_addr_2(); @@ -1726,7 +1708,7 @@ mod test { #[test] fn can_set_withdraw_address() { - let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1808,7 +1790,7 @@ mod test { #[test] fn cannot_steal() { - let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (0, 20, 1))); + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 20, 1))); let validator_addr_1 = env.validator_addr_1(); let validator_addr_2 = env.validator_addr_2(); @@ -1879,7 +1861,7 @@ mod test { #[test] fn denom_validation() { - let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1909,7 +1891,7 @@ mod test { #[test] fn cannot_slash_nonexistent() { - let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); let non_existing_validator_addr = env.validator_addr_3(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1941,7 +1923,7 @@ mod test { #[test] fn non_existent_validator() { - let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); let non_existing_validator_addr = env.validator_addr_3(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1983,7 +1965,7 @@ mod test { #[test] fn zero_staking_forbidden() { - let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2015,7 +1997,7 @@ mod test { #[test] fn query_staking() { - let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (0, 1, 1))); + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 1, 1))); let validator_addr_1 = env.validator_addr_1(); let validator_addr_2 = env.validator_addr_2(); @@ -2172,7 +2154,7 @@ mod test { #[test] fn delegation_queries_unbonding() { - let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2308,7 +2290,7 @@ mod test { #[test] fn partial_unbonding_reduces_stake() { - let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2423,7 +2405,7 @@ mod test { #[test] fn delegations_slashed() { - let mut env = TestEnv::wrap(TestEnv::setup(10, (10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2506,7 +2488,7 @@ mod test { #[test] fn rewards_initial_wait() { - let mut env = TestEnv::wrap(TestEnv::setup(10, (0, 100, 1), (10, 100, 1))); + let mut env = TestEnv::wrap(TestEnv::setup((0, 100, 1), (10, 100, 1))); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); From e743eeda21b6e81193c59626996e9f8d9716e7c1 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 14 Jun 2024 14:25:42 +0200 Subject: [PATCH 218/250] Refactored rewards for single delegator test case. --- src/staking.rs | 57 ++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 1cd4be28..247ddb83 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1304,19 +1304,19 @@ mod test { #[test] fn rewards_work_for_single_delegator() { - let (api, mut store, router, mut block, validator_addr, _) = - TestEnv::setup((10, 100, 1), (10, 100, 1)); - let stake = &router.staking; - let distr = &router.distribution; - let delegator_addr = api.addr_make("delegator"); + let mut env = TestEnv::wrap(TestEnv::setup((10, 20, 1), (10, 20, 1))); - let mut staking_storage = prefixed(&mut store, NAMESPACE_STAKING); + let validator_addr = env.validator_addr_1(); + let delegator_addr = env.delegator_addr_1(); + + let mut staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); // stake 200 tokens - stake + env.router + .staking .add_stake( - &api, + &env.api, &mut staking_storage, - &block, + &env.block, &delegator_addr, &validator_addr, coin(200, BONDED_DENOM), @@ -1324,22 +1324,25 @@ mod test { .unwrap(); // wait 1/2 year - block.time = block.time.plus_seconds(YEAR / 2); + env.block.time = env.block.time.plus_seconds(YEAR / 2); // should now have 200 * 10% / 2 - 10% commission = 9 tokens reward - let rewards = stake - .get_rewards(&store, &block, &delegator_addr, &validator_addr) + let rewards = env + .router + .staking + .get_rewards(&env.store, &env.block, &delegator_addr, &validator_addr) .unwrap() .unwrap(); - assert_eq!(rewards.amount.u128(), 9, "should have 9 tokens reward"); + assert_eq!(9, rewards.amount.u128()); // withdraw rewards - distr + env.router + .distribution .execute( - &api, - &mut store, - &router, - &block, + &env.api, + &mut env.store, + &env.router, + &env.block, delegator_addr.clone(), DistributionMsg::WithdrawDelegatorReward { validator: validator_addr.to_string(), @@ -1348,20 +1351,24 @@ mod test { .unwrap(); // should have no rewards left - let rewards = stake - .get_rewards(&store, &block, &delegator_addr, &validator_addr) + let rewards = env + .router + .staking + .get_rewards(&env.store, &env.block, &delegator_addr, &validator_addr) .unwrap() .unwrap(); - assert_eq!(rewards.amount.u128(), 0); + assert_eq!(0, rewards.amount.u128()); // wait another 1/2 year - block.time = block.time.plus_seconds(YEAR / 2); + env.block.time = env.block.time.plus_seconds(YEAR / 2); // should now have 9 tokens again - let rewards = stake - .get_rewards(&store, &block, &delegator_addr, &validator_addr) + let rewards = env + .router + .staking + .get_rewards(&env.store, &env.block, &delegator_addr, &validator_addr) .unwrap() .unwrap(); - assert_eq!(rewards.amount.u128(), 9); + assert_eq!(9, rewards.amount.u128()); } #[test] From 8e4fd79597a3ed5caff67d5e4a2debb7b4dcf2b5 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 14 Jun 2024 14:31:42 +0200 Subject: [PATCH 219/250] Refactored rewards for multiple delegators test case. --- src/staking.rs | 134 +++++++++++++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 55 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 247ddb83..0770adf3 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1373,32 +1373,37 @@ mod test { #[test] fn rewards_work_for_multiple_delegators() { - let (api, mut store, router, mut block, validator, _) = - TestEnv::setup((10, 100, 1), (10, 100, 1)); - let stake = &router.staking; - let distr = &router.distribution; - let bank = &router.bank; - let delegator1 = api.addr_make("delegator1"); - let delegator2 = api.addr_make("delegator2"); + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + // let (api, mut store, router, mut block, validator, _) = + // TestEnv::setup((10, 100, 1), (10, 100, 1)); + // let stake = &router.staking; + // let distr = &router.distribution; + // let bank = &router.bank; - let mut staking_storage = prefixed(&mut store, NAMESPACE_STAKING); + let validator = env.validator_addr_1(); + let delegator1 = env.delegator_addr_1(); + let delegator2 = env.delegator_addr_2(); + + let mut staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); // add 100 stake to delegator1 and 200 to delegator2 - stake + env.router + .staking .add_stake( - &api, + &env.api, &mut staking_storage, - &block, + &env.block, &delegator1, &validator, coin(100, BONDED_DENOM), ) .unwrap(); - stake + env.router + .staking .add_stake( - &api, + &env.api, &mut staking_storage, - &block, + &env.block, &delegator2, &validator, coin(200, BONDED_DENOM), @@ -1406,29 +1411,34 @@ mod test { .unwrap(); // wait 1 year - block.time = block.time.plus_seconds(YEAR); + env.block.time = env.block.time.plus_seconds(YEAR); // delegator1 should now have 100 * 10% - 10% commission = 9 tokens - let rewards = stake - .get_rewards(&store, &block, &delegator1, &validator) + let rewards = env + .router + .staking + .get_rewards(&env.store, &env.block, &delegator1, &validator) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 9); // delegator2 should now have 200 * 10% - 10% commission = 18 tokens - let rewards = stake - .get_rewards(&store, &block, &delegator2, &validator) + let rewards = env + .router + .staking + .get_rewards(&env.store, &env.block, &delegator2, &validator) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 18); // delegator1 stakes 100 more - let mut staking_storage = prefixed(&mut store, NAMESPACE_STAKING); - stake + let mut staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); + env.router + .staking .add_stake( - &api, + &env.api, &mut staking_storage, - &block, + &env.block, &delegator1, &validator, coin(100, BONDED_DENOM), @@ -1436,29 +1446,34 @@ mod test { .unwrap(); // wait another year - block.time = block.time.plus_seconds(YEAR); + env.block.time = env.block.time.plus_seconds(YEAR); // delegator1 should now have 9 + 200 * 10% - 10% commission = 27 tokens - let rewards = stake - .get_rewards(&store, &block, &delegator1, &validator) + let rewards = env + .router + .staking + .get_rewards(&env.store, &env.block, &delegator1, &validator) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 27); // delegator2 should now have 18 + 200 * 10% - 10% commission = 36 tokens - let rewards = stake - .get_rewards(&store, &block, &delegator2, &validator) + let rewards = env + .router + .staking + .get_rewards(&env.store, &env.block, &delegator2, &validator) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 36); // delegator2 unstakes 100 (has 100 left after that) - let mut staking_storage = prefixed(&mut store, NAMESPACE_STAKING); - stake + let mut staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); + env.router + .staking .remove_stake( - &api, + &env.api, &mut staking_storage, - &block, + &env.block, &delegator2, &validator, coin(100, BONDED_DENOM), @@ -1466,12 +1481,13 @@ mod test { .unwrap(); // and delegator1 withdraws rewards - distr + env.router + .distribution .execute( - &api, - &mut store, - &router, - &block, + &env.api, + &mut env.store, + &env.router, + &env.block, delegator1.clone(), DistributionMsg::WithdrawDelegatorReward { validator: validator.to_string(), @@ -1480,17 +1496,19 @@ mod test { .unwrap(); let balance: BalanceResponse = from_json( - bank.query( - &api, - &store, - &router.querier(&api, &store, &block), - &block, - BankQuery::Balance { - address: delegator1.to_string(), - denom: BONDED_DENOM.to_string(), - }, - ) - .unwrap(), + env.router + .bank + .query( + &env.api, + &env.store, + &env.router.querier(&env.api, &env.store, &env.block), + &env.block, + BankQuery::Balance { + address: delegator1.to_string(), + denom: BONDED_DENOM.to_string(), + }, + ) + .unwrap(), ) .unwrap(); assert_eq!( @@ -1498,8 +1516,10 @@ mod test { 27, "withdraw should change bank balance" ); - let rewards = stake - .get_rewards(&store, &block, &delegator1, &validator) + let rewards = env + .router + .staking + .get_rewards(&env.store, &env.block, &delegator1, &validator) .unwrap() .unwrap(); assert_eq!( @@ -1509,18 +1529,22 @@ mod test { ); // wait another year - block.time = block.time.plus_seconds(YEAR); + env.block.time = env.block.time.plus_seconds(YEAR); // delegator1 should now have 0 + 200 * 10% - 10% commission = 18 tokens - let rewards = stake - .get_rewards(&store, &block, &delegator1, &validator) + let rewards = env + .router + .staking + .get_rewards(&env.store, &env.block, &delegator1, &validator) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 18); // delegator2 should now have 36 + 100 * 10% - 10% commission = 45 tokens - let rewards = stake - .get_rewards(&store, &block, &delegator2, &validator) + let rewards = env + .router + .staking + .get_rewards(&env.store, &env.block, &delegator2, &validator) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 45); From 654234e7872f57e275d9f6e85bda8ed9b5e5c84e Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 14 Jun 2024 14:38:53 +0200 Subject: [PATCH 220/250] Flattened test structure to one module. --- src/staking.rs | 1821 ++++++++++++++++++++++++------------------------ 1 file changed, 900 insertions(+), 921 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 0770adf3..d4f14b16 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1035,10 +1035,11 @@ mod test { WasmKeeper, }; use cosmwasm_std::{ - from_json, + coins, from_json, testing::{mock_env, MockApi, MockStorage}, - BalanceResponse, BankQuery, + BalanceResponse, BankQuery, QuerierWrapper, }; + use serde::de::DeserializeOwned; /// Type alias for default build of [Router], to make its reference in typical test scenario. type BasicRouter = Router< @@ -1180,6 +1181,66 @@ mod test { } } + fn execute_stake(env: &mut TestEnv, sender: Addr, msg: StakingMsg) -> AnyResult { + env.router.staking.execute( + &env.api, + &mut env.store, + &env.router, + &env.block, + sender, + msg, + ) + } + + fn query_stake(env: &TestEnv, msg: StakingQuery) -> AnyResult { + Ok(from_json(env.router.staking.query( + &env.api, + &env.store, + &env.router.querier(&env.api, &env.store, &env.block), + &env.block, + msg, + )?)?) + } + + fn execute_distr( + env: &mut TestEnv, + sender: Addr, + msg: DistributionMsg, + ) -> AnyResult { + env.router.distribution.execute( + &env.api, + &mut env.store, + &env.router, + &env.block, + sender, + msg, + ) + } + + fn query_bank(env: &TestEnv, msg: BankQuery) -> AnyResult { + Ok(from_json(env.router.bank.query( + &env.api, + &env.store, + &env.router.querier(&env.api, &env.store, &env.block), + &env.block, + msg, + )?)?) + } + + fn assert_balances(env: &TestEnv, balances: impl IntoIterator) { + for (addr, amount) in balances { + let balance: BalanceResponse = query_bank( + env, + BankQuery::Balance { + address: addr.to_string(), + denom: BONDED_DENOM.to_string(), + }, + ) + .unwrap(); + assert_eq!(balance.amount.amount.u128(), amount); + } + } + #[test] fn add_get_validators() { let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 20, 1))); @@ -1374,11 +1435,6 @@ mod test { #[test] fn rewards_work_for_multiple_delegators() { let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); - // let (api, mut store, router, mut block, validator, _) = - // TestEnv::setup((10, 100, 1), (10, 100, 1)); - // let stake = &router.staking; - // let distr = &router.distribution; - // let bank = &router.bank; let validator = env.validator_addr_1(); let delegator1 = env.delegator_addr_1(); @@ -1511,22 +1567,15 @@ mod test { .unwrap(), ) .unwrap(); - assert_eq!( - balance.amount.amount.u128(), - 27, - "withdraw should change bank balance" - ); + assert_eq!(27, balance.amount.amount.u128()); + let rewards = env .router .staking .get_rewards(&env.store, &env.block, &delegator1, &validator) .unwrap() .unwrap(); - assert_eq!( - rewards.amount.u128(), - 0, - "withdraw should reduce rewards to 0" - ); + assert_eq!(0, rewards.amount.u128()); // wait another year env.block.time = env.block.time.plus_seconds(YEAR); @@ -1538,7 +1587,7 @@ mod test { .get_rewards(&env.store, &env.block, &delegator1, &validator) .unwrap() .unwrap(); - assert_eq!(rewards.amount.u128(), 18); + assert_eq!(18, rewards.amount.u128()); // delegator2 should now have 36 + 100 * 10% - 10% commission = 45 tokens let rewards = env @@ -1547,1024 +1596,954 @@ mod test { .get_rewards(&env.store, &env.block, &delegator2, &validator) .unwrap() .unwrap(); - assert_eq!(rewards.amount.u128(), 45); + assert_eq!(45, rewards.amount.u128()); } - mod msg { - use super::*; - use cosmwasm_std::{coins, QuerierWrapper}; - use serde::de::DeserializeOwned; - - fn execute_stake( - env: &mut TestEnv, - sender: Addr, - msg: StakingMsg, - ) -> AnyResult { - env.router.staking.execute( - &env.api, - &mut env.store, - &env.router, - &env.block, - sender, - msg, - ) - } + #[test] + fn execute() { + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 20, 1))); - fn query_stake(env: &TestEnv, msg: StakingQuery) -> AnyResult { - Ok(from_json(env.router.staking.query( - &env.api, - &env.store, - &env.router.querier(&env.api, &env.store, &env.block), - &env.block, - msg, - )?)?) - } + let validator_addr_1 = env.validator_addr_1(); + let validator_addr_2 = env.validator_addr_2(); + let delegator_addr_1 = env.delegator_addr_2(); + let reward_receiver_addr = env.user_addr_1(); - fn execute_distr( - env: &mut TestEnv, - sender: Addr, - msg: DistributionMsg, - ) -> AnyResult { - env.router.distribution.execute( - &env.api, + // initialize delegator account + env.router + .bank + .init_balance( &mut env.store, - &env.router, - &env.block, - sender, - msg, + &delegator_addr_1, + vec![coin(1000, BONDED_DENOM)], ) - } + .unwrap(); - fn query_bank(env: &TestEnv, msg: BankQuery) -> AnyResult { - Ok(from_json(env.router.bank.query( - &env.api, - &env.store, - &env.router.querier(&env.api, &env.store, &env.block), - &env.block, - msg, - )?)?) - } + // delegate 100 tokens to validator 1 + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Delegate { + validator: validator_addr_1.to_string(), + amount: coin(100, BONDED_DENOM), + }, + ) + .unwrap(); - fn assert_balances(env: &TestEnv, balances: impl IntoIterator) { - for (addr, amount) in balances { - let balance: BalanceResponse = query_bank( - env, - BankQuery::Balance { - address: addr.to_string(), - denom: BONDED_DENOM.to_string(), - }, - ) - .unwrap(); - assert_eq!(balance.amount.amount.u128(), amount); - } - } + // should now have 100 tokens less + assert_balances(&env, vec![(delegator_addr_1.clone(), 900)]); - #[test] - fn execute() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 20, 1))); + // wait a year + env.block.time = env.block.time.plus_seconds(YEAR); - let validator_addr_1 = env.validator_addr_1(); - let validator_addr_2 = env.validator_addr_2(); - let delegator_addr_1 = env.delegator_addr_2(); - let reward_receiver_addr = env.user_addr_1(); + // change the withdrawal address + execute_distr( + &mut env, + delegator_addr_1.clone(), + DistributionMsg::SetWithdrawAddress { + address: reward_receiver_addr.to_string(), + }, + ) + .unwrap(); - // initialize delegator account - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(1000, BONDED_DENOM)], - ) - .unwrap(); + // withdraw rewards + execute_distr( + &mut env, + delegator_addr_1.clone(), + DistributionMsg::WithdrawDelegatorReward { + validator: validator_addr_1.to_string(), + }, + ) + .unwrap(); - // delegate 100 tokens to validator 1 - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Delegate { - validator: validator_addr_1.to_string(), - amount: coin(100, BONDED_DENOM), - }, - ) - .unwrap(); + // withdrawal address received rewards + assert_balances( + &env, + // one year, 10%apr, 10% commission, 100 tokens staked + vec![(reward_receiver_addr, 100 / 10 * 9 / 10)], + ); - // should now have 100 tokens less - assert_balances(&env, vec![(delegator_addr_1.clone(), 900)]); + // redelegate to validator 2 + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Redelegate { + src_validator: validator_addr_1.to_string(), + dst_validator: validator_addr_2.to_string(), + amount: coin(100, BONDED_DENOM), + }, + ) + .unwrap(); - // wait a year - env.block.time = env.block.time.plus_seconds(YEAR); + // should have same amount as before (rewards receiver received rewards) + assert_balances(&env, vec![(delegator_addr_1.clone(), 900)]); - // change the withdrawal address - execute_distr( - &mut env, + let delegations: AllDelegationsResponse = query_stake( + &env, + StakingQuery::AllDelegations { + delegator: delegator_addr_1.to_string(), + }, + ) + .unwrap(); + assert_eq!( + delegations.delegations, + [Delegation::new( delegator_addr_1.clone(), - DistributionMsg::SetWithdrawAddress { - address: reward_receiver_addr.to_string(), - }, - ) - .unwrap(); + validator_addr_2.to_string(), + coin(100, BONDED_DENOM), + )] + ); - // withdraw rewards - execute_distr( - &mut env, - delegator_addr_1.clone(), - DistributionMsg::WithdrawDelegatorReward { - validator: validator_addr_1.to_string(), - }, - ) - .unwrap(); + // undelegate all tokens + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Undelegate { + validator: validator_addr_2.to_string(), + amount: coin(100, BONDED_DENOM), + }, + ) + .unwrap(); - // withdrawal address received rewards - assert_balances( - &env, - // one year, 10%apr, 10% commission, 100 tokens staked - vec![(reward_receiver_addr, 100 / 10 * 9 / 10)], - ); + // wait for unbonding period (60 seconds in default config) + env.block.time = env.block.time.plus_seconds(60); - // redelegate to validator 2 - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Redelegate { - src_validator: validator_addr_1.to_string(), - dst_validator: validator_addr_2.to_string(), - amount: coin(100, BONDED_DENOM), - }, - ) + // need to manually cause queue to get processed + env.router + .staking + .process_queue(&env.api, &mut env.store, &env.router, &env.block) .unwrap(); - // should have same amount as before (rewards receiver received rewards) - assert_balances(&env, vec![(delegator_addr_1.clone(), 900)]); - - let delegations: AllDelegationsResponse = query_stake( - &env, - StakingQuery::AllDelegations { - delegator: delegator_addr_1.to_string(), - }, - ) - .unwrap(); - assert_eq!( - delegations.delegations, - [Delegation::new( - delegator_addr_1.clone(), - validator_addr_2.to_string(), - coin(100, BONDED_DENOM), - )] - ); + // check bank balance + assert_balances(&env, vec![(delegator_addr_1.clone(), 1000)]); + } - // undelegate all tokens - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Undelegate { - validator: validator_addr_2.to_string(), - amount: coin(100, BONDED_DENOM), - }, - ) - .unwrap(); + #[test] + fn can_set_withdraw_address() { + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); - // wait for unbonding period (60 seconds in default config) - env.block.time = env.block.time.plus_seconds(60); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); + let reward_receiver_addr = env.user_addr_1(); - // need to manually cause queue to get processed - env.router - .staking - .process_queue(&env.api, &mut env.store, &env.router, &env.block) - .unwrap(); + env.router + .bank + .init_balance(&mut env.store, &delegator_addr_1, coins(100, BONDED_DENOM)) + .unwrap(); + + // Stake 100 tokens to the validator. + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Delegate { + validator: validator_addr_1.to_string(), + amount: coin(100, BONDED_DENOM), + }, + ) + .unwrap(); - // check bank balance - assert_balances(&env, vec![(delegator_addr_1.clone(), 1000)]); - } + // Change rewards receiver. + execute_distr( + &mut env, + delegator_addr_1.clone(), + DistributionMsg::SetWithdrawAddress { + address: reward_receiver_addr.to_string(), + }, + ) + .unwrap(); - #[test] - fn can_set_withdraw_address() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + // A year passes. + env.block.time = env.block.time.plus_seconds(YEAR); - let validator_addr_1 = env.validator_addr_1(); - let delegator_addr_1 = env.delegator_addr_1(); - let reward_receiver_addr = env.user_addr_1(); + // Withdraw rewards to reward receiver. + execute_distr( + &mut env, + delegator_addr_1.clone(), + DistributionMsg::WithdrawDelegatorReward { + validator: validator_addr_1.to_string(), + }, + ) + .unwrap(); - env.router - .bank - .init_balance(&mut env.store, &delegator_addr_1, coins(100, BONDED_DENOM)) - .unwrap(); + // Change reward receiver back to delegator. + execute_distr( + &mut env, + delegator_addr_1.clone(), + DistributionMsg::SetWithdrawAddress { + address: delegator_addr_1.to_string(), + }, + ) + .unwrap(); - // Stake 100 tokens to the validator. - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Delegate { - validator: validator_addr_1.to_string(), - amount: coin(100, BONDED_DENOM), - }, - ) - .unwrap(); + // Another year passes. + env.block.time = env.block.time.plus_seconds(YEAR); - // Change rewards receiver. - execute_distr( - &mut env, - delegator_addr_1.clone(), - DistributionMsg::SetWithdrawAddress { - address: reward_receiver_addr.to_string(), - }, - ) - .unwrap(); + // Withdraw rewards to delegator. + execute_distr( + &mut env, + delegator_addr_1.clone(), + DistributionMsg::WithdrawDelegatorReward { + validator: validator_addr_1.to_string(), + }, + ) + .unwrap(); - // A year passes. - env.block.time = env.block.time.plus_seconds(YEAR); + // one year, 10%apr, 10% commission, 100 tokens staked + let rewards_yr = 100 / 10 * 9 / 10; - // Withdraw rewards to reward receiver. - execute_distr( - &mut env, - delegator_addr_1.clone(), - DistributionMsg::WithdrawDelegatorReward { - validator: validator_addr_1.to_string(), - }, - ) - .unwrap(); + assert_balances( + &env, + vec![ + (reward_receiver_addr, rewards_yr), + (delegator_addr_1, rewards_yr), + ], + ); + } - // Change reward receiver back to delegator. - execute_distr( - &mut env, - delegator_addr_1.clone(), - DistributionMsg::SetWithdrawAddress { - address: delegator_addr_1.to_string(), - }, - ) - .unwrap(); + #[test] + fn cannot_steal() { + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 20, 1))); - // Another year passes. - env.block.time = env.block.time.plus_seconds(YEAR); + let validator_addr_1 = env.validator_addr_1(); + let validator_addr_2 = env.validator_addr_2(); + let delegator_addr_1 = env.delegator_addr_1(); - // Withdraw rewards to delegator. - execute_distr( - &mut env, - delegator_addr_1.clone(), - DistributionMsg::WithdrawDelegatorReward { - validator: validator_addr_1.to_string(), - }, + // initialize delegator account + env.router + .bank + .init_balance( + &mut env.store, + &delegator_addr_1, + vec![coin(100, BONDED_DENOM)], ) .unwrap(); - // one year, 10%apr, 10% commission, 100 tokens staked - let rewards_yr = 100 / 10 * 9 / 10; - - assert_balances( - &env, - vec![ - (reward_receiver_addr, rewards_yr), - (delegator_addr_1, rewards_yr), - ], - ); - } - - #[test] - fn cannot_steal() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 20, 1))); + // delegate 100 tokens to validator 1 + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Delegate { + validator: validator_addr_1.to_string(), + amount: coin(100, BONDED_DENOM), + }, + ) + .unwrap(); - let validator_addr_1 = env.validator_addr_1(); - let validator_addr_2 = env.validator_addr_2(); - let delegator_addr_1 = env.delegator_addr_1(); + // undelegate more tokens than we have + let e = execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Undelegate { + validator: validator_addr_1.to_string(), + amount: coin(200, BONDED_DENOM), + }, + ) + .unwrap_err(); - // initialize delegator account - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(100, BONDED_DENOM)], - ) - .unwrap(); + assert_eq!(e.to_string(), "invalid shares amount"); - // delegate 100 tokens to validator 1 - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Delegate { - validator: validator_addr_1.to_string(), - amount: coin(100, BONDED_DENOM), - }, - ) - .unwrap(); + // redelegate more tokens than we have from validator 1 to validator 2 + let e = execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Redelegate { + src_validator: validator_addr_1.to_string(), + dst_validator: validator_addr_2.to_string(), + amount: coin(200, BONDED_DENOM), + }, + ) + .unwrap_err(); + assert_eq!(e.to_string(), "invalid shares amount"); + + // undelegate from non-existing delegation + let e = execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Undelegate { + validator: validator_addr_2.to_string(), + amount: coin(100, BONDED_DENOM), + }, + ) + .unwrap_err(); + assert_eq!( + e.to_string(), + "no delegation for (address, validator) tuple" + ); + } - // undelegate more tokens than we have - let e = execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Undelegate { - validator: validator_addr_1.to_string(), - amount: coin(200, BONDED_DENOM), - }, - ) - .unwrap_err(); + #[test] + fn denom_validation() { + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); - assert_eq!(e.to_string(), "invalid shares amount"); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); - // redelegate more tokens than we have from validator 1 to validator 2 - let e = execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Redelegate { - src_validator: validator_addr_1.to_string(), - dst_validator: validator_addr_2.to_string(), - amount: coin(200, BONDED_DENOM), - }, - ) - .unwrap_err(); - assert_eq!(e.to_string(), "invalid shares amount"); + // fund delegator account + env.router + .bank + .init_balance(&mut env.store, &delegator_addr_1, vec![coin(100, "FAKE")]) + .unwrap(); + + // try to delegate 100 to validator + let e = execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Delegate { + validator: validator_addr_1.to_string(), + amount: coin(100, "FAKE"), + }, + ) + .unwrap_err(); - // undelegate from non-existing delegation - let e = execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Undelegate { - validator: validator_addr_2.to_string(), - amount: coin(100, BONDED_DENOM), - }, - ) - .unwrap_err(); - assert_eq!( - e.to_string(), - "no delegation for (address, validator) tuple" - ); - } + assert_eq!( + e.to_string(), + "cannot delegate coins of denominator FAKE, only of TOKEN", + ); + } - #[test] - fn denom_validation() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + #[test] + fn cannot_slash_nonexistent() { + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); - let validator_addr_1 = env.validator_addr_1(); - let delegator_addr_1 = env.delegator_addr_1(); + let non_existing_validator_addr = env.validator_addr_3(); + let delegator_addr_1 = env.delegator_addr_1(); - // fund delegator account - env.router - .bank - .init_balance(&mut env.store, &delegator_addr_1, vec![coin(100, "FAKE")]) - .unwrap(); + // fund delegator account + env.router + .bank + .init_balance(&mut env.store, &delegator_addr_1, vec![coin(100, "FAKE")]) + .unwrap(); - // try to delegate 100 to validator - let e = execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Delegate { - validator: validator_addr_1.to_string(), - amount: coin(100, "FAKE"), + // try to delegate 100 to non existing validator + let e = env + .router + .staking + .sudo( + &env.api, + &mut env.store, + &env.router, + &env.block, + StakingSudo::Slash { + validator: non_existing_validator_addr.to_string(), + percentage: Decimal::percent(50), }, ) .unwrap_err(); - assert_eq!( - e.to_string(), - "cannot delegate coins of denominator FAKE, only of TOKEN", - ); - } + assert_eq!(e.to_string(), "validator does not exist"); + } - #[test] - fn cannot_slash_nonexistent() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + #[test] + fn non_existent_validator() { + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); - let non_existing_validator_addr = env.validator_addr_3(); - let delegator_addr_1 = env.delegator_addr_1(); + let non_existing_validator_addr = env.validator_addr_3(); + let delegator_addr_1 = env.delegator_addr_1(); - // fund delegator account - env.router - .bank - .init_balance(&mut env.store, &delegator_addr_1, vec![coin(100, "FAKE")]) - .unwrap(); + // init balances + env.router + .bank + .init_balance( + &mut env.store, + &delegator_addr_1, + vec![coin(100, BONDED_DENOM)], + ) + .unwrap(); - // try to delegate 100 to non existing validator - let e = env - .router - .staking - .sudo( - &env.api, - &mut env.store, - &env.router, - &env.block, - StakingSudo::Slash { - validator: non_existing_validator_addr.to_string(), - percentage: Decimal::percent(50), - }, - ) - .unwrap_err(); + // try to delegate + let err = execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Delegate { + validator: non_existing_validator_addr.to_string(), + amount: coin(100, BONDED_DENOM), + }, + ) + .unwrap_err(); + assert_eq!(err.to_string(), "validator does not exist"); + + // try to undelegate + let err = execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Undelegate { + validator: non_existing_validator_addr.to_string(), + amount: coin(100, BONDED_DENOM), + }, + ) + .unwrap_err(); + assert_eq!(err.to_string(), "validator does not exist"); + } - assert_eq!(e.to_string(), "validator does not exist"); - } + #[test] + fn zero_staking_forbidden() { + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); - #[test] - fn non_existent_validator() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); + + // delegate 0 + let err = execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Delegate { + validator: validator_addr_1.to_string(), + amount: coin(0, BONDED_DENOM), + }, + ) + .unwrap_err(); + assert_eq!(err.to_string(), "invalid delegation amount"); + + // undelegate 0 + let err = execute_stake( + &mut env, + delegator_addr_1, + StakingMsg::Undelegate { + validator: validator_addr_1.to_string(), + amount: coin(0, BONDED_DENOM), + }, + ) + .unwrap_err(); + assert_eq!(err.to_string(), "invalid shares amount"); + } - let non_existing_validator_addr = env.validator_addr_3(); - let delegator_addr_1 = env.delegator_addr_1(); + #[test] + fn query_staking() { + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 1, 1))); - // init balances - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(100, BONDED_DENOM)], - ) - .unwrap(); + let validator_addr_1 = env.validator_addr_1(); + let validator_addr_2 = env.validator_addr_2(); + let delegator_addr_1 = env.delegator_addr_1(); + let delegator_addr_2 = env.delegator_addr_2(); + let not_validator_addr = env.user_addr_1(); - // try to delegate - let err = execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Delegate { - validator: non_existing_validator_addr.to_string(), - amount: coin(100, BONDED_DENOM), - }, - ) - .unwrap_err(); - assert_eq!(err.to_string(), "validator does not exist"); - - // try to undelegate - let err = execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Undelegate { - validator: non_existing_validator_addr.to_string(), - amount: coin(100, BONDED_DENOM), - }, - ) - .unwrap_err(); - assert_eq!(err.to_string(), "validator does not exist"); - } - - #[test] - fn zero_staking_forbidden() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); - - let validator_addr_1 = env.validator_addr_1(); - let delegator_addr_1 = env.delegator_addr_1(); - - // delegate 0 - let err = execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Delegate { - validator: validator_addr_1.to_string(), - amount: coin(0, BONDED_DENOM), - }, - ) - .unwrap_err(); - assert_eq!(err.to_string(), "invalid delegation amount"); - - // undelegate 0 - let err = execute_stake( - &mut env, - delegator_addr_1, - StakingMsg::Undelegate { - validator: validator_addr_1.to_string(), - amount: coin(0, BONDED_DENOM), - }, - ) - .unwrap_err(); - assert_eq!(err.to_string(), "invalid shares amount"); - } - - #[test] - fn query_staking() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 1, 1))); - - let validator_addr_1 = env.validator_addr_1(); - let validator_addr_2 = env.validator_addr_2(); - let delegator_addr_1 = env.delegator_addr_1(); - let delegator_addr_2 = env.delegator_addr_2(); - let not_validator_addr = env.user_addr_1(); - - // init balances - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(260, BONDED_DENOM)], - ) - .unwrap(); - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_2, - vec![coin(150, BONDED_DENOM)], - ) - .unwrap(); - - // query validators - let valoper1: ValidatorResponse = query_stake( - &env, - StakingQuery::Validator { - address: validator_addr_1.to_string(), - }, + // init balances + env.router + .bank + .init_balance( + &mut env.store, + &delegator_addr_1, + vec![coin(260, BONDED_DENOM)], ) .unwrap(); - let valoper2: ValidatorResponse = query_stake( - &env, - StakingQuery::Validator { - address: validator_addr_2.to_string(), - }, + env.router + .bank + .init_balance( + &mut env.store, + &delegator_addr_2, + vec![coin(150, BONDED_DENOM)], ) .unwrap(); - let validators: AllValidatorsResponse = - query_stake(&env, StakingQuery::AllValidators {}).unwrap(); - assert_eq!( - validators.validators, - [valoper1.validator.unwrap(), valoper2.validator.unwrap()] - ); - - // query non-existent validator - let response = query_stake::( - &env, - StakingQuery::Validator { - address: not_validator_addr.to_string(), - }, - ) - .unwrap(); - assert_eq!(response.validator, None); + // query validators + let valoper1: ValidatorResponse = query_stake( + &env, + StakingQuery::Validator { + address: validator_addr_1.to_string(), + }, + ) + .unwrap(); + let valoper2: ValidatorResponse = query_stake( + &env, + StakingQuery::Validator { + address: validator_addr_2.to_string(), + }, + ) + .unwrap(); - // query bonded denom - let response: BondedDenomResponse = - query_stake(&env, StakingQuery::BondedDenom {}).unwrap(); - assert_eq!(response.denom, BONDED_DENOM); + let validators: AllValidatorsResponse = + query_stake(&env, StakingQuery::AllValidators {}).unwrap(); + assert_eq!( + validators.validators, + [valoper1.validator.unwrap(), valoper2.validator.unwrap()] + ); - // delegate some tokens with delegator1 and delegator2 - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Delegate { - validator: validator_addr_1.to_string(), - amount: coin(100, BONDED_DENOM), - }, - ) - .unwrap(); - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Delegate { - validator: validator_addr_2.to_string(), - amount: coin(160, BONDED_DENOM), - }, - ) - .unwrap(); - execute_stake( - &mut env, - delegator_addr_2.clone(), - StakingMsg::Delegate { - validator: validator_addr_1.to_string(), - amount: coin(150, BONDED_DENOM), - }, - ) - .unwrap(); - // unstake some again - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Undelegate { - validator: validator_addr_1.to_string(), - amount: coin(50, BONDED_DENOM), - }, - ) - .unwrap(); - execute_stake( - &mut env, - delegator_addr_2.clone(), - StakingMsg::Undelegate { - validator: validator_addr_1.to_string(), - amount: coin(50, BONDED_DENOM), - }, - ) - .unwrap(); + // query non-existent validator + let response = query_stake::( + &env, + StakingQuery::Validator { + address: not_validator_addr.to_string(), + }, + ) + .unwrap(); + assert_eq!(response.validator, None); + + // query bonded denom + let response: BondedDenomResponse = + query_stake(&env, StakingQuery::BondedDenom {}).unwrap(); + assert_eq!(response.denom, BONDED_DENOM); + + // delegate some tokens with delegator1 and delegator2 + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Delegate { + validator: validator_addr_1.to_string(), + amount: coin(100, BONDED_DENOM), + }, + ) + .unwrap(); + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Delegate { + validator: validator_addr_2.to_string(), + amount: coin(160, BONDED_DENOM), + }, + ) + .unwrap(); + execute_stake( + &mut env, + delegator_addr_2.clone(), + StakingMsg::Delegate { + validator: validator_addr_1.to_string(), + amount: coin(150, BONDED_DENOM), + }, + ) + .unwrap(); + // unstake some again + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Undelegate { + validator: validator_addr_1.to_string(), + amount: coin(50, BONDED_DENOM), + }, + ) + .unwrap(); + execute_stake( + &mut env, + delegator_addr_2.clone(), + StakingMsg::Undelegate { + validator: validator_addr_1.to_string(), + amount: coin(50, BONDED_DENOM), + }, + ) + .unwrap(); - // query all delegations - let response1: AllDelegationsResponse = query_stake( - &env, - StakingQuery::AllDelegations { - delegator: delegator_addr_1.to_string(), - }, - ) - .unwrap(); - assert_eq!( - response1.delegations, - vec![ - Delegation::new( - delegator_addr_1.clone(), - validator_addr_1.to_string(), - coin(50, BONDED_DENOM), - ), - Delegation::new( - delegator_addr_1.clone(), - validator_addr_2.to_string(), - coin(160, BONDED_DENOM), - ), - ] - ); - let response2: DelegationResponse = query_stake( - &env, - StakingQuery::Delegation { - delegator: delegator_addr_2.to_string(), - validator: validator_addr_1.to_string(), - }, - ) - .unwrap(); - assert_eq!( - response2.delegation.unwrap(), - FullDelegation::new( - delegator_addr_2.clone(), + // query all delegations + let response1: AllDelegationsResponse = query_stake( + &env, + StakingQuery::AllDelegations { + delegator: delegator_addr_1.to_string(), + }, + ) + .unwrap(); + assert_eq!( + response1.delegations, + vec![ + Delegation::new( + delegator_addr_1.clone(), validator_addr_1.to_string(), - coin(100, BONDED_DENOM), - coin(100, BONDED_DENOM), - vec![], + coin(50, BONDED_DENOM), ), - ); - } - - #[test] - fn delegation_queries_unbonding() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + Delegation::new( + delegator_addr_1.clone(), + validator_addr_2.to_string(), + coin(160, BONDED_DENOM), + ), + ] + ); + let response2: DelegationResponse = query_stake( + &env, + StakingQuery::Delegation { + delegator: delegator_addr_2.to_string(), + validator: validator_addr_1.to_string(), + }, + ) + .unwrap(); + assert_eq!( + response2.delegation.unwrap(), + FullDelegation::new( + delegator_addr_2.clone(), + validator_addr_1.to_string(), + coin(100, BONDED_DENOM), + coin(100, BONDED_DENOM), + vec![], + ), + ); + } - let validator_addr_1 = env.validator_addr_1(); - let delegator_addr_1 = env.delegator_addr_1(); - let delegator_addr_2 = env.delegator_addr_2(); + #[test] + fn delegation_queries_unbonding() { + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); - // init balances - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(100, BONDED_DENOM)], - ) - .unwrap(); - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_2, - vec![coin(150, BONDED_DENOM)], - ) - .unwrap(); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); + let delegator_addr_2 = env.delegator_addr_2(); - // delegate some tokens with delegator1 and delegator2 - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Delegate { - validator: validator_addr_1.to_string(), - amount: coin(100, BONDED_DENOM), - }, - ) - .unwrap(); - execute_stake( - &mut env, - delegator_addr_2.clone(), - StakingMsg::Delegate { - validator: validator_addr_1.to_string(), - amount: coin(150, BONDED_DENOM), - }, - ) - .unwrap(); - // unstake some of delegator1's stake - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Undelegate { - validator: validator_addr_1.to_string(), - amount: coin(50, BONDED_DENOM), - }, + // init balances + env.router + .bank + .init_balance( + &mut env.store, + &delegator_addr_1, + vec![coin(100, BONDED_DENOM)], ) .unwrap(); - // unstake all of delegator2's stake - execute_stake( - &mut env, - delegator_addr_2.clone(), - StakingMsg::Undelegate { - validator: validator_addr_1.to_string(), - amount: coin(150, BONDED_DENOM), - }, + env.router + .bank + .init_balance( + &mut env.store, + &delegator_addr_2, + vec![coin(150, BONDED_DENOM)], ) .unwrap(); - // query all delegations - let response1: AllDelegationsResponse = query_stake( - &env, - StakingQuery::AllDelegations { - delegator: delegator_addr_1.to_string(), - }, - ) - .unwrap(); - assert_eq!( - response1.delegations, - vec![Delegation::new( - delegator_addr_1.clone(), - validator_addr_1.to_string(), - coin(50, BONDED_DENOM), - )] - ); - let response2: DelegationResponse = query_stake( - &env, - StakingQuery::Delegation { - delegator: delegator_addr_2.to_string(), - validator: validator_addr_1.to_string(), - }, - ) - .unwrap(); - assert_eq!(response2.delegation, None); + // delegate some tokens with delegator1 and delegator2 + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Delegate { + validator: validator_addr_1.to_string(), + amount: coin(100, BONDED_DENOM), + }, + ) + .unwrap(); + execute_stake( + &mut env, + delegator_addr_2.clone(), + StakingMsg::Delegate { + validator: validator_addr_1.to_string(), + amount: coin(150, BONDED_DENOM), + }, + ) + .unwrap(); + // unstake some of delegator1's stake + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Undelegate { + validator: validator_addr_1.to_string(), + amount: coin(50, BONDED_DENOM), + }, + ) + .unwrap(); + // unstake all of delegator2's stake + execute_stake( + &mut env, + delegator_addr_2.clone(), + StakingMsg::Undelegate { + validator: validator_addr_1.to_string(), + amount: coin(150, BONDED_DENOM), + }, + ) + .unwrap(); - // unstake rest of delegator1's stake in two steps - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Undelegate { - validator: validator_addr_1.to_string(), - amount: coin(25, BONDED_DENOM), - }, - ) - .unwrap(); - env.block.time = env.block.time.plus_seconds(10); - execute_stake( - &mut env, + // query all delegations + let response1: AllDelegationsResponse = query_stake( + &env, + StakingQuery::AllDelegations { + delegator: delegator_addr_1.to_string(), + }, + ) + .unwrap(); + assert_eq!( + response1.delegations, + vec![Delegation::new( delegator_addr_1.clone(), - StakingMsg::Undelegate { - validator: validator_addr_1.to_string(), - amount: coin(25, BONDED_DENOM), - }, - ) - .unwrap(); - - // query all delegations again - let response1: DelegationResponse = query_stake( - &env, - StakingQuery::Delegation { - delegator: delegator_addr_1.to_string(), - validator: validator_addr_1.to_string(), - }, - ) - .unwrap(); - let response2: AllDelegationsResponse = query_stake( - &env, - StakingQuery::AllDelegations { - delegator: delegator_addr_1.to_string(), - }, - ) - .unwrap(); - assert_eq!( - response1.delegation, None, - "delegator1 should have no delegations left" - ); - assert_eq!(response2.delegations, vec![]); - } + validator_addr_1.to_string(), + coin(50, BONDED_DENOM), + )] + ); + let response2: DelegationResponse = query_stake( + &env, + StakingQuery::Delegation { + delegator: delegator_addr_2.to_string(), + validator: validator_addr_1.to_string(), + }, + ) + .unwrap(); + assert_eq!(response2.delegation, None); + + // unstake rest of delegator1's stake in two steps + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Undelegate { + validator: validator_addr_1.to_string(), + amount: coin(25, BONDED_DENOM), + }, + ) + .unwrap(); + env.block.time = env.block.time.plus_seconds(10); + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Undelegate { + validator: validator_addr_1.to_string(), + amount: coin(25, BONDED_DENOM), + }, + ) + .unwrap(); - #[test] - fn partial_unbonding_reduces_stake() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + // query all delegations again + let response1: DelegationResponse = query_stake( + &env, + StakingQuery::Delegation { + delegator: delegator_addr_1.to_string(), + validator: validator_addr_1.to_string(), + }, + ) + .unwrap(); + let response2: AllDelegationsResponse = query_stake( + &env, + StakingQuery::AllDelegations { + delegator: delegator_addr_1.to_string(), + }, + ) + .unwrap(); + assert_eq!( + response1.delegation, None, + "delegator1 should have no delegations left" + ); + assert_eq!(response2.delegations, vec![]); + } - let validator_addr_1 = env.validator_addr_1(); - let delegator_addr_1 = env.delegator_addr_1(); + #[test] + fn partial_unbonding_reduces_stake() { + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); - // init balance - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(100, BONDED_DENOM)], - ) - .unwrap(); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); - // delegate all tokens - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Delegate { - validator: validator_addr_1.to_string(), - amount: coin(100, BONDED_DENOM), - }, - ) - .unwrap(); - // unstake in multiple steps - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Undelegate { - validator: validator_addr_1.to_string(), - amount: coin(50, BONDED_DENOM), - }, - ) - .unwrap(); - env.block.time = env.block.time.plus_seconds(10); - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Undelegate { - validator: validator_addr_1.to_string(), - amount: coin(30, BONDED_DENOM), - }, - ) - .unwrap(); - env.block.time = env.block.time.plus_seconds(10); - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Undelegate { - validator: validator_addr_1.to_string(), - amount: coin(20, BONDED_DENOM), - }, + // init balance + env.router + .bank + .init_balance( + &mut env.store, + &delegator_addr_1, + vec![coin(100, BONDED_DENOM)], ) .unwrap(); - // wait for first unbonding to complete (but not the others) and process queue - env.block.time = env.block.time.plus_seconds(40); - env.router - .staking - .process_queue(&env.api, &mut env.store, &env.router, &env.block) - .unwrap(); + // delegate all tokens + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Delegate { + validator: validator_addr_1.to_string(), + amount: coin(100, BONDED_DENOM), + }, + ) + .unwrap(); + // unstake in multiple steps + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Undelegate { + validator: validator_addr_1.to_string(), + amount: coin(50, BONDED_DENOM), + }, + ) + .unwrap(); + env.block.time = env.block.time.plus_seconds(10); + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Undelegate { + validator: validator_addr_1.to_string(), + amount: coin(30, BONDED_DENOM), + }, + ) + .unwrap(); + env.block.time = env.block.time.plus_seconds(10); + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Undelegate { + validator: validator_addr_1.to_string(), + amount: coin(20, BONDED_DENOM), + }, + ) + .unwrap(); - // query delegations - // we now have 0 stake, 50 unbonding and 50 completed unbonding - let response1: DelegationResponse = query_stake( - &env, - StakingQuery::Delegation { - delegator: delegator_addr_1.to_string(), - validator: validator_addr_1.to_string(), - }, - ) - .unwrap(); - let response2: AllDelegationsResponse = query_stake( - &env, - StakingQuery::AllDelegations { - delegator: delegator_addr_1.to_string(), - }, - ) + // wait for first unbonding to complete (but not the others) and process queue + env.block.time = env.block.time.plus_seconds(40); + env.router + .staking + .process_queue(&env.api, &mut env.store, &env.router, &env.block) .unwrap(); - assert_eq!(response1.delegation, None); - assert_eq!(response2.delegations, vec![]); - // wait for the rest to complete - env.block.time = env.block.time.plus_seconds(20); - env.router - .staking - .process_queue(&env.api, &mut env.store, &env.router, &env.block) - .unwrap(); + // query delegations + // we now have 0 stake, 50 unbonding and 50 completed unbonding + let response1: DelegationResponse = query_stake( + &env, + StakingQuery::Delegation { + delegator: delegator_addr_1.to_string(), + validator: validator_addr_1.to_string(), + }, + ) + .unwrap(); + let response2: AllDelegationsResponse = query_stake( + &env, + StakingQuery::AllDelegations { + delegator: delegator_addr_1.to_string(), + }, + ) + .unwrap(); + assert_eq!(response1.delegation, None); + assert_eq!(response2.delegations, vec![]); - // query delegations again - let response1: DelegationResponse = query_stake( - &env, - StakingQuery::Delegation { - delegator: delegator_addr_1.to_string(), - validator: validator_addr_1.to_string(), - }, - ) - .unwrap(); - let response2: AllDelegationsResponse = query_stake( - &env, - StakingQuery::AllDelegations { - delegator: delegator_addr_1.to_string(), - }, - ) + // wait for the rest to complete + env.block.time = env.block.time.plus_seconds(20); + env.router + .staking + .process_queue(&env.api, &mut env.store, &env.router, &env.block) .unwrap(); - assert_eq!( - response1.delegation, None, - "delegator should have nothing left" - ); - assert!(response2.delegations.is_empty()); - } - #[test] - fn delegations_slashed() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + // query delegations again + let response1: DelegationResponse = query_stake( + &env, + StakingQuery::Delegation { + delegator: delegator_addr_1.to_string(), + validator: validator_addr_1.to_string(), + }, + ) + .unwrap(); + let response2: AllDelegationsResponse = query_stake( + &env, + StakingQuery::AllDelegations { + delegator: delegator_addr_1.to_string(), + }, + ) + .unwrap(); + assert_eq!( + response1.delegation, None, + "delegator should have nothing left" + ); + assert!(response2.delegations.is_empty()); + } - let validator_addr_1 = env.validator_addr_1(); - let delegator_addr_1 = env.delegator_addr_1(); + #[test] + fn delegations_slashed() { + let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); - // init balance - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(333, BONDED_DENOM)], - ) - .unwrap(); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); - // delegate some tokens - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Delegate { - validator: validator_addr_1.to_string(), - amount: coin(333, BONDED_DENOM), - }, + // init balance + env.router + .bank + .init_balance( + &mut env.store, + &delegator_addr_1, + vec![coin(333, BONDED_DENOM)], ) .unwrap(); - // unstake some - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Undelegate { + + // delegate some tokens + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Delegate { + validator: validator_addr_1.to_string(), + amount: coin(333, BONDED_DENOM), + }, + ) + .unwrap(); + // unstake some + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Undelegate { + validator: validator_addr_1.to_string(), + amount: coin(111, BONDED_DENOM), + }, + ) + .unwrap(); + + // slash validator + env.router + .staking + .sudo( + &env.api, + &mut env.store, + &env.router, + &env.block, + StakingSudo::Slash { validator: validator_addr_1.to_string(), - amount: coin(111, BONDED_DENOM), + percentage: Decimal::percent(50), }, ) .unwrap(); - // slash validator - env.router - .staking - .sudo( - &env.api, - &mut env.store, - &env.router, - &env.block, - StakingSudo::Slash { - validator: validator_addr_1.to_string(), - percentage: Decimal::percent(50), - }, - ) - .unwrap(); - - // query all delegations - let response1: AllDelegationsResponse = query_stake( - &env, - StakingQuery::AllDelegations { - delegator: delegator_addr_1.to_string(), - }, + // query all delegations + let response1: AllDelegationsResponse = query_stake( + &env, + StakingQuery::AllDelegations { + delegator: delegator_addr_1.to_string(), + }, + ) + .unwrap(); + assert_eq!( + response1.delegations[0], + Delegation::new( + delegator_addr_1.clone(), + validator_addr_1.to_string(), + coin(111, BONDED_DENOM), ) - .unwrap(); - assert_eq!( - response1.delegations[0], - Delegation::new( - delegator_addr_1.clone(), - validator_addr_1.to_string(), - coin(111, BONDED_DENOM), - ) - ); + ); - // wait until unbonding is complete and check if amount was slashed - env.block.time = env.block.time.plus_seconds(60); - env.router - .staking - .process_queue(&env.api, &mut env.store, &env.router, &env.block) + // wait until unbonding is complete and check if amount was slashed + env.block.time = env.block.time.plus_seconds(60); + env.router + .staking + .process_queue(&env.api, &mut env.store, &env.router, &env.block) + .unwrap(); + let balance = + QuerierWrapper::::new(&env.router.querier(&env.api, &env.store, &env.block)) + .query_balance(delegator_addr_1, BONDED_DENOM) .unwrap(); - let balance = - QuerierWrapper::::new(&env.router.querier(&env.api, &env.store, &env.block)) - .query_balance(delegator_addr_1, BONDED_DENOM) - .unwrap(); - assert_eq!(balance.amount.u128(), 55); - } - - #[test] - fn rewards_initial_wait() { - let mut env = TestEnv::wrap(TestEnv::setup((0, 100, 1), (10, 100, 1))); - - let validator_addr_1 = env.validator_addr_1(); - let delegator_addr_1 = env.delegator_addr_1(); + assert_eq!(balance.amount.u128(), 55); + } - // initialize balances for delegator - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(100, BONDED_DENOM)], - ) - .unwrap(); + #[test] + fn rewards_initial_wait() { + let mut env = TestEnv::wrap(TestEnv::setup((0, 100, 1), (10, 100, 1))); - // wait one year before staking - env.block.time = env.block.time.plus_seconds(YEAR); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); - // stake (delegate) some tokens to validator - execute_stake( - &mut env, - delegator_addr_1.clone(), - StakingMsg::Delegate { - validator: validator_addr_1.to_string(), - amount: coin(100, BONDED_DENOM), - }, + // initialize balances for delegator + env.router + .bank + .init_balance( + &mut env.store, + &delegator_addr_1, + vec![coin(100, BONDED_DENOM)], ) .unwrap(); - // wait another year - env.block.time = env.block.time.plus_seconds(YEAR); + // wait one year before staking + env.block.time = env.block.time.plus_seconds(YEAR); - // query rewards - let response: DelegationResponse = query_stake( - &env, - StakingQuery::Delegation { - delegator: delegator_addr_1.to_string(), - validator: validator_addr_1.to_string(), - }, - ) - .unwrap(); + // stake (delegate) some tokens to validator + execute_stake( + &mut env, + delegator_addr_1.clone(), + StakingMsg::Delegate { + validator: validator_addr_1.to_string(), + amount: coin(100, BONDED_DENOM), + }, + ) + .unwrap(); - assert_eq!( - response.delegation.unwrap().accumulated_rewards, - vec![coin(10, BONDED_DENOM)] // 10% of 100 - ); - } + // wait another year + env.block.time = env.block.time.plus_seconds(YEAR); + + // query rewards + let response: DelegationResponse = query_stake( + &env, + StakingQuery::Delegation { + delegator: delegator_addr_1.to_string(), + validator: validator_addr_1.to_string(), + }, + ) + .unwrap(); + + assert_eq!( + response.delegation.unwrap().accumulated_rewards, + vec![coin(10, BONDED_DENOM)] // 10% of 100 + ); } } From fb780d84e97df01ce23cce463a42ec83e1159372 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 14 Jun 2024 14:43:24 +0200 Subject: [PATCH 221/250] Refactored (unified) variable names. --- src/staking.rs | 100 ++++++++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index d4f14b16..ef49a7df 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1245,11 +1245,11 @@ mod test { fn add_get_validators() { let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 20, 1))); - let validator_addr = env.validator_addr_3(); + let validator_addr_3 = env.validator_addr_3(); // add a new validator (validator no. 3 does not exist yet) let validator = Validator::new( - validator_addr.to_string(), + validator_addr_3.to_string(), Decimal::percent(10), Decimal::percent(20), Decimal::percent(1), @@ -1264,14 +1264,14 @@ mod test { let val = env .router .staking - .get_validator(&staking_storage, &validator_addr) + .get_validator(&staking_storage, &validator_addr_3) .unwrap() .unwrap(); assert_eq!(val, validator); // try to add a validator with same address (validator no. 3) let validator_fake = Validator::new( - validator_addr.to_string(), + validator_addr_3.to_string(), Decimal::percent(1), Decimal::percent(10), Decimal::percent(100), @@ -1286,7 +1286,7 @@ mod test { let val = env .router .staking - .get_validator(&staking_storage, &validator_addr) + .get_validator(&staking_storage, &validator_addr_3) .unwrap() .unwrap(); assert_eq!(val, validator); @@ -1296,8 +1296,8 @@ mod test { fn validator_slashing() { let mut env = TestEnv::wrap(TestEnv::setup((10, 20, 1), (10, 20, 1))); - let validator_addr = env.validator_addr_1(); - let delegator_addr = env.delegator_addr_1(); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); // stake (delegate) 100 tokens from delegator to validator let mut staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); @@ -1307,8 +1307,8 @@ mod test { &env.api, &mut staking_storage, &env.block, - &delegator_addr, - &validator_addr, + &delegator_addr_1, + &validator_addr_1, coin(100, BONDED_DENOM), ) .unwrap(); @@ -1322,7 +1322,7 @@ mod test { &env.router, &env.block, StakingSudo::Slash { - validator: validator_addr.to_string(), + validator: validator_addr_1.to_string(), percentage: Decimal::percent(50), }, ) @@ -1333,7 +1333,7 @@ mod test { let stake_left = env .router .staking - .get_stake(&staking_storage, &delegator_addr, &validator_addr) + .get_stake(&staking_storage, &delegator_addr_1, &validator_addr_1) .unwrap() .unwrap(); assert_eq!(50, stake_left.amount.u128()); @@ -1347,7 +1347,7 @@ mod test { &env.router, &env.block, StakingSudo::Slash { - validator: validator_addr.to_string(), + validator: validator_addr_1.to_string(), percentage: Decimal::percent(100), }, ) @@ -1358,7 +1358,7 @@ mod test { let stake_left = env .router .staking - .get_stake(&staking_storage, &delegator_addr, &validator_addr) + .get_stake(&staking_storage, &delegator_addr_1, &validator_addr_1) .unwrap(); assert_eq!(None, stake_left); } @@ -1367,8 +1367,8 @@ mod test { fn rewards_work_for_single_delegator() { let mut env = TestEnv::wrap(TestEnv::setup((10, 20, 1), (10, 20, 1))); - let validator_addr = env.validator_addr_1(); - let delegator_addr = env.delegator_addr_1(); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); let mut staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); // stake 200 tokens @@ -1378,8 +1378,8 @@ mod test { &env.api, &mut staking_storage, &env.block, - &delegator_addr, - &validator_addr, + &delegator_addr_1, + &validator_addr_1, coin(200, BONDED_DENOM), ) .unwrap(); @@ -1391,7 +1391,7 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator_addr, &validator_addr) + .get_rewards(&env.store, &env.block, &delegator_addr_1, &validator_addr_1) .unwrap() .unwrap(); assert_eq!(9, rewards.amount.u128()); @@ -1404,9 +1404,9 @@ mod test { &mut env.store, &env.router, &env.block, - delegator_addr.clone(), + delegator_addr_1.clone(), DistributionMsg::WithdrawDelegatorReward { - validator: validator_addr.to_string(), + validator: validator_addr_1.to_string(), }, ) .unwrap(); @@ -1415,7 +1415,7 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator_addr, &validator_addr) + .get_rewards(&env.store, &env.block, &delegator_addr_1, &validator_addr_1) .unwrap() .unwrap(); assert_eq!(0, rewards.amount.u128()); @@ -1426,7 +1426,7 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator_addr, &validator_addr) + .get_rewards(&env.store, &env.block, &delegator_addr_1, &validator_addr_1) .unwrap() .unwrap(); assert_eq!(9, rewards.amount.u128()); @@ -1436,9 +1436,9 @@ mod test { fn rewards_work_for_multiple_delegators() { let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); - let validator = env.validator_addr_1(); - let delegator1 = env.delegator_addr_1(); - let delegator2 = env.delegator_addr_2(); + let validator_addr_1 = env.validator_addr_1(); + let delegator_addr_1 = env.delegator_addr_1(); + let delegator_addr_2 = env.delegator_addr_2(); let mut staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); @@ -1449,8 +1449,8 @@ mod test { &env.api, &mut staking_storage, &env.block, - &delegator1, - &validator, + &delegator_addr_1, + &validator_addr_1, coin(100, BONDED_DENOM), ) .unwrap(); @@ -1460,8 +1460,8 @@ mod test { &env.api, &mut staking_storage, &env.block, - &delegator2, - &validator, + &delegator_addr_2, + &validator_addr_1, coin(200, BONDED_DENOM), ) .unwrap(); @@ -1473,7 +1473,7 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator1, &validator) + .get_rewards(&env.store, &env.block, &delegator_addr_1, &validator_addr_1) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 9); @@ -1482,7 +1482,7 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator2, &validator) + .get_rewards(&env.store, &env.block, &delegator_addr_2, &validator_addr_1) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 18); @@ -1495,8 +1495,8 @@ mod test { &env.api, &mut staking_storage, &env.block, - &delegator1, - &validator, + &delegator_addr_1, + &validator_addr_1, coin(100, BONDED_DENOM), ) .unwrap(); @@ -1508,7 +1508,7 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator1, &validator) + .get_rewards(&env.store, &env.block, &delegator_addr_1, &validator_addr_1) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 27); @@ -1517,7 +1517,7 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator2, &validator) + .get_rewards(&env.store, &env.block, &delegator_addr_2, &validator_addr_1) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 36); @@ -1530,8 +1530,8 @@ mod test { &env.api, &mut staking_storage, &env.block, - &delegator2, - &validator, + &delegator_addr_2, + &validator_addr_1, coin(100, BONDED_DENOM), ) .unwrap(); @@ -1544,9 +1544,9 @@ mod test { &mut env.store, &env.router, &env.block, - delegator1.clone(), + delegator_addr_1.clone(), DistributionMsg::WithdrawDelegatorReward { - validator: validator.to_string(), + validator: validator_addr_1.to_string(), }, ) .unwrap(); @@ -1560,7 +1560,7 @@ mod test { &env.router.querier(&env.api, &env.store, &env.block), &env.block, BankQuery::Balance { - address: delegator1.to_string(), + address: delegator_addr_1.to_string(), denom: BONDED_DENOM.to_string(), }, ) @@ -1572,7 +1572,7 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator1, &validator) + .get_rewards(&env.store, &env.block, &delegator_addr_1, &validator_addr_1) .unwrap() .unwrap(); assert_eq!(0, rewards.amount.u128()); @@ -1584,7 +1584,7 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator1, &validator) + .get_rewards(&env.store, &env.block, &delegator_addr_1, &validator_addr_1) .unwrap() .unwrap(); assert_eq!(18, rewards.amount.u128()); @@ -1593,7 +1593,7 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator2, &validator) + .get_rewards(&env.store, &env.block, &delegator_addr_2, &validator_addr_1) .unwrap() .unwrap(); assert_eq!(45, rewards.amount.u128()); @@ -1904,7 +1904,7 @@ mod test { fn cannot_slash_nonexistent() { let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); - let non_existing_validator_addr = env.validator_addr_3(); + let validator_addr_3 = env.validator_addr_3(); let delegator_addr_1 = env.delegator_addr_1(); // fund delegator account @@ -1923,7 +1923,7 @@ mod test { &env.router, &env.block, StakingSudo::Slash { - validator: non_existing_validator_addr.to_string(), + validator: validator_addr_3.to_string(), percentage: Decimal::percent(50), }, ) @@ -1936,7 +1936,7 @@ mod test { fn non_existent_validator() { let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); - let non_existing_validator_addr = env.validator_addr_3(); + let validator_addr_3 = env.validator_addr_3(); let delegator_addr_1 = env.delegator_addr_1(); // init balances @@ -1954,7 +1954,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { - validator: non_existing_validator_addr.to_string(), + validator: validator_addr_3.to_string(), amount: coin(100, BONDED_DENOM), }, ) @@ -1966,7 +1966,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: non_existing_validator_addr.to_string(), + validator: validator_addr_3.to_string(), amount: coin(100, BONDED_DENOM), }, ) @@ -2014,7 +2014,7 @@ mod test { let validator_addr_2 = env.validator_addr_2(); let delegator_addr_1 = env.delegator_addr_1(); let delegator_addr_2 = env.delegator_addr_2(); - let not_validator_addr = env.user_addr_1(); + let user_addr_1 = env.user_addr_1(); // init balances env.router @@ -2061,7 +2061,7 @@ mod test { let response = query_stake::( &env, StakingQuery::Validator { - address: not_validator_addr.to_string(), + address: user_addr_1.to_string(), }, ) .unwrap(); From e86217c146d95389f4475c4052cfe2f4691634f5 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 14 Jun 2024 14:57:08 +0200 Subject: [PATCH 222/250] Simplified test env. --- src/staking.rs | 80 +++++++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 47 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index ef49a7df..93c858cb 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1053,22 +1053,7 @@ mod test { StargateFailing, >; - fn mock_router() -> BasicRouter { - Router { - wasm: WasmKeeper::new(), - bank: BankKeeper::new(), - custom: FailingModule::new(), - staking: StakeKeeper::new(), - distribution: DistributionKeeper::new(), - ibc: IbcFailingModule::new(), - gov: GovFailingModule::new(), - stargate: StargateFailing, - } - } - - type TestTuple = (MockApi, MockStorage, BasicRouter, BlockInfo, Addr, Addr); - - // shortens tests a bit + /// Test environment that simplifies initialization of test cases. struct TestEnv { api: MockApi, store: MockStorage, @@ -1083,9 +1068,19 @@ mod test { } impl TestEnv { - fn setup(validator1: (u64, u64, u64), validator2: (u64, u64, u64)) -> TestTuple { + /// Returns preconfigured test environment. + fn new(validator1: (u64, u64, u64), validator2: (u64, u64, u64)) -> Self { let api = MockApi::default(); - let router = mock_router(); + let router = Router { + wasm: WasmKeeper::new(), + bank: BankKeeper::new(), + custom: FailingModule::new(), + staking: StakeKeeper::new(), + distribution: DistributionKeeper::new(), + ibc: IbcFailingModule::new(), + gov: GovFailingModule::new(), + stargate: StargateFailing, + }; let mut store = MockStorage::new(); let block = mock_env().block; @@ -1121,25 +1116,13 @@ mod test { .add_validator(&api, &mut store, &block, valoper2) .unwrap(); - ( + Self { api, store, router, block, validator_addr_1, validator_addr_2, - ) - } - - fn wrap(tuple: TestTuple) -> Self { - let api = tuple.0; - Self { - api, - store: tuple.1, - router: tuple.2, - block: tuple.3, - validator_addr_1: tuple.4, - validator_addr_2: tuple.5, validator_addr_3: api.addr_make("validator3"), delegator_addr_1: api.addr_make("delegator1"), delegator_addr_2: api.addr_make("delegator2"), @@ -1165,16 +1148,19 @@ mod test { self.validator_addr_3.clone() } + /// Returns address of the delegator no. 1. #[inline(always)] fn delegator_addr_1(&self) -> Addr { self.delegator_addr_1.clone() } + /// Returns address of the delegator no. 2. #[inline(always)] fn delegator_addr_2(&self) -> Addr { self.delegator_addr_2.clone() } + /// Returns address of the user no. 1. #[inline(always)] fn user_addr_1(&self) -> Addr { self.user_addr_1.clone() @@ -1243,7 +1229,7 @@ mod test { #[test] fn add_get_validators() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 20, 1))); + let mut env = TestEnv::new((10, 100, 1), (0, 20, 1)); let validator_addr_3 = env.validator_addr_3(); @@ -1294,7 +1280,7 @@ mod test { #[test] fn validator_slashing() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 20, 1), (10, 20, 1))); + let mut env = TestEnv::new((10, 20, 1), (10, 20, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1365,7 +1351,7 @@ mod test { #[test] fn rewards_work_for_single_delegator() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 20, 1), (10, 20, 1))); + let mut env = TestEnv::new((10, 20, 1), (10, 20, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1434,7 +1420,7 @@ mod test { #[test] fn rewards_work_for_multiple_delegators() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1601,7 +1587,7 @@ mod test { #[test] fn execute() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 20, 1))); + let mut env = TestEnv::new((10, 100, 1), (0, 20, 1)); let validator_addr_1 = env.validator_addr_1(); let validator_addr_2 = env.validator_addr_2(); @@ -1719,7 +1705,7 @@ mod test { #[test] fn can_set_withdraw_address() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1801,7 +1787,7 @@ mod test { #[test] fn cannot_steal() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 20, 1))); + let mut env = TestEnv::new((10, 100, 1), (0, 20, 1)); let validator_addr_1 = env.validator_addr_1(); let validator_addr_2 = env.validator_addr_2(); @@ -1872,7 +1858,7 @@ mod test { #[test] fn denom_validation() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1902,7 +1888,7 @@ mod test { #[test] fn cannot_slash_nonexistent() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); let validator_addr_3 = env.validator_addr_3(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1934,7 +1920,7 @@ mod test { #[test] fn non_existent_validator() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); let validator_addr_3 = env.validator_addr_3(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1976,7 +1962,7 @@ mod test { #[test] fn zero_staking_forbidden() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2008,7 +1994,7 @@ mod test { #[test] fn query_staking() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (0, 1, 1))); + let mut env = TestEnv::new((10, 100, 1), (0, 1, 1)); let validator_addr_1 = env.validator_addr_1(); let validator_addr_2 = env.validator_addr_2(); @@ -2165,7 +2151,7 @@ mod test { #[test] fn delegation_queries_unbonding() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2301,7 +2287,7 @@ mod test { #[test] fn partial_unbonding_reduces_stake() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2416,7 +2402,7 @@ mod test { #[test] fn delegations_slashed() { - let mut env = TestEnv::wrap(TestEnv::setup((10, 100, 1), (10, 100, 1))); + let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2499,7 +2485,7 @@ mod test { #[test] fn rewards_initial_wait() { - let mut env = TestEnv::wrap(TestEnv::setup((0, 100, 1), (10, 100, 1))); + let mut env = TestEnv::new((0, 100, 1), (10, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); From 56e9de8cb4a81ab18aba38bc589f3d09fcabff6a Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 14 Jun 2024 15:19:02 +0200 Subject: [PATCH 223/250] Refactored balances initialization. --- src/staking.rs | 154 ++++++++++++++----------------------------------- 1 file changed, 44 insertions(+), 110 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 93c858cb..9b6033f3 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1213,6 +1213,17 @@ mod test { )?)?) } + fn init_balance(env: &mut TestEnv, address: &Addr, amount: u128) { + init_balance_denom(env, address, amount, BONDED_DENOM); + } + + fn init_balance_denom(env: &mut TestEnv, address: &Addr, amount: u128, denom: &str) { + env.router + .bank + .init_balance(&mut env.store, address, coins(amount, denom)) + .unwrap(); + } + fn assert_balances(env: &TestEnv, balances: impl IntoIterator) { for (addr, amount) in balances { let balance: BalanceResponse = query_bank( @@ -1594,15 +1605,8 @@ mod test { let delegator_addr_1 = env.delegator_addr_2(); let reward_receiver_addr = env.user_addr_1(); - // initialize delegator account - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(1000, BONDED_DENOM)], - ) - .unwrap(); + // initialize balances + init_balance(&mut env, &delegator_addr_1, 1000); // delegate 100 tokens to validator 1 execute_stake( @@ -1711,12 +1715,10 @@ mod test { let delegator_addr_1 = env.delegator_addr_1(); let reward_receiver_addr = env.user_addr_1(); - env.router - .bank - .init_balance(&mut env.store, &delegator_addr_1, coins(100, BONDED_DENOM)) - .unwrap(); + // initialize balances + init_balance(&mut env, &delegator_addr_1, 100); - // Stake 100 tokens to the validator. + // stake (delegate) 100 tokens to the validator execute_stake( &mut env, delegator_addr_1.clone(), @@ -1727,7 +1729,7 @@ mod test { ) .unwrap(); - // Change rewards receiver. + // change the receiver of rewards execute_distr( &mut env, delegator_addr_1.clone(), @@ -1737,7 +1739,7 @@ mod test { ) .unwrap(); - // A year passes. + // let one year pass env.block.time = env.block.time.plus_seconds(YEAR); // Withdraw rewards to reward receiver. @@ -1793,15 +1795,8 @@ mod test { let validator_addr_2 = env.validator_addr_2(); let delegator_addr_1 = env.delegator_addr_1(); - // initialize delegator account - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(100, BONDED_DENOM)], - ) - .unwrap(); + // initialize balances + init_balance(&mut env, &delegator_addr_1, 100); // delegate 100 tokens to validator 1 execute_stake( @@ -1863,11 +1858,8 @@ mod test { let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); - // fund delegator account - env.router - .bank - .init_balance(&mut env.store, &delegator_addr_1, vec![coin(100, "FAKE")]) - .unwrap(); + // init balances + init_balance_denom(&mut env, &delegator_addr_1, 100, "FAKE"); // try to delegate 100 to validator let e = execute_stake( @@ -1893,11 +1885,8 @@ mod test { let validator_addr_3 = env.validator_addr_3(); let delegator_addr_1 = env.delegator_addr_1(); - // fund delegator account - env.router - .bank - .init_balance(&mut env.store, &delegator_addr_1, vec![coin(100, "FAKE")]) - .unwrap(); + // init balances + init_balance_denom(&mut env, &delegator_addr_1, 100, "FAKE"); // try to delegate 100 to non existing validator let e = env @@ -1925,15 +1914,8 @@ mod test { let validator_addr_3 = env.validator_addr_3(); let delegator_addr_1 = env.delegator_addr_1(); - // init balances - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(100, BONDED_DENOM)], - ) - .unwrap(); + // initialize balances + init_balance(&mut env, &delegator_addr_1, 100); // try to delegate let err = execute_stake( @@ -2002,23 +1984,9 @@ mod test { let delegator_addr_2 = env.delegator_addr_2(); let user_addr_1 = env.user_addr_1(); - // init balances - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(260, BONDED_DENOM)], - ) - .unwrap(); - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_2, - vec![coin(150, BONDED_DENOM)], - ) - .unwrap(); + // initialize balances + init_balance(&mut env, &delegator_addr_1, 260); + init_balance(&mut env, &delegator_addr_2, 150); // query validators let valoper1: ValidatorResponse = query_stake( @@ -2157,23 +2125,9 @@ mod test { let delegator_addr_1 = env.delegator_addr_1(); let delegator_addr_2 = env.delegator_addr_2(); - // init balances - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(100, BONDED_DENOM)], - ) - .unwrap(); - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_2, - vec![coin(150, BONDED_DENOM)], - ) - .unwrap(); + // initialize balances + init_balance(&mut env, &delegator_addr_1, 100); + init_balance(&mut env, &delegator_addr_2, 150); // delegate some tokens with delegator1 and delegator2 execute_stake( @@ -2292,15 +2246,8 @@ mod test { let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); - // init balance - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(100, BONDED_DENOM)], - ) - .unwrap(); + // initialize balances + init_balance(&mut env, &delegator_addr_1, 100); // delegate all tokens execute_stake( @@ -2407,17 +2354,10 @@ mod test { let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); - // init balance - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(333, BONDED_DENOM)], - ) - .unwrap(); + // initialize balances + init_balance(&mut env, &delegator_addr_1, 333); - // delegate some tokens + // stake (delegate) some tokens execute_stake( &mut env, delegator_addr_1.clone(), @@ -2427,7 +2367,8 @@ mod test { }, ) .unwrap(); - // unstake some + + // unstake (undelegate) some tokens execute_stake( &mut env, delegator_addr_1.clone(), @@ -2480,30 +2421,23 @@ mod test { QuerierWrapper::::new(&env.router.querier(&env.api, &env.store, &env.block)) .query_balance(delegator_addr_1, BONDED_DENOM) .unwrap(); - assert_eq!(balance.amount.u128(), 55); + assert_eq!(55, balance.amount.u128()); } #[test] fn rewards_initial_wait() { - let mut env = TestEnv::new((0, 100, 1), (10, 100, 1)); + let mut env = TestEnv::new((0, 100, 1), (0, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); - // initialize balances for delegator - env.router - .bank - .init_balance( - &mut env.store, - &delegator_addr_1, - vec![coin(100, BONDED_DENOM)], - ) - .unwrap(); + // initialize balances + init_balance(&mut env, &delegator_addr_1, 100); // wait one year before staking env.block.time = env.block.time.plus_seconds(YEAR); - // stake (delegate) some tokens to validator + // stake (delegate) 100 tokens to validator execute_stake( &mut env, delegator_addr_1.clone(), From 781321cc374a51f9d5dd5d2af59a3e045ce9702a Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 14 Jun 2024 15:24:07 +0200 Subject: [PATCH 224/250] Refactored variable names. --- src/staking.rs | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 9b6033f3..00055948 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1810,7 +1810,7 @@ mod test { .unwrap(); // undelegate more tokens than we have - let e = execute_stake( + let error_result = execute_stake( &mut env, delegator_addr_1.clone(), StakingMsg::Undelegate { @@ -1819,11 +1819,10 @@ mod test { }, ) .unwrap_err(); - - assert_eq!(e.to_string(), "invalid shares amount"); + assert_eq!(error_result.to_string(), "invalid shares amount"); // redelegate more tokens than we have from validator 1 to validator 2 - let e = execute_stake( + let error_result = execute_stake( &mut env, delegator_addr_1.clone(), StakingMsg::Redelegate { @@ -1833,10 +1832,10 @@ mod test { }, ) .unwrap_err(); - assert_eq!(e.to_string(), "invalid shares amount"); + assert_eq!(error_result.to_string(), "invalid shares amount"); // undelegate from non-existing delegation - let e = execute_stake( + let error_result = execute_stake( &mut env, delegator_addr_1.clone(), StakingMsg::Undelegate { @@ -1846,7 +1845,7 @@ mod test { ) .unwrap_err(); assert_eq!( - e.to_string(), + error_result.to_string(), "no delegation for (address, validator) tuple" ); } @@ -1862,7 +1861,7 @@ mod test { init_balance_denom(&mut env, &delegator_addr_1, 100, "FAKE"); // try to delegate 100 to validator - let e = execute_stake( + let error_result = execute_stake( &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { @@ -1871,9 +1870,8 @@ mod test { }, ) .unwrap_err(); - assert_eq!( - e.to_string(), + error_result.to_string(), "cannot delegate coins of denominator FAKE, only of TOKEN", ); } @@ -1889,7 +1887,7 @@ mod test { init_balance_denom(&mut env, &delegator_addr_1, 100, "FAKE"); // try to delegate 100 to non existing validator - let e = env + let error_result = env .router .staking .sudo( @@ -1903,8 +1901,7 @@ mod test { }, ) .unwrap_err(); - - assert_eq!(e.to_string(), "validator does not exist"); + assert_eq!(error_result.to_string(), "validator does not exist"); } #[test] @@ -1918,7 +1915,7 @@ mod test { init_balance(&mut env, &delegator_addr_1, 100); // try to delegate - let err = execute_stake( + let error_result = execute_stake( &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { @@ -1927,10 +1924,10 @@ mod test { }, ) .unwrap_err(); - assert_eq!(err.to_string(), "validator does not exist"); + assert_eq!(error_result.to_string(), "validator does not exist"); // try to undelegate - let err = execute_stake( + let error_result = execute_stake( &mut env, delegator_addr_1.clone(), StakingMsg::Undelegate { @@ -1939,7 +1936,7 @@ mod test { }, ) .unwrap_err(); - assert_eq!(err.to_string(), "validator does not exist"); + assert_eq!(error_result.to_string(), "validator does not exist"); } #[test] @@ -1950,7 +1947,7 @@ mod test { let delegator_addr_1 = env.delegator_addr_1(); // delegate 0 - let err = execute_stake( + let error_result = execute_stake( &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { @@ -1959,10 +1956,10 @@ mod test { }, ) .unwrap_err(); - assert_eq!(err.to_string(), "invalid delegation amount"); + assert_eq!(error_result.to_string(), "invalid delegation amount"); // undelegate 0 - let err = execute_stake( + let error_result = execute_stake( &mut env, delegator_addr_1, StakingMsg::Undelegate { @@ -1971,7 +1968,7 @@ mod test { }, ) .unwrap_err(); - assert_eq!(err.to_string(), "invalid shares amount"); + assert_eq!(error_result.to_string(), "invalid shares amount"); } #[test] From 9e88af837c11a1c8dc4d8c57c013afa325f1762a Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Fri, 14 Jun 2024 16:52:43 +0200 Subject: [PATCH 225/250] Added address function generators. --- src/staking.rs | 195 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 134 insertions(+), 61 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index 00055948..fc7b171f 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1056,7 +1056,7 @@ mod test { /// Test environment that simplifies initialization of test cases. struct TestEnv { api: MockApi, - store: MockStorage, + storage: MockStorage, router: BasicRouter, block: BlockInfo, validator_addr_1: Addr, @@ -1070,6 +1070,19 @@ mod test { impl TestEnv { /// Returns preconfigured test environment. fn new(validator1: (u64, u64, u64), validator2: (u64, u64, u64)) -> Self { + // Utility function for creating a validator's address, + // which has a different prefix from a user's address. + fn valoper_address(api: &MockApi, value: &str) -> Addr { + //TODO: this will be different in next PR, as requested in: https://github.com/CosmWasm/cw-multi-test/issues/173 + api.addr_make(value) + } + + // Utility function for creating a user's address, + // which is in Bech32 format with the chain's prefix. + fn user_address(api: &MockApi, value: &str) -> Addr { + api.addr_make(value) + } + let api = MockApi::default(); let router = Router { wasm: WasmKeeper::new(), @@ -1081,18 +1094,20 @@ mod test { gov: GovFailingModule::new(), stargate: StargateFailing, }; - let mut store = MockStorage::new(); + let mut storage = MockStorage::new(); let block = mock_env().block; - let validator_addr_1 = api.addr_make("validator1"); - let validator_addr_2 = api.addr_make("validator2"); + let validator_addr_1 = valoper_address(&api, "validator1"); + let validator_addr_2 = valoper_address(&api, "validator2"); + let validator_addr_3 = valoper_address(&api, "validator3"); + // configure basic staking parameters router .staking - .setup(&mut store, StakingInfo::default()) + .setup(&mut storage, StakingInfo::default()) .unwrap(); - // add first validator + // create validator no. 1 let valoper1 = Validator::new( validator_addr_1.to_string(), Decimal::percent(validator1.0), @@ -1101,10 +1116,10 @@ mod test { ); router .staking - .add_validator(&api, &mut store, &block, valoper1) + .add_validator(&api, &mut storage, &block, valoper1) .unwrap(); - // add second validator + // create validator no. 2 let valoper2 = Validator::new( validator_addr_2.to_string(), Decimal::percent(validator2.0), @@ -1113,20 +1128,21 @@ mod test { ); router .staking - .add_validator(&api, &mut store, &block, valoper2) + .add_validator(&api, &mut storage, &block, valoper2) .unwrap(); + // return testing environment Self { api, - store, + storage, router, block, validator_addr_1, validator_addr_2, - validator_addr_3: api.addr_make("validator3"), - delegator_addr_1: api.addr_make("delegator1"), - delegator_addr_2: api.addr_make("delegator2"), - user_addr_1: api.addr_make("user1"), + validator_addr_3, + delegator_addr_1: user_address(&api, "delegator1"), + delegator_addr_2: user_address(&api, "delegator2"), + user_addr_1: user_address(&api, "user1"), } } @@ -1167,10 +1183,11 @@ mod test { } } + /// Executes staking message. fn execute_stake(env: &mut TestEnv, sender: Addr, msg: StakingMsg) -> AnyResult { env.router.staking.execute( &env.api, - &mut env.store, + &mut env.storage, &env.router, &env.block, sender, @@ -1178,16 +1195,18 @@ mod test { ) } + /// Executes staking query. fn query_stake(env: &TestEnv, msg: StakingQuery) -> AnyResult { Ok(from_json(env.router.staking.query( &env.api, - &env.store, - &env.router.querier(&env.api, &env.store, &env.block), + &env.storage, + &env.router.querier(&env.api, &env.storage, &env.block), &env.block, msg, )?)?) } + /// Executes distribution message. fn execute_distr( env: &mut TestEnv, sender: Addr, @@ -1195,7 +1214,7 @@ mod test { ) -> AnyResult { env.router.distribution.execute( &env.api, - &mut env.store, + &mut env.storage, &env.router, &env.block, sender, @@ -1203,27 +1222,31 @@ mod test { ) } + /// Executes bank query. fn query_bank(env: &TestEnv, msg: BankQuery) -> AnyResult { Ok(from_json(env.router.bank.query( &env.api, - &env.store, - &env.router.querier(&env.api, &env.store, &env.block), + &env.storage, + &env.router.querier(&env.api, &env.storage, &env.block), &env.block, msg, )?)?) } + /// Initializes balance for specified address in staking denominator. fn init_balance(env: &mut TestEnv, address: &Addr, amount: u128) { init_balance_denom(env, address, amount, BONDED_DENOM); } + /// Initializes balance for specified address in any denominator. fn init_balance_denom(env: &mut TestEnv, address: &Addr, amount: u128, denom: &str) { env.router .bank - .init_balance(&mut env.store, address, coins(amount, denom)) + .init_balance(&mut env.storage, address, coins(amount, denom)) .unwrap(); } + /// Utility function for checking multiple balances in staking denominator. fn assert_balances(env: &TestEnv, balances: impl IntoIterator) { for (addr, amount) in balances { let balance: BalanceResponse = query_bank( @@ -1247,17 +1270,17 @@ mod test { // add a new validator (validator no. 3 does not exist yet) let validator = Validator::new( validator_addr_3.to_string(), + Decimal::percent(1), Decimal::percent(10), - Decimal::percent(20), Decimal::percent(1), ); env.router .staking - .add_validator(&env.api, &mut env.store, &env.block, validator.clone()) + .add_validator(&env.api, &mut env.storage, &env.block, validator.clone()) .unwrap(); // get the newly created validator - let staking_storage = prefixed_read(&env.store, NAMESPACE_STAKING); + let staking_storage = prefixed_read(&env.storage, NAMESPACE_STAKING); let val = env .router .staking @@ -1266,20 +1289,20 @@ mod test { .unwrap(); assert_eq!(val, validator); - // try to add a validator with same address (validator no. 3) + // try to create a validator with the same address as validator no. 3 let validator_fake = Validator::new( validator_addr_3.to_string(), - Decimal::percent(1), - Decimal::percent(10), - Decimal::percent(100), + Decimal::percent(2), + Decimal::percent(20), + Decimal::percent(2), ); env.router .staking - .add_validator(&env.api, &mut env.store, &env.block, validator_fake) + .add_validator(&env.api, &mut env.storage, &env.block, validator_fake) .unwrap_err(); - // validator no. 3 should be still like the original value - let staking_storage = prefixed_read(&env.store, NAMESPACE_STAKING); + // validator no. 3 should still have the original values of its attributes + let staking_storage = prefixed_read(&env.storage, NAMESPACE_STAKING); let val = env .router .staking @@ -1297,7 +1320,7 @@ mod test { let delegator_addr_1 = env.delegator_addr_1(); // stake (delegate) 100 tokens from delegator to validator - let mut staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); + let mut staking_storage = prefixed(&mut env.storage, NAMESPACE_STAKING); env.router .staking .add_stake( @@ -1315,7 +1338,7 @@ mod test { .staking .sudo( &env.api, - &mut env.store, + &mut env.storage, &env.router, &env.block, StakingSudo::Slash { @@ -1326,7 +1349,7 @@ mod test { .unwrap(); // check the remaining stake - let staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); + let staking_storage = prefixed(&mut env.storage, NAMESPACE_STAKING); let stake_left = env .router .staking @@ -1340,7 +1363,7 @@ mod test { .staking .sudo( &env.api, - &mut env.store, + &mut env.storage, &env.router, &env.block, StakingSudo::Slash { @@ -1351,7 +1374,7 @@ mod test { .unwrap(); // check the current stake - let staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); + let staking_storage = prefixed(&mut env.storage, NAMESPACE_STAKING); let stake_left = env .router .staking @@ -1367,7 +1390,7 @@ mod test { let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); - let mut staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); + let mut staking_storage = prefixed(&mut env.storage, NAMESPACE_STAKING); // stake 200 tokens env.router .staking @@ -1388,7 +1411,12 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator_addr_1, &validator_addr_1) + .get_rewards( + &env.storage, + &env.block, + &delegator_addr_1, + &validator_addr_1, + ) .unwrap() .unwrap(); assert_eq!(9, rewards.amount.u128()); @@ -1398,7 +1426,7 @@ mod test { .distribution .execute( &env.api, - &mut env.store, + &mut env.storage, &env.router, &env.block, delegator_addr_1.clone(), @@ -1412,7 +1440,12 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator_addr_1, &validator_addr_1) + .get_rewards( + &env.storage, + &env.block, + &delegator_addr_1, + &validator_addr_1, + ) .unwrap() .unwrap(); assert_eq!(0, rewards.amount.u128()); @@ -1423,7 +1456,12 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator_addr_1, &validator_addr_1) + .get_rewards( + &env.storage, + &env.block, + &delegator_addr_1, + &validator_addr_1, + ) .unwrap() .unwrap(); assert_eq!(9, rewards.amount.u128()); @@ -1437,7 +1475,7 @@ mod test { let delegator_addr_1 = env.delegator_addr_1(); let delegator_addr_2 = env.delegator_addr_2(); - let mut staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); + let mut staking_storage = prefixed(&mut env.storage, NAMESPACE_STAKING); // add 100 stake to delegator1 and 200 to delegator2 env.router @@ -1470,7 +1508,12 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator_addr_1, &validator_addr_1) + .get_rewards( + &env.storage, + &env.block, + &delegator_addr_1, + &validator_addr_1, + ) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 9); @@ -1479,13 +1522,18 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator_addr_2, &validator_addr_1) + .get_rewards( + &env.storage, + &env.block, + &delegator_addr_2, + &validator_addr_1, + ) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 18); // delegator1 stakes 100 more - let mut staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); + let mut staking_storage = prefixed(&mut env.storage, NAMESPACE_STAKING); env.router .staking .add_stake( @@ -1505,7 +1553,12 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator_addr_1, &validator_addr_1) + .get_rewards( + &env.storage, + &env.block, + &delegator_addr_1, + &validator_addr_1, + ) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 27); @@ -1514,13 +1567,18 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator_addr_2, &validator_addr_1) + .get_rewards( + &env.storage, + &env.block, + &delegator_addr_2, + &validator_addr_1, + ) .unwrap() .unwrap(); assert_eq!(rewards.amount.u128(), 36); // delegator2 unstakes 100 (has 100 left after that) - let mut staking_storage = prefixed(&mut env.store, NAMESPACE_STAKING); + let mut staking_storage = prefixed(&mut env.storage, NAMESPACE_STAKING); env.router .staking .remove_stake( @@ -1538,7 +1596,7 @@ mod test { .distribution .execute( &env.api, - &mut env.store, + &mut env.storage, &env.router, &env.block, delegator_addr_1.clone(), @@ -1553,8 +1611,8 @@ mod test { .bank .query( &env.api, - &env.store, - &env.router.querier(&env.api, &env.store, &env.block), + &env.storage, + &env.router.querier(&env.api, &env.storage, &env.block), &env.block, BankQuery::Balance { address: delegator_addr_1.to_string(), @@ -1569,7 +1627,12 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator_addr_1, &validator_addr_1) + .get_rewards( + &env.storage, + &env.block, + &delegator_addr_1, + &validator_addr_1, + ) .unwrap() .unwrap(); assert_eq!(0, rewards.amount.u128()); @@ -1581,7 +1644,12 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator_addr_1, &validator_addr_1) + .get_rewards( + &env.storage, + &env.block, + &delegator_addr_1, + &validator_addr_1, + ) .unwrap() .unwrap(); assert_eq!(18, rewards.amount.u128()); @@ -1590,7 +1658,12 @@ mod test { let rewards = env .router .staking - .get_rewards(&env.store, &env.block, &delegator_addr_2, &validator_addr_1) + .get_rewards( + &env.storage, + &env.block, + &delegator_addr_2, + &validator_addr_1, + ) .unwrap() .unwrap(); assert_eq!(45, rewards.amount.u128()); @@ -1700,7 +1773,7 @@ mod test { // need to manually cause queue to get processed env.router .staking - .process_queue(&env.api, &mut env.store, &env.router, &env.block) + .process_queue(&env.api, &mut env.storage, &env.router, &env.block) .unwrap(); // check bank balance @@ -1892,7 +1965,7 @@ mod test { .staking .sudo( &env.api, - &mut env.store, + &mut env.storage, &env.router, &env.block, StakingSudo::Slash { @@ -2291,7 +2364,7 @@ mod test { env.block.time = env.block.time.plus_seconds(40); env.router .staking - .process_queue(&env.api, &mut env.store, &env.router, &env.block) + .process_queue(&env.api, &mut env.storage, &env.router, &env.block) .unwrap(); // query delegations @@ -2318,7 +2391,7 @@ mod test { env.block.time = env.block.time.plus_seconds(20); env.router .staking - .process_queue(&env.api, &mut env.store, &env.router, &env.block) + .process_queue(&env.api, &mut env.storage, &env.router, &env.block) .unwrap(); // query delegations again @@ -2381,7 +2454,7 @@ mod test { .staking .sudo( &env.api, - &mut env.store, + &mut env.storage, &env.router, &env.block, StakingSudo::Slash { @@ -2412,10 +2485,10 @@ mod test { env.block.time = env.block.time.plus_seconds(60); env.router .staking - .process_queue(&env.api, &mut env.store, &env.router, &env.block) + .process_queue(&env.api, &mut env.storage, &env.router, &env.block) .unwrap(); let balance = - QuerierWrapper::::new(&env.router.querier(&env.api, &env.store, &env.block)) + QuerierWrapper::::new(&env.router.querier(&env.api, &env.storage, &env.block)) .query_balance(delegator_addr_1, BONDED_DENOM) .unwrap(); assert_eq!(55, balance.amount.u128()); From f7fa5e899bd3377bf5755f2a4a4b6b3c6c0f04d6 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 17 Jun 2024 15:19:47 +0200 Subject: [PATCH 226/250] Added validator properties. --- src/staking.rs | 66 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/src/staking.rs b/src/staking.rs index fc7b171f..8dc750a4 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1041,6 +1041,26 @@ mod test { }; use serde::de::DeserializeOwned; + /// Utility structure for combining validator properties, + /// used mainly for validator initialization. + struct ValidatorProperties { + /// Validator's commission. + commission: Decimal, + /// Validator's maximum commission. + max_commission: Decimal, + /// The maximum daily increase of the validator's commission. + max_change_rate: Decimal, + } + + /// Creates validator properties from values expressed as a percentage. + fn vp(commission: u64, max_commission: u64, max_change_rate: u64) -> ValidatorProperties { + ValidatorProperties { + commission: Decimal::percent(commission), + max_commission: Decimal::percent(max_commission), + max_change_rate: Decimal::percent(max_change_rate), + } + } + /// Type alias for default build of [Router], to make its reference in typical test scenario. type BasicRouter = Router< BankKeeper, @@ -1069,7 +1089,7 @@ mod test { impl TestEnv { /// Returns preconfigured test environment. - fn new(validator1: (u64, u64, u64), validator2: (u64, u64, u64)) -> Self { + fn new(validator1: ValidatorProperties, validator2: ValidatorProperties) -> Self { // Utility function for creating a validator's address, // which has a different prefix from a user's address. fn valoper_address(api: &MockApi, value: &str) -> Addr { @@ -1110,9 +1130,9 @@ mod test { // create validator no. 1 let valoper1 = Validator::new( validator_addr_1.to_string(), - Decimal::percent(validator1.0), - Decimal::percent(validator1.1), - Decimal::percent(validator1.2), + validator1.commission, + validator1.max_commission, + validator1.max_change_rate, ); router .staking @@ -1122,9 +1142,9 @@ mod test { // create validator no. 2 let valoper2 = Validator::new( validator_addr_2.to_string(), - Decimal::percent(validator2.0), - Decimal::percent(validator2.1), - Decimal::percent(validator2.2), + validator2.commission, + validator2.max_commission, + validator2.max_change_rate, ); router .staking @@ -1263,7 +1283,7 @@ mod test { #[test] fn add_get_validators() { - let mut env = TestEnv::new((10, 100, 1), (0, 20, 1)); + let mut env = TestEnv::new(vp(10, 100, 1), vp(0, 20, 1)); let validator_addr_3 = env.validator_addr_3(); @@ -1314,7 +1334,7 @@ mod test { #[test] fn validator_slashing() { - let mut env = TestEnv::new((10, 20, 1), (10, 20, 1)); + let mut env = TestEnv::new(vp(10, 20, 1), vp(10, 20, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1385,7 +1405,7 @@ mod test { #[test] fn rewards_work_for_single_delegator() { - let mut env = TestEnv::new((10, 20, 1), (10, 20, 1)); + let mut env = TestEnv::new(vp(10, 20, 1), vp(10, 20, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1469,7 +1489,7 @@ mod test { #[test] fn rewards_work_for_multiple_delegators() { - let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); + let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1671,7 +1691,7 @@ mod test { #[test] fn execute() { - let mut env = TestEnv::new((10, 100, 1), (0, 20, 1)); + let mut env = TestEnv::new(vp(10, 100, 1), vp(0, 20, 1)); let validator_addr_1 = env.validator_addr_1(); let validator_addr_2 = env.validator_addr_2(); @@ -1782,7 +1802,7 @@ mod test { #[test] fn can_set_withdraw_address() { - let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); + let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1862,7 +1882,7 @@ mod test { #[test] fn cannot_steal() { - let mut env = TestEnv::new((10, 100, 1), (0, 20, 1)); + let mut env = TestEnv::new(vp(10, 100, 1), vp(0, 20, 1)); let validator_addr_1 = env.validator_addr_1(); let validator_addr_2 = env.validator_addr_2(); @@ -1925,7 +1945,7 @@ mod test { #[test] fn denom_validation() { - let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); + let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1951,7 +1971,7 @@ mod test { #[test] fn cannot_slash_nonexistent() { - let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); + let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1)); let validator_addr_3 = env.validator_addr_3(); let delegator_addr_1 = env.delegator_addr_1(); @@ -1979,7 +1999,7 @@ mod test { #[test] fn non_existent_validator() { - let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); + let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1)); let validator_addr_3 = env.validator_addr_3(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2014,7 +2034,7 @@ mod test { #[test] fn zero_staking_forbidden() { - let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); + let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2046,7 +2066,7 @@ mod test { #[test] fn query_staking() { - let mut env = TestEnv::new((10, 100, 1), (0, 1, 1)); + let mut env = TestEnv::new(vp(10, 100, 1), vp(0, 1, 1)); let validator_addr_1 = env.validator_addr_1(); let validator_addr_2 = env.validator_addr_2(); @@ -2189,7 +2209,7 @@ mod test { #[test] fn delegation_queries_unbonding() { - let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); + let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2311,7 +2331,7 @@ mod test { #[test] fn partial_unbonding_reduces_stake() { - let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); + let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2419,7 +2439,7 @@ mod test { #[test] fn delegations_slashed() { - let mut env = TestEnv::new((10, 100, 1), (10, 100, 1)); + let mut env = TestEnv::new(vp(10, 100, 1), vp(10, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); @@ -2496,7 +2516,7 @@ mod test { #[test] fn rewards_initial_wait() { - let mut env = TestEnv::new((0, 100, 1), (0, 100, 1)); + let mut env = TestEnv::new(vp(0, 100, 1), vp(0, 100, 1)); let validator_addr_1 = env.validator_addr_1(); let delegator_addr_1 = env.delegator_addr_1(); From a71923b925ed388ccd4cbe54a2b332091fe2c8d5 Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Wed, 19 Jun 2024 14:11:45 +0200 Subject: [PATCH 227/250] Do not validate validator addresses (#183) Removed validation of validator addresses. --- Cargo.lock | 4 +- src/staking.rs | 178 +++++++++++++++++++++++-------------------------- 2 files changed, 86 insertions(+), 96 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 416b5955..eb015e47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -532,9 +532,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] diff --git a/src/staking.rs b/src/staking.rs index 8dc750a4..79783ae0 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -50,12 +50,12 @@ struct Shares { } impl Shares { - /// Calculates the share of validator rewards that should be given to this staker. - pub fn share_of_rewards(&self, validator: &ValidatorInfo, rewards: Decimal) -> Decimal { - if validator.stake.is_zero() { + /// Calculates the share of validator's rewards that should be given to this staker. + pub fn share_of_rewards(&self, validator_info: &ValidatorInfo, rewards: Decimal) -> Decimal { + if validator_info.stake.is_zero() { return Decimal::zero(); } - rewards * self.stake / validator.stake + rewards * self.stake / validator_info.stake } } @@ -83,20 +83,24 @@ impl ValidatorInfo { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] struct Unbonding { + /// Staker (delegator) address. pub delegator: Addr, - pub validator: Addr, + /// Validator address. + pub validator: String, + /// Amount of stakes to be unbonded. pub amount: Uint128, + /// Timestamp at which unbonding will take place (simulates unbonding timeout). pub payout_at: Timestamp, } const STAKING_INFO: Item = Item::new("staking_info"); /// (staker_addr, validator_addr) -> shares -const STAKES: Map<(&Addr, &Addr), Shares> = Map::new("stakes"); -const VALIDATOR_MAP: Map<&Addr, Validator> = Map::new("validator_map"); +const STAKES: Map<(&Addr, &str), Shares> = Map::new("stakes"); +const VALIDATOR_MAP: Map<&str, Validator> = Map::new("validator_map"); /// Additional vec of validators, in case the `iterator` feature is disabled const VALIDATORS: Deque = Deque::new("validators"); /// Contains additional info for each validator -const VALIDATOR_INFO: Map<&Addr, ValidatorInfo> = Map::new("validator_info"); +const VALIDATOR_INFO: Map<&str, ValidatorInfo> = Map::new("validator_info"); /// The queue of unbonding operations. This is needed because unbonding has a waiting time. See [`StakeKeeper`] const UNBONDING_QUEUE: Item> = Item::new("unbonding_queue"); /// (addr) -> addr. Maps addresses to the address they have delegated @@ -174,27 +178,31 @@ impl StakeKeeper { Ok(()) } - /// Add a new validator available for staking + /// Add a new validator available for staking. pub fn add_validator( &self, - api: &dyn Api, + _api: &dyn Api, storage: &mut dyn Storage, block: &BlockInfo, validator: Validator, ) -> AnyResult<()> { let mut storage = prefixed(storage, NAMESPACE_STAKING); - - let val_addr = api.addr_validate(&validator.address)?; - if VALIDATOR_MAP.may_load(&storage, &val_addr)?.is_some() { + if VALIDATOR_MAP + .may_load(&storage, &validator.address)? + .is_some() + { bail!( "Cannot add validator {}, since a validator with that address already exists", - val_addr + validator.address ); } - - VALIDATOR_MAP.save(&mut storage, &val_addr, &validator)?; + VALIDATOR_MAP.save(&mut storage, &validator.address, &validator)?; VALIDATORS.push_back(&mut storage, &validator)?; - VALIDATOR_INFO.save(&mut storage, &val_addr, &ValidatorInfo::new(block.time))?; + VALIDATOR_INFO.save( + &mut storage, + &validator.address, + &ValidatorInfo::new(block.time), + )?; Ok(()) } @@ -202,16 +210,15 @@ impl StakeKeeper { Ok(STAKING_INFO.may_load(staking_storage)?.unwrap_or_default()) } - /// Returns the rewards of the given delegator at the given validator + /// Returns the rewards of the given delegator at the given validator. pub fn get_rewards( &self, storage: &dyn Storage, block: &BlockInfo, delegator: &Addr, - validator: &Addr, + validator: &str, ) -> AnyResult> { let staking_storage = prefixed_read(storage, NAMESPACE_STAKING); - let validator_obj = match self.get_validator(&staking_storage, validator)? { Some(validator) => validator, None => bail!("validator {} not found", validator), @@ -224,7 +231,6 @@ impl StakeKeeper { } }; let validator_info = VALIDATOR_INFO.load(&staking_storage, validator)?; - Self::get_rewards_internal( &staking_storage, block, @@ -288,10 +294,10 @@ impl StakeKeeper { /// It saves the validator info and stakers, so make sure not to overwrite that. /// Always call this to update rewards before changing anything that influences future rewards. fn update_rewards( - api: &dyn Api, + _api: &dyn Api, staking_storage: &mut dyn Storage, block: &BlockInfo, - validator: &Addr, + validator: &str, ) -> AnyResult<()> { let staking_info = Self::get_staking_info(staking_storage)?; @@ -320,12 +326,11 @@ impl StakeKeeper { // update delegators if !new_rewards.is_zero() { - let validator_addr = api.addr_validate(&validator_obj.address)?; // update all delegators for staker in validator_info.stakers.iter() { STAKES.update( staking_storage, - (staker, &validator_addr), + (staker, &validator_obj.address), |shares| -> AnyResult<_> { let mut shares = shares.expect("all stakers in validator_info should exist"); @@ -338,11 +343,11 @@ impl StakeKeeper { Ok(()) } - /// Returns the single validator with the given address (or `None` if there is no such validator) + /// Returns the single validator with the given address (or `None` if there is no such validator). fn get_validator( &self, staking_storage: &dyn Storage, - address: &Addr, + address: &str, ) -> AnyResult> { Ok(VALIDATOR_MAP.may_load(staking_storage, address)?) } @@ -357,7 +362,7 @@ impl StakeKeeper { &self, staking_storage: &dyn Storage, account: &Addr, - validator: &Addr, + validator: &str, ) -> AnyResult> { let shares = STAKES.may_load(staking_storage, (account, validator))?; let staking_info = Self::get_staking_info(staking_storage)?; @@ -376,7 +381,7 @@ impl StakeKeeper { staking_storage: &mut dyn Storage, block: &BlockInfo, to_address: &Addr, - validator: &Addr, + validator: &str, amount: Coin, ) -> AnyResult<()> { self.validate_denom(staking_storage, &amount)?; @@ -397,7 +402,7 @@ impl StakeKeeper { staking_storage: &mut dyn Storage, block: &BlockInfo, from_address: &Addr, - validator: &Addr, + validator: &str, amount: Coin, ) -> AnyResult<()> { self.validate_denom(staking_storage, &amount)?; @@ -418,7 +423,7 @@ impl StakeKeeper { staking_storage: &mut dyn Storage, block: &BlockInfo, delegator: &Addr, - validator: &Addr, + validator: &str, amount: impl Into, sub: bool, ) -> AnyResult<()> { @@ -473,7 +478,7 @@ impl StakeKeeper { api: &dyn Api, staking_storage: &mut dyn Storage, block: &BlockInfo, - validator: &Addr, + validator: &str, percentage: Decimal, ) -> AnyResult<()> { // calculate rewards before slashing @@ -644,8 +649,6 @@ impl Module for StakeKeeper { let mut staking_storage = prefixed(storage, NAMESPACE_STAKING); match msg { StakingMsg::Delegate { validator, amount } => { - let validator = api.addr_validate(&validator)?; - // see https://github.com/cosmos/cosmos-sdk/blob/3c5387048f75d7e78b40c5b8d2421fdb8f5d973a/x/staking/types/msg.go#L202-L207 if amount.amount.is_zero() { bail!("invalid delegation amount"); @@ -679,7 +682,6 @@ impl Module for StakeKeeper { Ok(AppResponse { events, data: None }) } StakingMsg::Undelegate { validator, amount } => { - let validator = api.addr_validate(&validator)?; self.validate_denom(&staking_storage, &amount)?; // see https://github.com/cosmos/cosmos-sdk/blob/3c5387048f75d7e78b40c5b8d2421fdb8f5d973a/x/staking/types/msg.go#L292-L297 @@ -719,8 +721,6 @@ impl Module for StakeKeeper { dst_validator, amount, } => { - let src_validator = api.addr_validate(&src_validator)?; - let dst_validator = api.addr_validate(&dst_validator)?; // see https://github.com/cosmos/cosmos-sdk/blob/v0.46.1/x/staking/keeper/msg_server.go#L316-L322 let events = vec![Event::new("redelegate") .add_attribute("source_validator", &src_validator) @@ -773,11 +773,7 @@ impl Module for StakeKeeper { .filter_map(|validator| { let delegator = delegator.clone(); let amount = self - .get_stake( - &staking_storage, - &delegator, - &Addr::unchecked(&validator.address), - ) + .get_stake(&staking_storage, &delegator, &validator.address) .transpose()?; Some(amount.map(|amount| { @@ -792,18 +788,17 @@ impl Module for StakeKeeper { delegator, validator, } => { - let validator_addr = Addr::unchecked(&validator); - let validator_obj = match self.get_validator(&staking_storage, &validator_addr)? { + let validator_obj = match self.get_validator(&staking_storage, &validator)? { Some(validator) => validator, None => bail!("non-existent validator {}", validator), }; let delegator = api.addr_validate(&delegator)?; let shares = STAKES - .may_load(&staking_storage, (&delegator, &validator_addr))? + .may_load(&staking_storage, (&delegator, &validator))? .unwrap_or_default(); - let validator_info = VALIDATOR_INFO.load(&staking_storage, &validator_addr)?; + let validator_info = VALIDATOR_INFO.load(&staking_storage, &validator)?; let reward = Self::get_rewards_internal( &staking_storage, block, @@ -842,7 +837,7 @@ impl Module for StakeKeeper { self.get_validators(&staking_storage)?, ))?), StakingQuery::Validator { address } => Ok(to_json_binary(&ValidatorResponse::new( - self.get_validator(&staking_storage, &Addr::unchecked(address))?, + self.get_validator(&staking_storage, &address)?, ))?), q => bail!("Unsupported staking sudo message: {:?}", q), } @@ -862,7 +857,6 @@ impl Module for StakeKeeper { percentage, } => { let mut staking_storage = prefixed(storage, NAMESPACE_STAKING); - let validator = api.addr_validate(&validator)?; self.validate_percentage(percentage)?; self.slash(api, &mut staking_storage, block, &validator, percentage)?; Ok(AppResponse::default()) @@ -892,7 +886,7 @@ impl DistributionKeeper { storage: &mut dyn Storage, block: &BlockInfo, delegator: &Addr, - validator: &Addr, + validator: &str, ) -> AnyResult { let mut staking_storage = prefixed(storage, NAMESPACE_STAKING); // update the validator and staker rewards @@ -956,10 +950,7 @@ impl Module for DistributionKeeper { ) -> AnyResult { match msg { DistributionMsg::WithdrawDelegatorReward { validator } => { - let validator_addr = api.addr_validate(&validator)?; - - let rewards = self.remove_rewards(api, storage, block, &sender, &validator_addr)?; - + let rewards = self.remove_rewards(api, storage, block, &sender, &validator)?; let staking_storage = prefixed_read(storage, NAMESPACE_STAKING); let distribution_storage = prefixed_read(storage, NAMESPACE_DISTRIBUTION); let staking_info = StakeKeeper::get_staking_info(&staking_storage)?; @@ -1031,8 +1022,8 @@ impl Module for DistributionKeeper { mod test { use super::*; use crate::{ - BankKeeper, FailingModule, GovFailingModule, IbcFailingModule, Router, StargateFailing, - WasmKeeper, + BankKeeper, FailingModule, GovFailingModule, IbcFailingModule, IntoBech32, Router, + StargateFailing, WasmKeeper, }; use cosmwasm_std::{ coins, from_json, @@ -1079,9 +1070,9 @@ mod test { storage: MockStorage, router: BasicRouter, block: BlockInfo, - validator_addr_1: Addr, - validator_addr_2: Addr, - validator_addr_3: Addr, + validator_addr_1: String, + validator_addr_2: String, + validator_addr_3: String, delegator_addr_1: Addr, delegator_addr_2: Addr, user_addr_1: Addr, @@ -1092,9 +1083,8 @@ mod test { fn new(validator1: ValidatorProperties, validator2: ValidatorProperties) -> Self { // Utility function for creating a validator's address, // which has a different prefix from a user's address. - fn valoper_address(api: &MockApi, value: &str) -> Addr { - //TODO: this will be different in next PR, as requested in: https://github.com/CosmWasm/cw-multi-test/issues/173 - api.addr_make(value) + fn validator_address(value: &str) -> String { + value.into_bech32_with_prefix("cosmwasmvaloper").to_string() } // Utility function for creating a user's address, @@ -1117,9 +1107,9 @@ mod test { let mut storage = MockStorage::new(); let block = mock_env().block; - let validator_addr_1 = valoper_address(&api, "validator1"); - let validator_addr_2 = valoper_address(&api, "validator2"); - let validator_addr_3 = valoper_address(&api, "validator3"); + let validator_addr_1 = validator_address("validator1"); + let validator_addr_2 = validator_address("validator2"); + let validator_addr_3 = validator_address("validator3"); // configure basic staking parameters router @@ -1168,19 +1158,19 @@ mod test { /// Returns an address of EXISTING validator no. 1. #[inline(always)] - fn validator_addr_1(&self) -> Addr { + fn validator_addr_1(&self) -> String { self.validator_addr_1.clone() } /// Returns an address of EXISTING validator no. 2. #[inline(always)] - fn validator_addr_2(&self) -> Addr { + fn validator_addr_2(&self) -> String { self.validator_addr_2.clone() } /// Returns an address of NON-EXISTING validator no. 3. #[inline(always)] - fn validator_addr_3(&self) -> Addr { + fn validator_addr_3(&self) -> String { self.validator_addr_3.clone() } @@ -1706,7 +1696,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), amount: coin(100, BONDED_DENOM), }, ) @@ -1733,7 +1723,7 @@ mod test { &mut env, delegator_addr_1.clone(), DistributionMsg::WithdrawDelegatorReward { - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), }, ) .unwrap(); @@ -1750,8 +1740,8 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Redelegate { - src_validator: validator_addr_1.to_string(), - dst_validator: validator_addr_2.to_string(), + src_validator: validator_addr_1, + dst_validator: validator_addr_2.clone(), amount: coin(100, BONDED_DENOM), }, ) @@ -1771,7 +1761,7 @@ mod test { delegations.delegations, [Delegation::new( delegator_addr_1.clone(), - validator_addr_2.to_string(), + validator_addr_2.clone(), coin(100, BONDED_DENOM), )] ); @@ -1781,7 +1771,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator_addr_2.to_string(), + validator: validator_addr_2, amount: coin(100, BONDED_DENOM), }, ) @@ -1816,7 +1806,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), amount: coin(100, BONDED_DENOM), }, ) @@ -1840,7 +1830,7 @@ mod test { &mut env, delegator_addr_1.clone(), DistributionMsg::WithdrawDelegatorReward { - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), }, ) .unwrap(); @@ -1863,7 +1853,7 @@ mod test { &mut env, delegator_addr_1.clone(), DistributionMsg::WithdrawDelegatorReward { - validator: validator_addr_1.to_string(), + validator: validator_addr_1, }, ) .unwrap(); @@ -1896,7 +1886,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), amount: coin(100, BONDED_DENOM), }, ) @@ -1907,7 +1897,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), amount: coin(200, BONDED_DENOM), }, ) @@ -1919,8 +1909,8 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Redelegate { - src_validator: validator_addr_1.to_string(), - dst_validator: validator_addr_2.to_string(), + src_validator: validator_addr_1, + dst_validator: validator_addr_2.clone(), amount: coin(200, BONDED_DENOM), }, ) @@ -1932,7 +1922,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator_addr_2.to_string(), + validator: validator_addr_2, amount: coin(100, BONDED_DENOM), }, ) @@ -1958,7 +1948,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator_addr_1.to_string(), + validator: validator_addr_1, amount: coin(100, "FAKE"), }, ) @@ -1989,7 +1979,7 @@ mod test { &env.router, &env.block, StakingSudo::Slash { - validator: validator_addr_3.to_string(), + validator: validator_addr_3, percentage: Decimal::percent(50), }, ) @@ -2012,7 +2002,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator_addr_3.to_string(), + validator: validator_addr_3.clone(), amount: coin(100, BONDED_DENOM), }, ) @@ -2024,7 +2014,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Undelegate { - validator: validator_addr_3.to_string(), + validator: validator_addr_3, amount: coin(100, BONDED_DENOM), }, ) @@ -2044,7 +2034,7 @@ mod test { &mut env, delegator_addr_1.clone(), StakingMsg::Delegate { - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), amount: coin(0, BONDED_DENOM), }, ) @@ -2056,7 +2046,7 @@ mod test { &mut env, delegator_addr_1, StakingMsg::Undelegate { - validator: validator_addr_1.to_string(), + validator: validator_addr_1, amount: coin(0, BONDED_DENOM), }, ) @@ -2182,7 +2172,7 @@ mod test { ), Delegation::new( delegator_addr_1.clone(), - validator_addr_2.to_string(), + validator_addr_2, coin(160, BONDED_DENOM), ), ] @@ -2191,7 +2181,7 @@ mod test { &env, StakingQuery::Delegation { delegator: delegator_addr_2.to_string(), - validator: validator_addr_1.to_string(), + validator: validator_addr_1.clone(), }, ) .unwrap(); @@ -2199,7 +2189,7 @@ mod test { response2.delegation.unwrap(), FullDelegation::new( delegator_addr_2.clone(), - validator_addr_1.to_string(), + validator_addr_1, coin(100, BONDED_DENOM), coin(100, BONDED_DENOM), vec![], @@ -2311,7 +2301,7 @@ mod test { &env, StakingQuery::Delegation { delegator: delegator_addr_1.to_string(), - validator: validator_addr_1.to_string(), + validator: validator_addr_1, }, ) .unwrap(); @@ -2419,7 +2409,7 @@ mod test { &env, StakingQuery::Delegation { delegator: delegator_addr_1.to_string(), - validator: validator_addr_1.to_string(), + validator: validator_addr_1, }, ) .unwrap(); @@ -2496,7 +2486,7 @@ mod test { response1.delegations[0], Delegation::new( delegator_addr_1.clone(), - validator_addr_1.to_string(), + validator_addr_1, coin(111, BONDED_DENOM), ) ); @@ -2546,7 +2536,7 @@ mod test { &env, StakingQuery::Delegation { delegator: delegator_addr_1.to_string(), - validator: validator_addr_1.to_string(), + validator: validator_addr_1, }, ) .unwrap(); From b57f7ee30762e63e9f00cd89ba31845e02e3e8a6 Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Thu, 20 Jun 2024 10:43:30 +0200 Subject: [PATCH 228/250] Enabled using `addr_make` inside `AppBuilder::build` (#189) Enabled using addr_make inside AppBuilder::build --- Cargo.lock | 4 +- src/app.rs | 12 +-- src/app_builder.rs | 35 +++---- src/tests/test_ibc.rs | 2 +- src/wasm.rs | 6 +- tests/mod.rs | 1 + tests/test_app/mod.rs | 1 + tests/test_app/test_initialize_app.rs | 21 +++++ tests/test_app_builder/test_with_bank.rs | 3 +- tests/test_app_builder/test_with_gov.rs | 3 +- tests/test_app_builder/test_with_ibc.rs | 3 +- tests/test_app_builder/test_with_staking.rs | 5 +- tests/test_app_builder/test_with_stargate.rs | 15 +-- tests/test_app_builder/test_with_storage.rs | 3 +- tests/test_app_builder/test_with_wasm.rs | 8 +- tests/test_bank/mod.rs | 1 + tests/test_bank/test_init_balance.rs | 96 ++++++++++++++++++++ 17 files changed, 170 insertions(+), 49 deletions(-) create mode 100644 tests/test_app/test_initialize_app.rs create mode 100644 tests/test_bank/mod.rs create mode 100644 tests/test_bank/test_init_balance.rs diff --git a/Cargo.lock b/Cargo.lock index eb015e47..ecd78733 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -789,9 +789,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "0d0208408ba0c3df17ed26eb06992cb1a1268d41b2c0e12e65203fbe3972cee5" [[package]] name = "syn" diff --git a/src/app.rs b/src/app.rs index 39540a69..b0798d2d 100644 --- a/src/app.rs +++ b/src/app.rs @@ -67,9 +67,9 @@ pub struct App< } /// No-op application initialization function. -pub fn no_init( +pub fn no_init( router: &mut Router, - api: &dyn Api, + api: &ApiT, storage: &mut dyn Storage, ) { let _ = (router, api, storage); @@ -96,7 +96,7 @@ impl BasicApp { GovFailingModule, StargateFailing, >, - &dyn Api, + &MockApi, &mut dyn Storage, ), { @@ -121,7 +121,7 @@ where GovFailingModule, StargateFailing, >, - &dyn Api, + &MockApi, &mut dyn Storage, ), { @@ -216,7 +216,7 @@ where where F: FnOnce( &mut Router, - &dyn Api, + &ApiT, &mut dyn Storage, ) -> T, { @@ -228,7 +228,7 @@ where where F: FnOnce( &Router, - &dyn Api, + &ApiT, &dyn Storage, ) -> T, { diff --git a/src/app_builder.rs b/src/app_builder.rs index ad9b0dc5..7d49815d 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -16,7 +16,7 @@ use std::fmt::Debug; /// /// ``` /// # use cosmwasm_std::Empty; -/// # use cw_multi_test::{BasicAppBuilder, FailingModule, Module, no_init}; +/// # use cw_multi_test::{no_init, BasicAppBuilder, FailingModule, Module}; /// # type MyHandler = FailingModule; /// # type MyExecC = Empty; /// # type MyQueryC = Empty; @@ -530,9 +530,9 @@ where 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 errors, make sure that all components - /// are properly relating to each other. + /// Builds the final [App] with initialization. + /// + /// At this point all component types have to be properly related to each other. pub fn build( self, init_fn: F, @@ -550,28 +550,29 @@ where StargateT: Stargate, F: FnOnce( &mut Router, - &dyn Api, + &ApiT, &mut dyn Storage, ), { - let router = Router { - wasm: self.wasm, - bank: self.bank, - custom: self.custom, - staking: self.staking, - distribution: self.distribution, - ibc: self.ibc, - gov: self.gov, - stargate: self.stargate, - }; - + // build the final application let mut app = App { - router, + router: Router { + wasm: self.wasm, + bank: self.bank, + custom: self.custom, + staking: self.staking, + distribution: self.distribution, + ibc: self.ibc, + gov: self.gov, + stargate: self.stargate, + }, api: self.api, block: self.block, storage: self.storage, }; + // execute initialization provided by the caller app.init_modules(init_fn); + // return already initialized application app } } diff --git a/src/tests/test_ibc.rs b/src/tests/test_ibc.rs index ed32377e..ab70567c 100644 --- a/src/tests/test_ibc.rs +++ b/src/tests/test_ibc.rs @@ -20,7 +20,7 @@ fn default_ibc() { #[test] fn accepting_ibc() { - let mut app = AppBuilder::new() + let mut app = AppBuilder::default() .with_ibc(IbcAcceptingModule::new()) .build(no_init); diff --git a/src/wasm.rs b/src/wasm.rs index 04493cd2..b92a8d18 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -433,7 +433,7 @@ where /// # Example /// /// ``` - /// use cw_multi_test::{AppBuilder, no_init, WasmKeeper}; + /// use cw_multi_test::{no_init, AppBuilder, WasmKeeper}; /// /// // create wasm keeper /// let wasm_keeper = WasmKeeper::new(); @@ -451,7 +451,7 @@ where /// /// ``` /// use cosmwasm_std::{Addr, Api, Storage}; - /// use cw_multi_test::{AddressGenerator, AppBuilder, no_init, WasmKeeper}; + /// use cw_multi_test::{no_init, AddressGenerator, AppBuilder, WasmKeeper}; /// use cw_multi_test::error::AnyResult; /// # use cosmwasm_std::testing::MockApi; /// @@ -490,7 +490,7 @@ where /// /// ``` /// use cosmwasm_std::{Addr, Checksum}; - /// use cw_multi_test::{AppBuilder, ChecksumGenerator, no_init, WasmKeeper}; + /// use cw_multi_test::{no_init, AppBuilder, ChecksumGenerator, WasmKeeper}; /// /// struct MyChecksumGenerator; /// diff --git a/tests/mod.rs b/tests/mod.rs index 9001d161..feb7b9ea 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -4,6 +4,7 @@ mod test_api; mod test_app; mod test_app_builder; mod test_attributes; +mod test_bank; mod test_contract_storage; mod test_module; mod test_prefixed_storage; diff --git a/tests/test_app/mod.rs b/tests/test_app/mod.rs index 6592434b..00601b0d 100644 --- a/tests/test_app/mod.rs +++ b/tests/test_app/mod.rs @@ -1,4 +1,5 @@ mod test_block_info; +mod test_initialize_app; #[cfg(feature = "cosmwasm_1_2")] mod test_instantiate2; mod test_store_code; diff --git a/tests/test_app/test_initialize_app.rs b/tests/test_app/test_initialize_app.rs new file mode 100644 index 00000000..977d9947 --- /dev/null +++ b/tests/test_app/test_initialize_app.rs @@ -0,0 +1,21 @@ +use cw_multi_test::App; +use cw_storage_plus::Map; + +const USER: &str = "user"; +const USERS: Map<&str, u64> = Map::new("users"); +const AMOUNT: u64 = 100; + +#[test] +fn initializing_app_should_work() { + let mut app = App::default(); + let mut amount = 0; + app.init_modules(|_router, api, storage| { + USERS + .save(storage, api.addr_make(USER).as_str(), &AMOUNT) + .unwrap(); + }); + app.read_module(|_router, api, storage| { + amount = USERS.load(storage, api.addr_make(USER).as_str()).unwrap() + }); + assert_eq!(AMOUNT, amount); +} diff --git a/tests/test_app_builder/test_with_bank.rs b/tests/test_app_builder/test_with_bank.rs index 3aba13fd..a6b00f4a 100644 --- a/tests/test_app_builder/test_with_bank.rs +++ b/tests/test_app_builder/test_with_bank.rs @@ -16,8 +16,7 @@ fn building_app_with_custom_bank_should_work() { let bank_keeper = MyBankKeeper::new(EXECUTE_MSG, QUERY_MSG, SUDO_MSG); // build the application with custom bank keeper - let app_builder = AppBuilder::default(); - let mut app = app_builder.with_bank(bank_keeper).build(no_init); + let mut app = AppBuilder::default().with_bank(bank_keeper).build(no_init); // prepare user addresses let recipient_addr = app.api().addr_make("recipient"); diff --git a/tests/test_app_builder/test_with_gov.rs b/tests/test_app_builder/test_with_gov.rs index d086674c..f1f8e0fe 100644 --- a/tests/test_app_builder/test_with_gov.rs +++ b/tests/test_app_builder/test_with_gov.rs @@ -14,8 +14,7 @@ fn building_app_with_custom_gov_should_work() { let gov_keeper = MyGovKeeper::new(EXECUTE_MSG, NO_MESSAGE, NO_MESSAGE); // build the application with custom gov keeper - let app_builder = AppBuilder::default(); - let mut app = app_builder.with_gov(gov_keeper).build(no_init); + let mut app = AppBuilder::default().with_gov(gov_keeper).build(no_init); // prepare addresses let sender_addr = app.api().addr_make("sender"); diff --git a/tests/test_app_builder/test_with_ibc.rs b/tests/test_app_builder/test_with_ibc.rs index a39ec0a5..f9a77ba3 100644 --- a/tests/test_app_builder/test_with_ibc.rs +++ b/tests/test_app_builder/test_with_ibc.rs @@ -15,8 +15,7 @@ fn building_app_with_custom_ibc_should_work() { let ibc_keeper = MyIbcKeeper::new(EXECUTE_MSG, QUERY_MSG, NO_MESSAGE); // build the application with custom ibc keeper - let app_builder = AppBuilder::default(); - let mut app = app_builder.with_ibc(ibc_keeper).build(no_init); + let mut app = AppBuilder::default().with_ibc(ibc_keeper).build(no_init); // prepare user addresses let sender_addr = app.api().addr_make("sender"); diff --git a/tests/test_app_builder/test_with_staking.rs b/tests/test_app_builder/test_with_staking.rs index ac429062..3f49b1d4 100644 --- a/tests/test_app_builder/test_with_staking.rs +++ b/tests/test_app_builder/test_with_staking.rs @@ -16,8 +16,9 @@ fn building_app_with_custom_staking_should_work() { let stake_keeper = MyStakeKeeper::new(EXECUTE_MSG, QUERY_MSG, SUDO_MSG); // build the application with custom stake keeper - let app_builder = AppBuilder::default(); - let mut app = app_builder.with_staking(stake_keeper).build(no_init); + let mut app = AppBuilder::default() + .with_staking(stake_keeper) + .build(no_init); // prepare addresses let validator_addr = app.api().addr_make("validator"); diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index 51b10b80..3bb09844 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -113,8 +113,9 @@ fn building_app_with_custom_stargate_should_work() { #[cfg(feature = "cosmwasm_2_0")] fn building_app_with_custom_any_grpc_should_work() { // build the application with custom stargate keeper - let app_builder = AppBuilder::default(); - let mut app = app_builder.with_stargate(StargateKeeper).build(no_init); + let mut app = AppBuilder::default() + .with_stargate(StargateKeeper) + .build(no_init); // prepare user addresses let sender_addr = app.api().addr_make("sender"); @@ -144,8 +145,9 @@ fn building_app_with_custom_any_grpc_should_work() { #[test] fn building_app_with_accepting_stargate_should_work() { - let app_builder = AppBuilder::default(); - let mut app = app_builder.with_stargate(StargateAccepting).build(no_init); + let mut app = AppBuilder::default() + .with_stargate(StargateAccepting) + .build(no_init); // prepare user addresses let sender_addr = app.api().addr_make("sender"); @@ -238,8 +240,9 @@ fn default_failing_stargate_should_work() { #[test] #[cfg(feature = "cosmwasm_2_0")] fn default_failing_any_grpc_should_work() { - let app_builder = AppBuilder::default(); - let mut app = app_builder.with_stargate(StargateFailing).build(no_init); + let mut app = AppBuilder::default() + .with_stargate(StargateFailing) + .build(no_init); // prepare user addresses let sender_addr = app.api().addr_make("sender"); diff --git a/tests/test_app_builder/test_with_storage.rs b/tests/test_app_builder/test_with_storage.rs index 3290f9c1..6adf6909 100644 --- a/tests/test_app_builder/test_with_storage.rs +++ b/tests/test_app_builder/test_with_storage.rs @@ -41,8 +41,7 @@ fn building_app_with_custom_storage_should_work() { let label = "my-counter"; // build the application with custom storage - let app_builder = AppBuilder::default(); - let mut app = app_builder + let mut app = AppBuilder::default() .with_storage(MyStorage::default()) .build(no_init); diff --git a/tests/test_app_builder/test_with_wasm.rs b/tests/test_app_builder/test_with_wasm.rs index 390c8684..258894c2 100644 --- a/tests/test_app_builder/test_with_wasm.rs +++ b/tests/test_app_builder/test_with_wasm.rs @@ -91,8 +91,7 @@ fn building_app_with_custom_wasm_should_work() { let wasm_keeper = MyWasmKeeper::new(EXECUTE_MSG, QUERY_MSG, SUDO_MSG); // build the application with custom wasm keeper - let app_builder = AppBuilder::default(); - let mut app = app_builder.with_wasm(wasm_keeper).build(no_init); + let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init); // prepare addresses let contract_addr = app.api().addr_make("contract"); @@ -162,6 +161,7 @@ fn building_app_with_custom_wasm_should_work() { fn compiling_with_wasm_keeper_should_work() { // this verifies only compilation errors // while our WasmKeeper does not implement Module - let app_builder = AppBuilder::default(); - let _ = app_builder.with_wasm(WasmKeeper::default()).build(no_init); + let _ = AppBuilder::default() + .with_wasm(WasmKeeper::default()) + .build(no_init); } diff --git a/tests/test_bank/mod.rs b/tests/test_bank/mod.rs new file mode 100644 index 00000000..dfe6392e --- /dev/null +++ b/tests/test_bank/mod.rs @@ -0,0 +1 @@ +mod test_init_balance; diff --git a/tests/test_bank/test_init_balance.rs b/tests/test_bank/test_init_balance.rs new file mode 100644 index 00000000..b312b22d --- /dev/null +++ b/tests/test_bank/test_init_balance.rs @@ -0,0 +1,96 @@ +use cosmwasm_std::{Coin, CustomMsg, CustomQuery, Uint128}; +use cw_multi_test::{custom_app, App, AppBuilder, BasicApp}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +const USER: &str = "user"; +const DENOM: &str = "denom"; +const AMOUNT: u128 = 100; + +fn assert_balance(coins: Vec) { + assert_eq!(1, coins.len()); + assert_eq!(AMOUNT, coins[0].amount.u128()); + assert_eq!(DENOM, coins[0].denom); +} + +fn coins() -> Vec { + vec![Coin { + denom: DENOM.to_string(), + amount: Uint128::new(AMOUNT), + }] +} + +#[test] +fn initializing_balance_should_work() { + let app = AppBuilder::new().build(|router, api, storage| { + router + .bank + .init_balance(storage, &api.addr_make(USER), coins()) + .unwrap(); + }); + assert_balance( + app.wrap() + .query_all_balances(app.api().addr_make(USER)) + .unwrap(), + ); +} + +#[test] +fn initializing_balance_without_builder_should_work() { + let app = App::new(|router, api, storage| { + router + .bank + .init_balance(storage, &api.addr_make(USER), coins()) + .unwrap(); + }); + assert_balance( + app.wrap() + .query_all_balances(app.api().addr_make(USER)) + .unwrap(), + ); +} + +#[test] +fn initializing_balance_custom_app_should_work() { + #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] + #[serde(rename = "snake_case")] + pub enum CustomHelperMsg { + HelperMsg, + } + impl CustomMsg for CustomHelperMsg {} + + #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] + #[serde(rename = "snake_case")] + pub enum CustomHelperQuery { + HelperQuery, + } + impl CustomQuery for CustomHelperQuery {} + + let app: BasicApp = custom_app(|router, api, storage| { + router + .bank + .init_balance(storage, &api.addr_make(USER), coins()) + .unwrap(); + }); + assert_balance( + app.wrap() + .query_all_balances(app.api().addr_make(USER)) + .unwrap(), + ); +} + +#[test] +fn initializing_balance_later_should_work() { + let mut app = App::default(); + app.init_modules(|router, api, storage| { + router + .bank + .init_balance(storage, &api.addr_make(USER), coins()) + .unwrap(); + }); + assert_balance( + app.wrap() + .query_all_balances(app.api().addr_make(USER)) + .unwrap(), + ); +} From 9b4e9ebc342922a066885897ab7ae9fb4f65fab6 Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Fri, 21 Jun 2024 11:46:48 +0200 Subject: [PATCH 229/250] Removed `cosmwasm-std` features from dependencies (#191) Removed cosmwasm-std features from dependencies --- Cargo.lock | 18 ++++---- Cargo.toml | 4 +- src/app.rs | 15 ++++++- src/app_builder.rs | 6 +-- src/contracts.rs | 3 ++ src/featured.rs | 43 +++++++++++++++++++ src/gov.rs | 6 ++- src/lib.rs | 3 ++ src/test_helpers/mod.rs | 3 ++ src/tests/mod.rs | 3 ++ src/tests/test_app.rs | 5 ++- src/wasm.rs | 2 +- tests/mod.rs | 1 + tests/test_app_builder/mod.rs | 7 ++- .../test_with_distribution.rs | 4 +- tests/test_app_builder/test_with_gov.rs | 4 +- tests/test_app_builder/test_with_ibc.rs | 4 +- tests/test_app_builder/test_with_stargate.rs | 1 + 18 files changed, 105 insertions(+), 27 deletions(-) create mode 100644 src/featured.rs diff --git a/Cargo.lock b/Cargo.lock index ecd78733..e010c172 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -572,9 +572,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -599,7 +599,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -669,7 +669,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -712,7 +712,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -723,7 +723,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -806,9 +806,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "ff8655ed1d86f3af4ee3fd3263786bc14245ad17c4c7e85ba7187fb3ae028c90" dependencies = [ "proc-macro2", "quote", @@ -832,7 +832,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 5635c814..aa6add42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,8 @@ edition = "2021" [features] default = [] backtrace = ["anyhow/backtrace"] +staking = ["cosmwasm-std/staking"] +stargate = ["cosmwasm-std/stargate"] cosmwasm_1_1 = ["cosmwasm-std/cosmwasm_1_1"] cosmwasm_1_2 = ["cosmwasm_1_1", "cosmwasm-std/cosmwasm_1_2"] cosmwasm_1_3 = ["cosmwasm_1_2", "cosmwasm-std/cosmwasm_1_3"] @@ -23,7 +25,7 @@ cosmwasm_2_0 = ["cosmwasm_1_4", "cosmwasm-std/cosmwasm_2_0"] [dependencies] anyhow = "1.0.86" bech32 = "0.11.0" -cosmwasm-std = { version = "2.0.4", features = ["staking", "stargate"] } +cosmwasm-std = "2.0.4" cw-storage-plus = "2.0.0" cw-utils = "2.0.0" derivative = "2.2.0" diff --git a/src/app.rs b/src/app.rs index b0798d2d..e58e589a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2,13 +2,15 @@ use crate::bank::{Bank, BankKeeper, BankSudo}; use crate::contracts::Contract; use crate::error::{bail, AnyResult}; use crate::executor::{AppResponse, Executor}; +use crate::featured::staking::{ + Distribution, DistributionKeeper, StakeKeeper, Staking, StakingSudo, +}; use crate::gov::Gov; use crate::ibc::Ibc; use crate::module::{FailingModule, Module}; use crate::prefixed_storage::{ prefixed, prefixed_multilevel, prefixed_multilevel_read, prefixed_read, }; -use crate::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking, StakingSudo}; use crate::transactions::transactional; use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; use crate::{AppBuilder, GovFailingModule, IbcFailingModule, Stargate, StargateFailing}; @@ -653,13 +655,18 @@ where CosmosMsg::Wasm(msg) => self.wasm.execute(api, storage, self, block, sender, msg), CosmosMsg::Bank(msg) => self.bank.execute(api, storage, self, block, sender, msg), CosmosMsg::Custom(msg) => self.custom.execute(api, storage, self, block, sender, msg), + #[cfg(feature = "staking")] CosmosMsg::Staking(msg) => self.staking.execute(api, storage, self, block, sender, msg), + #[cfg(feature = "staking")] CosmosMsg::Distribution(msg) => self .distribution .execute(api, storage, self, block, sender, msg), + #[cfg(feature = "stargate")] CosmosMsg::Ibc(msg) => self.ibc.execute(api, storage, self, block, sender, msg), + #[cfg(feature = "stargate")] CosmosMsg::Gov(msg) => self.gov.execute(api, storage, self, block, sender, msg), #[allow(deprecated)] + #[cfg(feature = "stargate")] CosmosMsg::Stargate { type_url, value } => self .stargate .execute_stargate(api, storage, self, block, sender, type_url, value), @@ -686,9 +693,12 @@ where QueryRequest::Wasm(req) => self.wasm.query(api, storage, &querier, block, req), QueryRequest::Bank(req) => self.bank.query(api, storage, &querier, block, req), QueryRequest::Custom(req) => self.custom.query(api, storage, &querier, block, req), + #[cfg(feature = "staking")] QueryRequest::Staking(req) => self.staking.query(api, storage, &querier, block, req), + #[cfg(feature = "stargate")] QueryRequest::Ibc(req) => self.ibc.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), @@ -708,8 +718,9 @@ where match msg { SudoMsg::Wasm(msg) => self.wasm.sudo(api, storage, self, block, msg), SudoMsg::Bank(msg) => self.bank.sudo(api, storage, self, block, msg), + #[cfg(feature = "staking")] SudoMsg::Staking(msg) => self.staking.sudo(api, storage, self, block, msg), - SudoMsg::Custom(_) => unimplemented!(), + _ => unimplemented!(), } } } diff --git a/src/app_builder.rs b/src/app_builder.rs index 7d49815d..67fc8d41 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -1,9 +1,9 @@ //! AppBuilder helps you set up your test blockchain environment step by step [App]. +use crate::featured::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking}; use crate::{ - App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingModule, Gov, GovFailingModule, - Ibc, IbcFailingModule, Module, Router, StakeKeeper, Staking, Stargate, StargateFailing, Wasm, - WasmKeeper, + App, Bank, BankKeeper, FailingModule, Gov, GovFailingModule, Ibc, IbcFailingModule, Module, + Router, Stargate, StargateFailing, Wasm, WasmKeeper, }; use cosmwasm_std::testing::{mock_env, MockApi, MockStorage}; use cosmwasm_std::{Api, BlockInfo, CustomMsg, CustomQuery, Empty, Storage}; diff --git a/src/contracts.rs b/src/contracts.rs index e3feb726..5f550423 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -430,9 +430,12 @@ where msg: match msg.msg { CosmosMsg::Wasm(wasm) => CosmosMsg::Wasm(wasm), CosmosMsg::Bank(bank) => CosmosMsg::Bank(bank), + #[cfg(feature = "staking")] CosmosMsg::Staking(staking) => CosmosMsg::Staking(staking), + #[cfg(feature = "staking")] CosmosMsg::Distribution(distribution) => CosmosMsg::Distribution(distribution), CosmosMsg::Custom(_) => unreachable!(), + #[cfg(feature = "stargate")] CosmosMsg::Ibc(ibc) => CosmosMsg::Ibc(ibc), #[cfg(feature = "cosmwasm_2_0")] CosmosMsg::Any(any) => CosmosMsg::Any(any), diff --git a/src/featured.rs b/src/featured.rs new file mode 100644 index 00000000..9d916182 --- /dev/null +++ b/src/featured.rs @@ -0,0 +1,43 @@ +//! # Definitions enabled or disabled by crate's features + +#[cfg(feature = "stargate")] +pub use cosmwasm_std::GovMsg; + +#[cfg(not(feature = "stargate"))] +pub use cosmwasm_std::Empty as GovMsg; + +#[cfg(feature = "staking")] +pub mod staking { + pub use crate::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking, StakingSudo}; +} + +#[cfg(not(feature = "staking"))] +pub mod staking { + use crate::error::AnyResult; + use crate::{AppResponse, CosmosRouter, FailingModule, Module}; + use cosmwasm_std::{Api, BlockInfo, CustomMsg, CustomQuery, Empty, Storage}; + + pub enum StakingSudo {} + + pub trait Staking: Module { + fn process_queue( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + ) -> AnyResult { + Ok(AppResponse::default()) + } + } + + pub type StakeKeeper = FailingModule; + + impl Staking for StakeKeeper {} + + pub trait Distribution: Module {} + + pub type DistributionKeeper = FailingModule; + + impl Distribution for DistributionKeeper {} +} diff --git a/src/gov.rs b/src/gov.rs index f2c01940..66e9dc47 100644 --- a/src/gov.rs +++ b/src/gov.rs @@ -1,15 +1,19 @@ +use crate::featured::GovMsg; use crate::{AcceptingModule, FailingModule, Module}; -use cosmwasm_std::{Empty, GovMsg}; +use cosmwasm_std::Empty; + /// Handles governance-related operations within the test environment. /// This trait is essential for testing contracts that interact with governance mechanisms, /// simulating proposals, voting, and other governance activities. pub trait Gov: Module {} + /// A type alias for a module that accepts governance-related interactions. /// It's used in scenarios where you need to test how your contract interacts /// with governance processes and messages. pub type GovAcceptingModule = AcceptingModule; impl Gov for GovAcceptingModule {} + /// This type alias represents a module designed to fail in response to governance operations. /// It's useful for testing how contracts behave when governance actions do not proceed as expected. pub type GovFailingModule = FailingModule; diff --git a/src/lib.rs b/src/lib.rs index e5d3f24c..76f1413b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -134,10 +134,12 @@ mod contracts; pub mod custom_handler; pub mod error; mod executor; +mod featured; mod gov; mod ibc; mod module; mod prefixed_storage; +#[cfg(feature = "staking")] mod staking; mod stargate; mod test_helpers; @@ -160,6 +162,7 @@ pub use crate::executor::{AppResponse, Executor}; pub use crate::gov::{Gov, GovAcceptingModule, GovFailingModule}; pub use crate::ibc::{Ibc, IbcAcceptingModule, IbcFailingModule}; pub use crate::module::{AcceptingModule, FailingModule, Module}; +#[cfg(feature = "staking")] pub use crate::staking::{ Distribution, DistributionKeeper, StakeKeeper, Staking, StakingInfo, StakingSudo, }; diff --git a/src/test_helpers/mod.rs b/src/test_helpers/mod.rs index d6ee1adc..c3f47c02 100644 --- a/src/test_helpers/mod.rs +++ b/src/test_helpers/mod.rs @@ -8,11 +8,14 @@ use serde::{Deserialize, Serialize}; pub mod caller; pub mod echo; pub mod error; +#[cfg(feature = "stargate")] pub mod gov; pub mod hackatom; +#[cfg(feature = "stargate")] pub mod ibc; pub mod payout; pub mod reflect; +#[cfg(feature = "stargate")] pub mod stargate; /// Custom message for testing purposes. diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 2f5d2092..39470562 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -3,6 +3,9 @@ mod test_app; mod test_custom_handler; mod test_error; +#[cfg(feature = "stargate")] mod test_gov; +#[cfg(feature = "stargate")] mod test_ibc; +#[cfg(feature = "stargate")] mod test_stargate; diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 2c459e76..7c078b5b 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -1,12 +1,13 @@ use crate::custom_handler::CachingCustomHandler; use crate::error::{bail, AnyResult}; +use crate::featured::staking::{Distribution, Staking}; use crate::test_helpers::echo::EXECUTE_REPLY_BASE_ID; use crate::test_helpers::{caller, echo, error, hackatom, payout, reflect, CustomHelperMsg}; use crate::transactions::{transactional, StorageTransaction}; use crate::wasm::ContractData; use crate::{ - custom_app, next_block, no_init, App, AppResponse, Bank, CosmosRouter, Distribution, Executor, - Module, Router, Staking, Wasm, WasmSudo, + custom_app, next_block, no_init, App, AppResponse, Bank, CosmosRouter, Executor, Module, + Router, Wasm, WasmSudo, }; use crate::{AppBuilder, IntoAddr}; use cosmwasm_std::testing::{mock_env, MockQuerier}; diff --git a/src/wasm.rs b/src/wasm.rs index b92a8d18..42ec07cd 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1254,8 +1254,8 @@ mod test { use super::*; use crate::app::Router; use crate::bank::BankKeeper; + use crate::featured::staking::{DistributionKeeper, StakeKeeper}; use crate::module::FailingModule; - use crate::staking::{DistributionKeeper, StakeKeeper}; use crate::test_helpers::{caller, error, payout}; use crate::transactions::StorageTransaction; use crate::{GovFailingModule, IbcFailingModule, StargateFailing}; diff --git a/tests/mod.rs b/tests/mod.rs index feb7b9ea..4dcf2199 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -8,6 +8,7 @@ mod test_bank; mod test_contract_storage; mod test_module; mod test_prefixed_storage; +#[cfg(feature = "staking")] mod test_staking; mod test_wasm; diff --git a/tests/test_app_builder/mod.rs b/tests/test_app_builder/mod.rs index 6c8bf260..4df6f918 100644 --- a/tests/test_app_builder/mod.rs +++ b/tests/test_app_builder/mod.rs @@ -8,17 +8,20 @@ use std::marker::PhantomData; mod test_with_api; mod test_with_bank; mod test_with_block; +#[cfg(feature = "staking")] mod test_with_distribution; +#[cfg(feature = "stargate")] mod test_with_gov; +#[cfg(feature = "stargate")] mod test_with_ibc; +#[cfg(feature = "staking")] mod test_with_staking; +#[cfg(feature = "stargate")] mod test_with_stargate; mod test_with_storage; #[cfg(feature = "cosmwasm_1_2")] mod test_with_wasm; -const NO_MESSAGE: &str = ""; - struct MyKeeper( PhantomData<(ExecT, QueryT, SudoT)>, &'static str, diff --git a/tests/test_app_builder/test_with_distribution.rs b/tests/test_app_builder/test_with_distribution.rs index fe6a6f46..fc78fef5 100644 --- a/tests/test_app_builder/test_with_distribution.rs +++ b/tests/test_app_builder/test_with_distribution.rs @@ -1,4 +1,4 @@ -use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; +use crate::test_app_builder::MyKeeper; use cosmwasm_std::{DistributionMsg, Empty}; use cw_multi_test::{no_init, AppBuilder, Distribution, Executor}; @@ -12,7 +12,7 @@ const EXECUTE_MSG: &str = "distribution execute called"; fn building_app_with_custom_distribution_should_work() { // build custom distribution keeper // which has no query or sudo messages - let distribution_keeper = MyDistributionKeeper::new(EXECUTE_MSG, NO_MESSAGE, NO_MESSAGE); + let distribution_keeper = MyDistributionKeeper::new(EXECUTE_MSG, "", ""); // build the application with custom distribution keeper let app_builder = AppBuilder::default(); diff --git a/tests/test_app_builder/test_with_gov.rs b/tests/test_app_builder/test_with_gov.rs index f1f8e0fe..f7626eba 100644 --- a/tests/test_app_builder/test_with_gov.rs +++ b/tests/test_app_builder/test_with_gov.rs @@ -1,4 +1,4 @@ -use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; +use crate::test_app_builder::MyKeeper; use cosmwasm_std::{Empty, GovMsg, VoteOption}; use cw_multi_test::{no_init, AppBuilder, Executor, Gov}; @@ -11,7 +11,7 @@ const EXECUTE_MSG: &str = "gov execute called"; #[test] fn building_app_with_custom_gov_should_work() { // build custom governance keeper (no query and sudo handling for gov module) - let gov_keeper = MyGovKeeper::new(EXECUTE_MSG, NO_MESSAGE, NO_MESSAGE); + let gov_keeper = MyGovKeeper::new(EXECUTE_MSG, "", ""); // build the application with custom gov keeper let mut app = AppBuilder::default().with_gov(gov_keeper).build(no_init); diff --git a/tests/test_app_builder/test_with_ibc.rs b/tests/test_app_builder/test_with_ibc.rs index f9a77ba3..c92e7c08 100644 --- a/tests/test_app_builder/test_with_ibc.rs +++ b/tests/test_app_builder/test_with_ibc.rs @@ -1,4 +1,4 @@ -use crate::test_app_builder::{MyKeeper, NO_MESSAGE}; +use crate::test_app_builder::MyKeeper; use cosmwasm_std::{Empty, IbcMsg, IbcQuery, QueryRequest}; use cw_multi_test::{no_init, AppBuilder, Executor, Ibc}; @@ -12,7 +12,7 @@ const QUERY_MSG: &str = "ibc query called"; #[test] fn building_app_with_custom_ibc_should_work() { // build custom ibc keeper (no sudo handling for ibc) - let ibc_keeper = MyIbcKeeper::new(EXECUTE_MSG, QUERY_MSG, NO_MESSAGE); + let ibc_keeper = MyIbcKeeper::new(EXECUTE_MSG, QUERY_MSG, ""); // build the application with custom ibc keeper let mut app = AppBuilder::default().with_ibc(ibc_keeper).build(no_init); diff --git a/tests/test_app_builder/test_with_stargate.rs b/tests/test_app_builder/test_with_stargate.rs index 3bb09844..41e40f74 100644 --- a/tests/test_app_builder/test_with_stargate.rs +++ b/tests/test_app_builder/test_with_stargate.rs @@ -206,6 +206,7 @@ fn building_app_with_accepting_any_grpc_should_work() { } #[test] +#[cfg(feature = "stargate")] fn default_failing_stargate_should_work() { let app_builder = AppBuilder::default(); let mut app = app_builder.with_stargate(StargateFailing).build(no_init); From a62f5f51510388ea7916961809f051d413214674 Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Tue, 25 Jun 2024 13:22:04 +0200 Subject: [PATCH 230/250] Added lacking changelog items. --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2758683..4bd41a3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,23 @@ - V2: upgrading dependencies and refactoring [\#128](https://github.com/CosmWasm/cw-multi-test/pull/128) ([DariuszDepta](https://github.com/DariuszDepta)) +## [v1.2.0](https://github.com/CosmWasm/cw-multi-test/tree/v1.2.0) (2024-06-12) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v1.1.0...v1.2.0) + +**Merged pull requests:** + +- Backport: Removed validation of empty attribute value [\#181](https://github.com/CosmWasm/cw-multi-test/pull/181) ([DariuszDepta](https://github.com/DariuszDepta)) + +## [v1.1.0](https://github.com/CosmWasm/cw-multi-test/tree/v1.1.0) (2024-04-23) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v1.0.0...v1.1.0) + +**Merged pull requests:** + +- Backport: Expose contract storage [\#155](https://github.com/CosmWasm/cw-multi-test/issues/155) ([DariuszDepta](https://github.com/DariuszDepta)) +- Backport: Expose prefixed storage [\#156](https://github.com/CosmWasm/cw-multi-test/issues/156) ([DariuszDepta](https://github.com/DariuszDepta)) + ## [v1.0.0](https://github.com/CosmWasm/cw-multi-test/tree/v1.0.0) (2024-03-22) [Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.20.1...v1.0.0) From 9bf00a53ff30f456fe64a7817504ac16e2901410 Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Fri, 28 Jun 2024 12:37:32 +0200 Subject: [PATCH 231/250] Prepared release v2.1.0-rc.1 (#193) --- CHANGELOG.md | 25 +++++++++++++++++++++++++ Cargo.lock | 32 ++++++++++++++++---------------- Cargo.toml | 2 +- 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bd41a3a..8cea6863 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # Changelog +## [v2.1.0-rc.1](https://github.com/CosmWasm/cw-multi-test/tree/v2.1.0-rc.1) (2024-06-28) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v2.0.1...v2.1.0-rc.1) + +**Closed issues:** + +- `StakingSudo::ProcessQueue` is still necessary, despite deprecation warnings [\#127](https://github.com/CosmWasm/cw-multi-test/issues/127) +- Cosmwasm Std Empty String Attribute Causes Failure [\#178](https://github.com/CosmWasm/cw-multi-test/issues/178) +- Don't validate validator addresses [\#173](https://github.com/CosmWasm/cw-multi-test/issues/173) +- Using `addr_make` inside `AppBuilder::build` [\#180](https://github.com/CosmWasm/cw-multi-test/issues/188) + +**Merged pull requests:** + +- Removed `cosmwasm-std` features from dependencies [\#191](https://github.com/CosmWasm/cw-multi-test/pull/191) ([DariuszDepta](https://github.com/DariuszDepta)) +- Enabled using `addr_make` inside `AppBuilder::build` [\#189](https://github.com/CosmWasm/cw-multi-test/pull/189) ([DariuszDepta](https://github.com/DariuszDepta)) +- Do not validate validator addresses [\#183](https://github.com/CosmWasm/cw-multi-test/pull/183) ([DariuszDepta](https://github.com/DariuszDepta)) +- Refactoring staking module, part 2 [\#186](https://github.com/CosmWasm/cw-multi-test/pull/186) ([DariuszDepta](https://github.com/DariuszDepta)) +- Refactoring staking module, part 1 [\#185](https://github.com/CosmWasm/cw-multi-test/pull/185) ([DariuszDepta](https://github.com/DariuszDepta)) +- Removed validation of empty attribute value [\#180](https://github.com/CosmWasm/cw-multi-test/pull/180) ([DariuszDepta](https://github.com/DariuszDepta)) +- Improved unstake handling [\#179](https://github.com/CosmWasm/cw-multi-test/pull/179) ([DariuszDepta](https://github.com/DariuszDepta)) +- Remove default features [\#175](https://github.com/CosmWasm/cw-multi-test/pull/175) ([DariuszDepta](https://github.com/DariuszDepta)) +- Feature-gates in pattern matching of CosmWasm 2.0 Enum Variants [\#170](https://github.com/CosmWasm/cw-multi-test/pull/170) ([AmitPr](https://github.com/AmitPr)) +- Upgraded dependencies [\#168](https://github.com/CosmWasm/cw-multi-test/pull/168) ([DariuszDepta](https://github.com/DariuszDepta)) +- Added lacking changelog items [\#192](https://github.com/CosmWasm/cw-multi-test/pull/192) ([DariuszDepta](https://github.com/DariuszDepta)) + ## [v2.0.1](https://github.com/CosmWasm/cw-multi-test/tree/v2.0.1) (2024-04-22) [Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v2.0.0...v2.0.1) diff --git a/Cargo.lock b/Cargo.lock index e010c172..242a0b00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,9 +120,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.99" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d" [[package]] name = "cfg-if" @@ -250,7 +250,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "2.0.1" +version = "2.1.0-rc.1" dependencies = [ "anyhow", "bech32 0.11.0", @@ -372,9 +372,9 @@ dependencies = [ [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elliptic-curve" @@ -599,7 +599,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -669,7 +669,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -712,7 +712,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -723,14 +723,14 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" dependencies = [ "itoa", "ryu", @@ -789,9 +789,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "subtle" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d0208408ba0c3df17ed26eb06992cb1a1268d41b2c0e12e65203fbe3972cee5" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -806,9 +806,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.67" +version = "2.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff8655ed1d86f3af4ee3fd3263786bc14245ad17c4c7e85ba7187fb3ae028c90" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" dependencies = [ "proc-macro2", "quote", @@ -832,7 +832,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index aa6add42..cf7c4574 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "2.0.1" +version = "2.1.0-rc.1" authors = [ "Ethan Frey ", "Dariusz Depta " From a22abee6be37c66396c1ec0b3e7ae71d5f744f9a Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Fri, 5 Jul 2024 11:14:48 +0200 Subject: [PATCH 232/250] Release_v2_1_0 (#198) --- Cargo.lock | 14 +++++++------- Cargo.toml | 2 +- README.md | 53 ++++++++++++++++++++++++++++++++--------------------- 3 files changed, 40 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 242a0b00..4f5ec9d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,9 +120,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.101" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d" +checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490" [[package]] name = "cfg-if" @@ -250,7 +250,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "2.1.0-rc.1" +version = "2.1.0" dependencies = [ "anyhow", "bech32 0.11.0", @@ -541,9 +541,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" dependencies = [ "memchr", ] @@ -728,9 +728,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.118" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa", "ryu", diff --git a/Cargo.toml b/Cargo.toml index cf7c4574..ac187193 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "2.1.0-rc.1" +version = "2.1.0" authors = [ "Ethan Frey ", "Dariusz Depta " diff --git a/README.md b/README.md index cc028d95..f9898d6b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# CosmWasm MultiTest +# CosmWasm MultiTest [![cw-multi-test on crates.io][crates-badge]][crates-url] [![docs][docs-badge]][docs-url] @@ -17,40 +17,51 @@ **Testing tools for multi-contract interactions** -## Introduction +## Introduction -**CosmWasm MultiTest** is a suite of testing tools designed for facilitating multi-contract +**CosmWasm MultiTest** is a suite of testing tools designed for facilitating multi-contract interactions within the [CosmWasm](https://github.com/CosmWasm) ecosystem. Its primary focus is on providing developers with a robust framework for simulating -complex contract interactions and bank operations. Currently, **CosmWasm MultiTest** -is in the _alpha_ stage, and primarily used internally for testing -[cw-plus](https://github.com/CosmWasm/cw-plus) contracts. +complex contract interactions and bank operations. -## Current Status - -### Internal Use and Refinement - -Internally, the **CosmWasm MultiTest** framework is an essential tool for the -testing of cw-plus contracts. Its development is focused on ensuring the reliability -and security of these contracts. The team is actively working on refactoring and enhancing -**CosmWasm MultiTest** to provide a more stable and feature-rich version for broader -community use in the future. - -### Framework Capabilities +## Library Capabilities **CosmWasm MultiTest** enables comprehensive unit testing, including scenarios where contracts -call other contracts and interact with the bank module. Its current implementation +call other contracts and interact with several modules like bank and staking. Its current implementation effectively handles these interactions, providing a realistic testing environment for contract developers. -The team is committed to extending **CosmWasm MultiTest**'s capabilities, making it a versatile tool +The team is committed to extending **CosmWasm MultiTest**'s capabilities, making it a versatile tool for various blockchain interaction tests. -## Conclusion +## Feature flags + +**CosmWasm MultiTest** library provides several feature flags that can be enabled like shown below: + +```toml +[dev-dependencies] +cw-multi-test = { version = "2.1.0", features = ["staking", "stargate", "cosmwasm_2_0"] } +``` + +Since version 2.1.0, **CosmWasm MultiTest** has no default features enabled. +The table below summarizes all available features: + +| Feature | Description | +|------------------|----------------------------------------------------------------------------------------------------| +| **backtrace** | Enables `backtrace` feature in **anyhow** dependency. | +| **staking** | Enables `staking` feature in **cosmwasm-std** dependency. | +| **stargate** | Enables `stargate` feature in **cosmwasm-std** dependency. | +| **cosmwasm_1_1** | Enables `cosmwasm_1_1` feature in **cosmwasm-std** dependency. | +| **cosmwasm_1_2** | Enables `cosmwasm_1_1` in **MultiTest** and `cosmwasm_1_2` feature in **cosmwasm-std** dependency. | +| **cosmwasm_1_3** | Enables `cosmwasm_1_2` in **MultiTest** and `cosmwasm_1_3` feature in **cosmwasm-std** dependency. | +| **cosmwasm_1_4** | Enables `cosmwasm_1_3` in **MultiTest** and `cosmwasm_1_4` feature in **cosmwasm-std** dependency. | +| **cosmwasm_2_0** | Enables `cosmwasm_1_4` in **MultiTest** and `cosmwasm_2_0` feature in **cosmwasm-std** dependency. | + +## Conclusion **CosmWasm MultiTest** stands as a vital development tool in the [CosmWasm](https://github.com/CosmWasm) ecosystem, especially for developers engaged in building complex decentralized applications. As the framework evolves, it is poised to become an even more integral part of the [CosmWasm](https://github.com/CosmWasm) development toolkit. -Users are encouraged to stay updated with its progress and contribute to its development. +Users are encouraged to stay updated with its progress and contribute to its development. ## License From b5ca81a7105e1c790f3443785e58deb7eda3ab99 Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Fri, 5 Jul 2024 12:05:20 +0200 Subject: [PATCH 233/250] Updated changelog. (#199) --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cea6863..99cd8f07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [v2.1.0-rc.1](https://github.com/CosmWasm/cw-multi-test/tree/v2.1.0-rc.1) (2024-06-28) +## [v2.1.0](https://github.com/CosmWasm/cw-multi-test/tree/v2.1.0) (2024-07-05) -[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v2.0.1...v2.1.0-rc.1) +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v2.0.1...v2.1.0) **Closed issues:** From 815397f5ac44d2310881db0cd20c0e2cfcb1c035 Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Wed, 10 Jul 2024 13:43:50 +0200 Subject: [PATCH 234/250] Upgraded dependencies. (#200) --- Cargo.lock | 47 +++++++++++++++++++---------------------------- Cargo.toml | 4 ++-- 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f5ec9d9..8c7d8177 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,9 +120,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.104" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490" +checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8" [[package]] name = "cfg-if" @@ -260,7 +260,7 @@ dependencies = [ "derivative", "hex", "hex-literal", - "itertools 0.13.0", + "itertools", "once_cell", "prost", "schemars", @@ -480,15 +480,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -581,9 +572,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.6" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc" dependencies = [ "bytes", "prost-derive", @@ -591,15 +582,15 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.6" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -669,7 +660,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -688,9 +679,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] @@ -706,13 +697,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -723,7 +714,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -806,9 +797,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.68" +version = "2.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" dependencies = [ "proc-macro2", "quote", @@ -832,7 +823,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ac187193..872e3881 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,9 +30,9 @@ cw-storage-plus = "2.0.0" cw-utils = "2.0.0" derivative = "2.2.0" itertools = "0.13.0" -prost = "0.12.6" +prost = "0.13.1" schemars = "0.8.21" -serde = "1.0.203" +serde = "1.0.204" sha2 = "0.10.8" thiserror = "1.0.61" From 25bc03b6864056fa6de360b14cdabcc603586bf6 Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Tue, 6 Aug 2024 15:16:11 +0200 Subject: [PATCH 235/250] Upgraded dependencies (#202) --- .circleci/config.yml | 38 +- Cargo.lock | 606 ++++++++++++++++++++++++-------- Cargo.toml | 4 +- tests/test_api/test_prefixed.rs | 2 +- 4 files changed, 488 insertions(+), 162 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 50ebb17b..8f29a39a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -30,7 +30,7 @@ workflows: jobs: build_and_test: docker: - - image: rust:1.70 + - image: rust:1.75 working_directory: ~/project steps: - checkout @@ -42,8 +42,8 @@ jobs: command: cargo update - restore_cache: keys: - - cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} - - cargocache-v2-multi-test:1.70- + - cargocache-v2-multi-test:1.75-{{ checksum "Cargo.lock" }} + - cargocache-v2-multi-test:1.75- - run: name: Build library for native target command: cargo build --locked @@ -54,12 +54,12 @@ jobs: paths: - /usr/local/cargo/registry - target - key: cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} + key: cargocache-v2-multi-test:1.75-{{ checksum "Cargo.lock" }} build_minimal: docker: - image: rustlang/rust:nightly - working_directory: ~/project/ + working_directory: ~/project steps: - checkout - run: @@ -68,9 +68,13 @@ jobs: - run: name: Remove Cargo.lock command: rm Cargo.lock + # Remove the following command after dependencies in crates ahash and num-bigint are upgraded! + - run: + name: Temporarily update problematic crates + command: cargo update -p ahash && cargo update -p num-bigint - restore_cache: keys: - - cargocache-v2-multi-test:1.70-minimal-{{ checksum "Cargo.toml" }} + - cargocache-v2-multi-test:1.75-minimal-{{ checksum "Cargo.toml" }} - run: name: Build library for native target command: cargo build -Zminimal-versions --all-features @@ -81,12 +85,12 @@ jobs: paths: - /usr/local/cargo/registry - target - key: cargocache-v2-multi-test:1.70-minimal-{{ checksum "Cargo.toml" }} + key: cargocache-v2-multi-test:1.75-minimal-{{ checksum "Cargo.toml" }} build_maximal: docker: - - image: rust:1.70 - working_directory: ~/project/ + - image: rust:1.75 + working_directory: ~/project steps: - checkout - run: @@ -97,7 +101,7 @@ jobs: command: cargo update - restore_cache: keys: - - cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} + - cargocache-v2-multi-test:1.75-{{ checksum "Cargo.lock" }} - run: name: Build library for native target command: cargo build --locked --all-features @@ -108,11 +112,11 @@ jobs: paths: - /usr/local/cargo/registry - target - key: cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} + key: cargocache-v2-multi-test:1.75-{{ checksum "Cargo.lock" }} lint: docker: - - image: rust:1.70 + - image: rust:1.75 steps: - checkout - run: @@ -123,8 +127,8 @@ jobs: command: cargo update - restore_cache: keys: - - cargocache-v2-lint-rust:1.70-{{ checksum "Cargo.lock" }} - - cargocache-v2-lint-rust:1.70- + - cargocache-v2-lint-rust:1.75-{{ checksum "Cargo.lock" }} + - cargocache-v2-lint-rust:1.75- - run: name: Add rustfmt component command: rustup component add rustfmt @@ -143,19 +147,19 @@ jobs: - target/debug/.fingerprint - target/debug/build - target/debug/deps - key: cargocache-v2-lint-rust:1.70-{{ checksum "Cargo.lock" }} + key: cargocache-v2-lint-rust:1.75-{{ checksum "Cargo.lock" }} coverage: # https://circleci.com/developer/images?imageType=machine machine: - image: ubuntu-2204:2024.01.1 + image: ubuntu-2404:2024.05.1 steps: - checkout - run: name: Run tests with coverage command: | mkdir -p cov - docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.1 \ + docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.31.0 \ sh -c "cargo tarpaulin --workspace --all-features --force-clean --engine llvm --out xml --output-dir cov" - codecov/upload: file: cov/cobertura.xml diff --git a/Cargo.lock b/Cargo.lock index 8c7d8177..73b8b583 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,15 +19,22 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ - "getrandom", + "cfg-if", "once_cell", "version_check", + "zerocopy", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "anyhow" version = "1.0.86" @@ -37,6 +44,133 @@ dependencies = [ "backtrace", ] +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "rayon", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rayon", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", + "rayon", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + [[package]] name = "backtrace" version = "0.3.73" @@ -60,21 +194,9 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64ct" -version = "1.6.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bech32" @@ -82,15 +204,6 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -102,9 +215,9 @@ dependencies = [ [[package]] name = "bnum" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56953345e39537a3e18bdaeba4cb0c58a78c1f61f361dc0fa7c5c7340ae87c5f" +checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790" [[package]] name = "byteorder" @@ -114,15 +227,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.0" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8" +checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" [[package]] name = "cfg-if" @@ -136,33 +249,51 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "cosmwasm-core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "367fc87c43759098a476ef90f915aadc66c300480ad9c155b512081fbf327bc1" + [[package]] name = "cosmwasm-crypto" -version = "2.0.4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a339f6b59ff7ad4ae05a70512a4f3c19bf8fcc845d46bfef90f4ec0810f72c" +checksum = "9b7c41f3e371ea457d3b98bb592c38858b46efcf614e0e988ec2ebbdb973954f" dependencies = [ - "digest 0.10.7", + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-serialize", + "cosmwasm-core", + "digest", + "ecdsa", "ed25519-zebra", "k256", - "rand_core 0.6.4", + "num-traits", + "p256", + "rand_core", + "rayon", + "sha2", "thiserror", ] [[package]] name = "cosmwasm-derive" -version = "2.0.4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d3bfea6af94a83880fb05478135ed0c256d9a2fcde58c595a10d64dcb9c925d" +checksum = "c10510e8eb66cf7e109741b1e2c76ad18f30b5a1daa064f5f7115c1f733aaea0" dependencies = [ - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.72", ] [[package]] name = "cosmwasm-schema" -version = "2.0.4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "101d0739564bd34cba9b84bf73665f0822487ae3b29b2dd59930608ed3aafd43" +checksum = "f79879b6b7ef6a331b05030ce91ce46a7c4b0baf1ed6b382cce2e9a168109380" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -173,33 +304,34 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.0.4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4be75f60158478da2c5d319ed59295bca1687ad50c18215a0485aa91a995ea" +checksum = "82b53e33c0e97170c7ac9cb440f4bc599a07f9cbb9b7e87916cca37b1239d57b" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] name = "cosmwasm-std" -version = "2.0.4" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded932165de44cd0717979c34fc3b84d8e8066b8dde4f5bd78f96a643b090f90" +checksum = "92011c39570876f340d5f9defa68bf92797b1c44421f1b9ea9b04a31d6defd33" dependencies = [ "base64", - "bech32 0.9.1", + "bech32", "bnum", + "cosmwasm-core", "cosmwasm-crypto", "cosmwasm-derive", - "derivative", - "forward_ref", + "derive_more", "hex", + "rand_core", "schemars", "serde", "serde-json-wasm", - "sha2 0.10.8", + "sha2", "static_assertions", "thiserror", ] @@ -213,6 +345,31 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -220,7 +377,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -237,35 +394,49 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.2.0" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "cw-multi-test" version = "2.1.0" dependencies = [ "anyhow", - "bech32 0.11.0", + "bech32", "cosmwasm-std", "cw-storage-plus", "cw-utils", "derivative", "hex", "hex-literal", - "itertools", + "itertools 0.13.0", "once_cell", "prost", "schemars", "serde", - "sha2 0.10.8", + "sha2", "thiserror", ] @@ -315,12 +486,24 @@ dependencies = [ ] [[package]] -name = "digest" -version = "0.9.0" +name = "derive_more" +version = "1.0.0-beta.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +checksum = "3249c0372e72f5f93b5c0ca54c0ab76bbf6216b6f718925476fd9bc4ffabb4fe" dependencies = [ - "generic-array", + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0-beta.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27d919ced7590fc17b5d5a3c63b662e8a7d2324212c4e4dbbed975cafd22d16d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", + "unicode-xid", ] [[package]] @@ -329,7 +512,7 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", "const-oid", "crypto-common", "subtle", @@ -348,25 +531,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", - "digest 0.10.7", + "digest", "elliptic-curve", "rfc6979", "signature", - "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature", ] [[package]] name = "ed25519-zebra" -version = "3.1.0" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" dependencies = [ "curve25519-dalek", - "hashbrown", + "ed25519", + "hashbrown 0.14.5", "hex", - "rand_core 0.6.4", - "serde", - "sha2 0.9.9", + "rand_core", + "sha2", "zeroize", ] @@ -384,12 +575,11 @@ checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", - "digest 0.10.7", + "digest", "ff", "generic-array", "group", - "pkcs8", - "rand_core 0.6.4", + "rand_core", "sec1", "subtle", "zeroize", @@ -401,15 +591,15 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle", ] [[package]] -name = "forward_ref" -version = "1.0.0" +name = "fiat-crypto" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "generic-array" @@ -446,19 +636,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core 0.6.4", + "rand_core", "subtle", ] [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + [[package]] name = "hex" version = "0.4.3" @@ -477,7 +677,16 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.7", + "digest", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", ] [[package]] @@ -504,9 +713,7 @@ dependencies = [ "cfg-if", "ecdsa", "elliptic-curve", - "once_cell", - "sha2 0.10.8", - "signature", + "sha2", ] [[package]] @@ -530,11 +737,39 @@ dependencies = [ "adler", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "object" -version = "0.36.1" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" dependencies = [ "memchr", ] @@ -546,19 +781,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] -name = "opaque-debug" -version = "0.3.1" +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "paste" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] -name = "pkcs8" -version = "0.10.2" +name = "ppv-lite86" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "der", - "spki", + "zerocopy", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", ] [[package]] @@ -587,10 +842,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" dependencies = [ "anyhow", - "itertools", + "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.72", ] [[package]] @@ -603,10 +858,24 @@ dependencies = [ ] [[package]] -name = "rand_core" -version = "0.5.1" +name = "rand" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] [[package]] name = "rand_core" @@ -617,6 +886,26 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "rfc6979" version = "0.4.0" @@ -633,6 +922,15 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "ryu" version = "1.0.18" @@ -660,7 +958,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.70", + "syn 2.0.72", ] [[package]] @@ -672,11 +970,16 @@ dependencies = [ "base16ct", "der", "generic-array", - "pkcs8", "subtle", "zeroize", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" version = "1.0.204" @@ -703,7 +1006,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.72", ] [[package]] @@ -714,33 +1017,21 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.72", ] [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - [[package]] name = "sha2" version = "0.10.8" @@ -749,7 +1040,7 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] @@ -758,18 +1049,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest 0.10.7", - "rand_core 0.6.4", -] - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", + "digest", + "rand_core", ] [[package]] @@ -797,9 +1078,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.70" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", @@ -808,22 +1089,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.72", ] [[package]] @@ -838,11 +1119,17 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" @@ -850,8 +1137,43 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] diff --git a/Cargo.toml b/Cargo.toml index 872e3881..f07aaca2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ cosmwasm_2_0 = ["cosmwasm_1_4", "cosmwasm-std/cosmwasm_2_0"] [dependencies] anyhow = "1.0.86" bech32 = "0.11.0" -cosmwasm-std = "2.0.4" +cosmwasm-std = "2.1.1" cw-storage-plus = "2.0.0" cw-utils = "2.0.0" derivative = "2.2.0" @@ -34,7 +34,7 @@ prost = "0.13.1" schemars = "0.8.21" serde = "1.0.204" sha2 = "0.10.8" -thiserror = "1.0.61" +thiserror = "1.0.63" [dev-dependencies] hex = "0.4.3" diff --git a/tests/test_api/test_prefixed.rs b/tests/test_api/test_prefixed.rs index 1feff2d5..3890278c 100644 --- a/tests/test_api/test_prefixed.rs +++ b/tests/test_api/test_prefixed.rs @@ -68,7 +68,7 @@ fn debug_should_not_panic() { } #[test] -#[should_panic(expected = "Generating address failed with reason: invalid length")] +#[should_panic] fn address_make_prefix_too_long() { api_prefix( "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_", From aa8e0e41d65a2a7fe81d25e5f78146f9953a5bcf Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Mon, 19 Aug 2024 11:03:41 +0200 Subject: [PATCH 236/250] Updated docs.rs metadata. (#204) --- Cargo.lock | 95 ++++++++++++++++++++++++++++++------------------------ Cargo.toml | 7 ++-- 2 files changed, 57 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 73b8b583..6616fb7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -233,9 +233,12 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.7" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -251,15 +254,15 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-core" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "367fc87c43759098a476ef90f915aadc66c300480ad9c155b512081fbf327bc1" +checksum = "d905990ef3afb5753bb709dc7de88e9e370aa32bcc2f31731d4b533b63e82490" [[package]] name = "cosmwasm-crypto" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7c41f3e371ea457d3b98bb592c38858b46efcf614e0e988ec2ebbdb973954f" +checksum = "5b2a7bd9c1dd9a377a4dc0f4ad97d24b03c33798cd5a6d7ceb8869b41c5d2f2d" dependencies = [ "ark-bls12-381", "ark-ec", @@ -280,20 +283,20 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c10510e8eb66cf7e109741b1e2c76ad18f30b5a1daa064f5f7115c1f733aaea0" +checksum = "029910b409398fdf81955d7301b906caf81f2c42b013ea074fbd89720229c424" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] name = "cosmwasm-schema" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79879b6b7ef6a331b05030ce91ce46a7c4b0baf1ed6b382cce2e9a168109380" +checksum = "4bc0d4d85e83438ab9a0fea9348446f7268bc016aacfebce37e998559f151294" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -304,20 +307,20 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b53e33c0e97170c7ac9cb440f4bc599a07f9cbb9b7e87916cca37b1239d57b" +checksum = "edf5c8adac41bb7751c050d7c4c18675be19ee128714454454575e894424eeef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] name = "cosmwasm-std" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92011c39570876f340d5f9defa68bf92797b1c44421f1b9ea9b04a31d6defd33" +checksum = "51dec99a2e478715c0a4277f0dbeadbb8466500eb7dec873d0924edd086e77f1" dependencies = [ "base64", "bech32", @@ -338,9 +341,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -416,7 +419,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -487,22 +490,22 @@ dependencies = [ [[package]] name = "derive_more" -version = "1.0.0-beta.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3249c0372e72f5f93b5c0ca54c0ab76bbf6216b6f718925476fd9bc4ffabb4fe" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "1.0.0-beta.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27d919ced7590fc17b5d5a3c63b662e8a7d2324212c4e4dbbed975cafd22d16d" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", "unicode-xid", ] @@ -718,9 +721,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.155" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "memchr" @@ -767,9 +770,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.2" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "memchr", ] @@ -845,7 +848,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -958,7 +961,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -982,9 +985,9 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] @@ -1000,13 +1003,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -1017,14 +1020,14 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] name = "serde_json" -version = "1.0.122" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" +checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" dependencies = [ "itoa", "memchr", @@ -1043,6 +1046,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signature" version = "2.2.0" @@ -1078,9 +1087,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" dependencies = [ "proc-macro2", "quote", @@ -1104,7 +1113,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -1155,7 +1164,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -1175,5 +1184,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] diff --git a/Cargo.toml b/Cargo.toml index f07aaca2..6d6cc21d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,9 @@ homepage = "https://cosmwasm.com" license = "Apache-2.0" edition = "2021" +[package.metadata.docs.rs] +all-features = true + [features] default = [] backtrace = ["anyhow/backtrace"] @@ -25,14 +28,14 @@ cosmwasm_2_0 = ["cosmwasm_1_4", "cosmwasm-std/cosmwasm_2_0"] [dependencies] anyhow = "1.0.86" bech32 = "0.11.0" -cosmwasm-std = "2.1.1" +cosmwasm-std = "2.1.3" cw-storage-plus = "2.0.0" cw-utils = "2.0.0" derivative = "2.2.0" itertools = "0.13.0" prost = "0.13.1" schemars = "0.8.21" -serde = "1.0.204" +serde = "1.0.208" sha2 = "0.10.8" thiserror = "1.0.63" From 82e6f0adcd7701d3a7111b9dca25b61596ccae09 Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Tue, 20 Aug 2024 10:56:55 +0200 Subject: [PATCH 237/250] Prepared release v2.1.1 (#205) --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99cd8f07..ac331a58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [v2.1.1](https://github.com/CosmWasm/cw-multi-test/tree/v2.1.1) (2024-08-20) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v2.1.0...v2.1.1) + +**Closed issues:** + +- Fix documentation metadata [\#203](https://github.com/CosmWasm/cw-multi-test/issues/203) + +**Merged pull requests:** + +- Fixed documentation metadata [\#204](https://github.com/CosmWasm/cw-multi-test/pull/204) ([DariuszDepta](https://github.com/DariuszDepta)) + ## [v2.1.0](https://github.com/CosmWasm/cw-multi-test/tree/v2.1.0) (2024-07-05) [Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v2.0.1...v2.1.0) From f520a26d832a6664de4ee08b1c376c39fbd03245 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 20 Aug 2024 11:06:24 +0200 Subject: [PATCH 238/250] Updated Cargo.lock --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6616fb7d..ab672af0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1130,9 +1130,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "version_check" From 252f430004ebd16bd2fba91223db96d080193b4d Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 20 Aug 2024 11:27:23 +0200 Subject: [PATCH 239/250] Bumped version. --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab672af0..8f4cc12a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -424,7 +424,7 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "2.1.0" +version = "2.1.1" dependencies = [ "anyhow", "bech32", diff --git a/Cargo.toml b/Cargo.toml index 6d6cc21d..3857a5ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "2.1.0" +version = "2.1.1" authors = [ "Ethan Frey ", "Dariusz Depta " From 31b1a7b32a6b59bb39d435eba7f76af26c07ae6b Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 16 Sep 2024 10:18:49 +0200 Subject: [PATCH 240/250] Updated dependencies. --- Cargo.lock | 181 ++++++++++++++++++++++++++++++++++------------------- Cargo.toml | 10 +-- 2 files changed, 120 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f4cc12a..3e43c1f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" @@ -37,9 +37,9 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" dependencies = [ "backtrace", ] @@ -173,17 +173,17 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets", ] [[package]] @@ -231,15 +231,6 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" -[[package]] -name = "cc" -version = "1.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" -dependencies = [ - "shlex", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -289,7 +280,7 @@ checksum = "029910b409398fdf81955d7301b906caf81f2c42b013ea074fbd89720229c424" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -313,7 +304,7 @@ checksum = "edf5c8adac41bb7751c050d7c4c18675be19ee128714454454575e894424eeef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -341,9 +332,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -419,12 +410,12 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "cw-multi-test" -version = "2.1.1" +version = "2.2.0" dependencies = [ "anyhow", "bech32", @@ -505,7 +496,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", "unicode-xid", ] @@ -628,9 +619,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "group" @@ -733,11 +724,11 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] @@ -770,18 +761,18 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" [[package]] name = "p256" @@ -830,9 +821,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc" +checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" dependencies = [ "bytes", "prost-derive", @@ -840,22 +831,22 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" +checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" dependencies = [ "anyhow", "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -927,9 +918,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] @@ -961,7 +952,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -985,9 +976,9 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] @@ -1003,13 +994,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -1020,14 +1011,14 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -1046,12 +1037,6 @@ dependencies = [ "digest", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "signature" version = "2.2.0" @@ -1087,9 +1072,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.75" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -1113,7 +1098,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -1124,9 +1109,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-xid" @@ -1146,6 +1131,70 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "zerocopy" version = "0.7.35" @@ -1164,7 +1213,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -1184,5 +1233,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] diff --git a/Cargo.toml b/Cargo.toml index 3857a5ec..e9143a91 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-multi-test" -version = "2.1.1" +version = "2.2.0" authors = [ "Ethan Frey ", "Dariusz Depta " @@ -26,20 +26,20 @@ cosmwasm_1_4 = ["cosmwasm_1_3", "cosmwasm-std/cosmwasm_1_4"] cosmwasm_2_0 = ["cosmwasm_1_4", "cosmwasm-std/cosmwasm_2_0"] [dependencies] -anyhow = "1.0.86" +anyhow = "1.0.89" bech32 = "0.11.0" cosmwasm-std = "2.1.3" cw-storage-plus = "2.0.0" cw-utils = "2.0.0" derivative = "2.2.0" itertools = "0.13.0" -prost = "0.13.1" +prost = "0.13.2" schemars = "0.8.21" -serde = "1.0.208" +serde = "1.0.210" sha2 = "0.10.8" thiserror = "1.0.63" [dev-dependencies] hex = "0.4.3" hex-literal = "0.4.1" -once_cell = "1.19.0" +qonce_cell = "1.20.0" From f4cef113e48e72ee734d988429dacb1845292425 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 16 Sep 2024 10:20:04 +0200 Subject: [PATCH 241/250] Fixed typo. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e9143a91..e8ab356f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,4 +42,4 @@ thiserror = "1.0.63" [dev-dependencies] hex = "0.4.3" hex-literal = "0.4.1" -qonce_cell = "1.20.0" +once_cell = "1.20.0" From 2293bb67bde88a2944f128ca55fefdef1a0daf5e Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Tue, 17 Sep 2024 09:16:43 +0200 Subject: [PATCH 242/250] Added cosmwasm_2_1 feature flag. (#210) --- Cargo.toml | 1 + src/checksums.rs | 4 ---- src/gov.rs | 11 +++-------- src/ibc.rs | 15 ++++++--------- src/wasm.rs | 4 +--- 5 files changed, 11 insertions(+), 24 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e8ab356f..2c6954d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ cosmwasm_1_2 = ["cosmwasm_1_1", "cosmwasm-std/cosmwasm_1_2"] cosmwasm_1_3 = ["cosmwasm_1_2", "cosmwasm-std/cosmwasm_1_3"] cosmwasm_1_4 = ["cosmwasm_1_3", "cosmwasm-std/cosmwasm_1_4"] cosmwasm_2_0 = ["cosmwasm_1_4", "cosmwasm-std/cosmwasm_2_0"] +cosmwasm_2_1 = ["cosmwasm_2_0", "cosmwasm-std/cosmwasm_2_1"] [dependencies] anyhow = "1.0.89" diff --git a/src/checksums.rs b/src/checksums.rs index f5c641f6..2f5a9781 100644 --- a/src/checksums.rs +++ b/src/checksums.rs @@ -2,10 +2,6 @@ use cosmwasm_std::{Addr, Checksum}; -/// Provides a custom interface for generating checksums for contract code. -/// This is crucial for ensuring code integrity and is particularly useful -/// in environments where code verification is a key part of the contract -/// deployment process. /// This trait defines a method to calculate checksum based on /// the creator's address and a unique code identifier. pub trait ChecksumGenerator { diff --git a/src/gov.rs b/src/gov.rs index 66e9dc47..9d34b59b 100644 --- a/src/gov.rs +++ b/src/gov.rs @@ -2,20 +2,15 @@ use crate::featured::GovMsg; use crate::{AcceptingModule, FailingModule, Module}; use cosmwasm_std::Empty; -/// Handles governance-related operations within the test environment. -/// This trait is essential for testing contracts that interact with governance mechanisms, -/// simulating proposals, voting, and other governance activities. +/// This trait implements the interface of the governance module. pub trait Gov: Module {} -/// A type alias for a module that accepts governance-related interactions. -/// It's used in scenarios where you need to test how your contract interacts -/// with governance processes and messages. +/// Implementation of the always accepting governance module. pub type GovAcceptingModule = AcceptingModule; impl Gov for GovAcceptingModule {} -/// This type alias represents a module designed to fail in response to governance operations. -/// It's useful for testing how contracts behave when governance actions do not proceed as expected. +/// Implementation of the always failing governance module. pub type GovFailingModule = FailingModule; impl Gov for GovFailingModule {} diff --git a/src/ibc.rs b/src/ibc.rs index e8442c2b..32236c34 100644 --- a/src/ibc.rs +++ b/src/ibc.rs @@ -1,18 +1,15 @@ use crate::{AcceptingModule, FailingModule, Module}; use cosmwasm_std::{Empty, IbcMsg, IbcQuery}; -///Manages Inter-Blockchain Communication (IBC) functionalities. -///This trait is critical for testing contracts that involve cross-chain interactions, -///reflecting the interconnected nature of the Cosmos ecosystem. + +/// This trait implements the interface for IBC functionalities. pub trait Ibc: Module {} -/// Ideal for testing contracts that involve IBC, this module is designed to successfully -/// handle cross-chain messages. It's key for ensuring that your contract can smoothly interact -/// with other blockchains in the Cosmos network. + +/// Implementation of the always accepting IBC module. pub type IbcAcceptingModule = AcceptingModule; impl Ibc for IbcAcceptingModule {} -/// Use this to test how your contract deals with problematic IBC scenarios. -/// It's a module that deliberately fails in handling IBC messages, allowing you -/// to check how your contract behaves in less-than-ideal cross-chain communication situations. + +/// implementation of the always failing IBC module. pub type IbcFailingModule = FailingModule; impl Ibc for IbcFailingModule {} diff --git a/src/wasm.rs b/src/wasm.rs index 42ec07cd..2e78cced 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -78,9 +78,7 @@ struct CodeData { source_id: usize, } -/// Acts as the interface for interacting with WebAssembly (Wasm) modules. -/// This trait is crucial for testing smart contracts written in languages that compile to WebAssembly, -/// which is common in the Cosmos and CosmWasm ecosystems. +/// This trait implements the interface of the Wasm module. pub trait Wasm { /// Handles all `WasmMsg` messages. fn execute( From b846f156f72e98d2037710dab856544fbb3a49db Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Tue, 17 Sep 2024 12:39:05 +0200 Subject: [PATCH 243/250] Unifying instantiate2 implementation (#212) --- Cargo.lock | 4 +- Cargo.toml | 2 +- src/contracts.rs | 29 ++- src/wasm.rs | 170 +++++++++--------- tests/mod.rs | 9 + tests/test_app/mod.rs | 2 - tests/test_app/test_instantiate2.rs | 127 ++++++++----- .../test_app/test_store_code_with_creator.rs | 2 + 8 files changed, 208 insertions(+), 137 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3e43c1f2..d73d2e36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -770,9 +770,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "p256" diff --git a/Cargo.toml b/Cargo.toml index 2c6954d1..72b371fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,4 +43,4 @@ thiserror = "1.0.63" [dev-dependencies] hex = "0.4.3" hex-literal = "0.4.1" -once_cell = "1.20.0" +once_cell = "1.19.0" diff --git a/src/contracts.rs b/src/contracts.rs index 5f550423..4ac1605b 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -2,8 +2,8 @@ use crate::error::{anyhow, bail, AnyError, AnyResult}; use cosmwasm_std::{ - from_json, Binary, CosmosMsg, CustomMsg, CustomQuery, Deps, DepsMut, Empty, Env, MessageInfo, - QuerierWrapper, Reply, Response, SubMsg, + from_json, Binary, Checksum, CosmosMsg, CustomMsg, CustomQuery, Deps, DepsMut, Empty, Env, + MessageInfo, QuerierWrapper, Reply, Response, SubMsg, }; use serde::de::DeserializeOwned; use std::fmt::{Debug, Display}; @@ -33,6 +33,11 @@ where /// Evaluates contract's `migrate` entry-point. fn migrate(&self, deps: DepsMut, env: Env, msg: Vec) -> AnyResult>; + + /// Returns the provided checksum of the contract's Wasm blob. + fn checksum(&self) -> Option { + None + } } #[rustfmt::skip] @@ -156,6 +161,7 @@ pub struct ContractWrapper< sudo_fn: Option>, reply_fn: Option>, migrate_fn: Option>, + checksum: Option, } impl ContractWrapper @@ -182,6 +188,7 @@ where sudo_fn: None, reply_fn: None, migrate_fn: None, + checksum: None, } } @@ -199,6 +206,7 @@ where sudo_fn: None, reply_fn: None, migrate_fn: None, + checksum: None, } } } @@ -237,6 +245,7 @@ where sudo_fn: Some(Box::new(sudo_fn)), reply_fn: self.reply_fn, migrate_fn: self.migrate_fn, + checksum: None, } } @@ -256,6 +265,7 @@ where sudo_fn: Some(customize_permissioned_fn(sudo_fn)), reply_fn: self.reply_fn, migrate_fn: self.migrate_fn, + checksum: None, } } @@ -274,6 +284,7 @@ where sudo_fn: self.sudo_fn, reply_fn: Some(Box::new(reply_fn)), migrate_fn: self.migrate_fn, + checksum: None, } } @@ -292,6 +303,7 @@ where sudo_fn: self.sudo_fn, reply_fn: Some(customize_permissioned_fn(reply_fn)), migrate_fn: self.migrate_fn, + checksum: None, } } @@ -311,6 +323,7 @@ where sudo_fn: self.sudo_fn, reply_fn: self.reply_fn, migrate_fn: Some(Box::new(migrate_fn)), + checksum: None, } } @@ -330,8 +343,15 @@ where sudo_fn: self.sudo_fn, reply_fn: self.reply_fn, migrate_fn: Some(customize_permissioned_fn(migrate_fn)), + checksum: None, } } + + /// Populates [ContractWrapper] with the provided checksum of the contract's Wasm blob. + pub fn with_checksum(mut self, checksum: Checksum) -> Self { + self.checksum = Some(checksum); + self + } } fn customize_contract_fn( @@ -534,4 +554,9 @@ where None => bail!("migrate is not implemented for contract"), } } + + /// Returns the provided checksum of the contract's Wasm blob. + fn checksum(&self) -> Option { + self.checksum + } } diff --git a/src/wasm.rs b/src/wasm.rs index 2e78cced..2fc0e044 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -337,90 +337,6 @@ where } } -impl WasmKeeper { - /// Returns a handler to code of the contract with specified code id. - pub fn contract_code(&self, code_id: u64) -> AnyResult<&dyn Contract> { - let code_data = self.code_data(code_id)?; - Ok(self.code_base[code_data.source_id].borrow()) - } - - /// Returns code data of the contract with specified code id. - fn code_data(&self, code_id: u64) -> AnyResult<&CodeData> { - if code_id < 1 { - bail!(Error::invalid_code_id()); - } - Ok(self - .code_data - .get(&code_id) - .ok_or_else(|| Error::unregistered_code_id(code_id))?) - } - - /// Validates all attributes. - /// - /// In `wasmd`, before version v0.45.0 empty attribute values were not allowed. - /// Since `wasmd` v0.45.0 empty attribute values are allowed, - /// so the value is not validated anymore. - fn verify_attributes(attributes: &[Attribute]) -> AnyResult<()> { - for attr in attributes { - let key = attr.key.trim(); - let val = attr.value.trim(); - if key.is_empty() { - bail!(Error::empty_attribute_key(val)); - } - if key.starts_with('_') { - bail!(Error::reserved_attribute_key(key)); - } - } - Ok(()) - } - - fn verify_response(response: Response) -> AnyResult> - where - T: CustomMsg, - { - Self::verify_attributes(&response.attributes)?; - - for event in &response.events { - Self::verify_attributes(&event.attributes)?; - let ty = event.ty.trim(); - if ty.len() < 2 { - bail!(Error::event_type_too_short(ty)); - } - } - - Ok(response) - } - - fn save_code( - &mut self, - code_id: u64, - creator: Addr, - code: Box>, - ) -> u64 { - // prepare the next identifier for the contract 'source' code - let source_id = self.code_base.len(); - // calculate the checksum of the contract 'source' code based on code_id - let checksum = self.checksum_generator.checksum(&creator, code_id); - // store the 'source' code of the contract - self.code_base.push(code); - // store the additional code attributes like creator address and checksum - self.code_data.insert( - code_id, - CodeData { - creator, - checksum, - source_id, - }, - ); - code_id - } - - /// Returns the next code identifier. - fn next_code_id(&self) -> Option { - self.code_data.keys().last().unwrap_or(&0u64).checked_add(1) - } -} - impl WasmKeeper where ExecC: CustomMsg + DeserializeOwned + 'static, @@ -513,7 +429,91 @@ where self } - /// Executes contract's `query` entry-point. + /// Returns a handler to code of the contract with specified code id. + pub fn contract_code(&self, code_id: u64) -> AnyResult<&dyn Contract> { + let code_data = self.code_data(code_id)?; + Ok(self.code_base[code_data.source_id].borrow()) + } + + /// Returns code data of the contract with specified code id. + fn code_data(&self, code_id: u64) -> AnyResult<&CodeData> { + if code_id < 1 { + bail!(Error::invalid_code_id()); + } + Ok(self + .code_data + .get(&code_id) + .ok_or_else(|| Error::unregistered_code_id(code_id))?) + } + + /// Validates all attributes. + /// + /// In `wasmd`, before version v0.45.0 empty attribute values were not allowed. + /// Since `wasmd` v0.45.0 empty attribute values are allowed, + /// so the value is not validated anymore. + fn verify_attributes(attributes: &[Attribute]) -> AnyResult<()> { + for attr in attributes { + let key = attr.key.trim(); + let val = attr.value.trim(); + if key.is_empty() { + bail!(Error::empty_attribute_key(val)); + } + if key.starts_with('_') { + bail!(Error::reserved_attribute_key(key)); + } + } + Ok(()) + } + + fn verify_response(response: Response) -> AnyResult> + where + T: CustomMsg, + { + Self::verify_attributes(&response.attributes)?; + + for event in &response.events { + Self::verify_attributes(&event.attributes)?; + let ty = event.ty.trim(); + if ty.len() < 2 { + bail!(Error::event_type_too_short(ty)); + } + } + + Ok(response) + } + + fn save_code( + &mut self, + code_id: u64, + creator: Addr, + code: Box>, + ) -> u64 { + // prepare the next identifier for the contract's code + let source_id = self.code_base.len(); + // prepare the contract's Wasm blob checksum + let checksum = code + .checksum() + .unwrap_or(self.checksum_generator.checksum(&creator, code_id)); + // store the 'source' code of the contract + self.code_base.push(code); + // store the additional code attributes like creator address and checksum + self.code_data.insert( + code_id, + CodeData { + creator, + checksum, + source_id, + }, + ); + code_id + } + + /// Returns the next contract's code identifier. + fn next_code_id(&self) -> Option { + self.code_data.keys().last().unwrap_or(&0u64).checked_add(1) + } + + /// Executes the contract's `query` entry-point. pub fn query_smart( &self, address: Addr, diff --git a/tests/mod.rs b/tests/mod.rs index 4dcf2199..6f5d40fe 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -70,5 +70,14 @@ mod test_contracts { pub fn contract() -> Box> { Box::new(ContractWrapper::new_with_empty(execute, instantiate, query)) } + + #[cfg(feature = "cosmwasm_1_2")] + pub fn contract_with_checksum() -> Box> { + Box::new( + ContractWrapper::new_with_empty(execute, instantiate, query).with_checksum( + cosmwasm_std::Checksum::generate(&[1, 2, 3, 4, 5, 6, 7, 8, 9]), + ), + ) + } } } diff --git a/tests/test_app/mod.rs b/tests/test_app/mod.rs index 00601b0d..165154af 100644 --- a/tests/test_app/mod.rs +++ b/tests/test_app/mod.rs @@ -1,8 +1,6 @@ mod test_block_info; mod test_initialize_app; -#[cfg(feature = "cosmwasm_1_2")] mod test_instantiate2; mod test_store_code; -#[cfg(feature = "cosmwasm_1_2")] mod test_store_code_with_creator; mod test_store_code_with_id; diff --git a/tests/test_app/test_instantiate2.rs b/tests/test_app/test_instantiate2.rs index 95fc8eed..a881315e 100644 --- a/tests/test_app/test_instantiate2.rs +++ b/tests/test_app/test_instantiate2.rs @@ -1,12 +1,21 @@ +#![cfg(feature = "cosmwasm_1_2")] + use crate::test_contracts::counter; use cosmwasm_std::testing::MockApi; -use cosmwasm_std::{instantiate2_address, to_json_binary, Api, Empty, WasmMsg}; -use cw_multi_test::{no_init, AppBuilder, Executor}; +use cosmwasm_std::{instantiate2_address, to_json_binary, Addr, Api, Coin, Empty, WasmMsg}; +use cw_multi_test::{no_init, App, AppBuilder, Executor}; use cw_utils::parse_instantiate_response_data; +const FUNDS: Vec = vec![]; +const SALT: &[u8] = "bad kids".as_bytes(); +const LABEL: &str = "label"; +const JUNO_1: &str = "juno1navvz5rjlvn43xjqxlpl7dunk6hglmhuh7c6a53eq6qamfam3dus7a220h"; +const JUNO_2: &str = "juno1qaygqu9plc7nqqgwt7d6dxhmej2tl0lu20j84l5pnz5p4th4zz5qwd77z5"; +const OSMO: &str = "osmo1navvz5rjlvn43xjqxlpl7dunk6hglmhuh7c6a53eq6qamfam3dusg94p04"; + #[test] fn instantiate2_works() { - // prepare the application with custom Api and custom address generator + // prepare the chain with custom Api and custom address generator let mut app = AppBuilder::default() .with_api(MockApi::default().with_prefix("juno")) .build(no_init); @@ -15,21 +24,18 @@ fn instantiate2_works() { let sender = app.api().addr_make("sender"); let creator = app.api().addr_make("creator"); - // store the contract's code + // store the contract's code (Wasm blob checksum is generated) let code_id = app.store_code_with_creator(creator, counter::contract()); - // prepare the salt for predictable address - let salt = "bad kids".as_bytes(); - // instantiate the contract with predictable address let init_msg = to_json_binary(&Empty {}).unwrap(); let msg = WasmMsg::Instantiate2 { admin: None, code_id, msg: init_msg, - funds: vec![], - label: "label".into(), - salt: salt.into(), + funds: FUNDS, + label: LABEL.into(), + salt: SALT.into(), }; let res = app.execute(sender.clone(), msg.into()).unwrap(); @@ -38,34 +44,49 @@ fn instantiate2_works() { assert!(parsed.data.is_none()); // check the resulting predictable contract's address - assert_eq!( - parsed.contract_address, - "juno1navvz5rjlvn43xjqxlpl7dunk6hglmhuh7c6a53eq6qamfam3dus7a220h" - ); + assert_eq!(parsed.contract_address, JUNO_1); // must be equal + assert_ne!(parsed.contract_address, JUNO_2); // must differ - // ---------------------------------------------------------------------- - // Below is an additional check, proving that the predictable address - // from contract instantiation is exactly the same as the address - // returned from the function cosmwasm_std::instantiate2_address - // ---------------------------------------------------------------------- + // comparing with the result from `cosmwasm_std::instantiate2_address` is done here + compare_with_cosmwasm_vm_address(&app, code_id, &sender, &parsed.contract_address); +} - // get the code info of the contract - let code_info_response = app.wrap().query_wasm_code_info(code_id).unwrap(); +#[test] +fn instantiate2_works_with_checksum_provided_in_contract() { + // prepare the chain with custom API and custom address generator + let mut app = AppBuilder::default() + .with_api(MockApi::default().with_prefix("juno")) + .build(no_init); - // retrieve the contract's code checksum - let checksum = code_info_response.checksum.as_slice(); + // prepare addresses for the sender and creator + let sender = app.api().addr_make("sender"); + let creator = app.api().addr_make("creator"); - // canonicalize the sender address (which is now in human Bech32 format) - let sender_addr = app.api().addr_canonicalize(sender.as_str()).unwrap(); + // store the contract's code (Wasm blob checksum is provided in contract) + let code_id = app.store_code_with_creator(creator, counter::contract_with_checksum()); - // get the contract address using cosmwasm_std::instantiate2_address function - let contract_addr = instantiate2_address(checksum, &sender_addr, salt).unwrap(); + // instantiate the contract with predictable address + let init_msg = to_json_binary(&Empty {}).unwrap(); + let msg = WasmMsg::Instantiate2 { + admin: None, + code_id, + msg: init_msg, + funds: FUNDS, + label: LABEL.into(), + salt: SALT.into(), + }; + let res = app.execute(sender.clone(), msg.into()).unwrap(); - // humanize the address of the contract - let contract_human_addr = app.api().addr_humanize(&contract_addr).unwrap(); + // check the instantiate result + let parsed = parse_instantiate_response_data(res.data.unwrap().as_slice()).unwrap(); + assert!(parsed.data.is_none()); - // check if the predictable contract's address matches the result from instantiate2_address function - assert_eq!(parsed.contract_address, contract_human_addr.to_string()); + // check the resulting predictable contract's address + assert_eq!(parsed.contract_address, JUNO_2); // must be equal + assert_ne!(parsed.contract_address, JUNO_1); // must differ + + // comparing with the result from `cosmwasm_std::instantiate2_address` is done here + compare_with_cosmwasm_vm_address(&app, code_id, &sender, &parsed.contract_address); } #[test] @@ -88,8 +109,8 @@ fn instantiate2_should_work_for_multiple_salts() { admin: None, code_id, msg: to_json_binary(&Empty {}).unwrap(), - funds: vec![], - label: "label".into(), + funds: FUNDS, + label: LABEL.into(), salt: salt.as_bytes().into(), }; let res = app.execute(sender.clone(), msg.into()).unwrap(); @@ -115,18 +136,15 @@ fn instantiate2_fails_for_duplicated_addresses() { // store the contract's code let code_id = app.store_code_with_creator(creator, counter::contract()); - // prepare the salt for predictable address - let salt = "bad kids".as_bytes(); - // instantiate the contract with predictable address let init_msg = to_json_binary(&Empty {}).unwrap(); let msg = WasmMsg::Instantiate2 { admin: None, code_id, msg: init_msg, - funds: vec![], - label: "label".into(), - salt: salt.into(), + funds: FUNDS, + label: LABEL.into(), + salt: SALT.into(), }; let res = app.execute(sender.clone(), msg.clone().into()).unwrap(); @@ -135,10 +153,7 @@ fn instantiate2_fails_for_duplicated_addresses() { assert!(parsed.data.is_none()); // check the resulting predictable contract's address - assert_eq!( - parsed.contract_address, - "osmo1navvz5rjlvn43xjqxlpl7dunk6hglmhuh7c6a53eq6qamfam3dusg94p04" - ); + assert_eq!(parsed.contract_address, OSMO); // creating a new instance of the same contract with the same sender and salt // should fail because the generated contract address is the same @@ -160,9 +175,31 @@ fn instantiate2_fails_for_duplicated_addresses() { let sender_addr = app.api().addr_canonicalize(sender.as_str()).unwrap(); // get the contract address using cosmwasm_std::instantiate2_address function twice - let contract_addr_1 = instantiate2_address(checksum, &sender_addr, salt).unwrap(); - let contract_addr_2 = instantiate2_address(checksum, &sender_addr, salt).unwrap(); + let contract_addr_1 = instantiate2_address(checksum, &sender_addr, SALT).unwrap(); + let contract_addr_2 = instantiate2_address(checksum, &sender_addr, SALT).unwrap(); // contract addresses should be the same assert_eq!(contract_addr_1, contract_addr_2); } + +/// Utility function proving that the predictable address from contract instantiation +/// is exactly the same as the address returned from the function `cosmwasm_std::instantiate2_address`. +fn compare_with_cosmwasm_vm_address(app: &App, code_id: u64, sender: &Addr, expected_addr: &str) { + // get the code info of the contract + let code_info_response = app.wrap().query_wasm_code_info(code_id).unwrap(); + + // retrieve the contract's code checksum + let checksum = code_info_response.checksum.as_slice(); + + // canonicalize the sender address (which is now in human Bech32 format) + let sender_addr = app.api().addr_canonicalize(sender.as_str()).unwrap(); + + // get the contract address using cosmwasm_std::instantiate2_address function + let contract_addr = instantiate2_address(checksum, &sender_addr, SALT).unwrap(); + + // humanize the address of the contract + let contract_human_addr = app.api().addr_humanize(&contract_addr).unwrap(); + + // check if the predictable contract's address matches the result from instantiate2_address function + assert_eq!(expected_addr, contract_human_addr.to_string()); +} diff --git a/tests/test_app/test_store_code_with_creator.rs b/tests/test_app/test_store_code_with_creator.rs index 73d469dc..5f70a1e4 100644 --- a/tests/test_app/test_store_code_with_creator.rs +++ b/tests/test_app/test_store_code_with_creator.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "cosmwasm_1_2")] + use crate::test_contracts::counter; use cw_multi_test::{no_init, AppBuilder}; use cw_multi_test::{MockApiBech32, MockApiBech32m}; From f12271d0adf8b6584c4cfb6dc57aac112656369a Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:43:52 +0200 Subject: [PATCH 244/250] Removed `derivative` crate dependency (#214) --- Cargo.lock | 53 ++++++++++++++++---------------- Cargo.toml | 7 ++--- src/custom_handler.rs | 48 ++++++++++++++++++++++------- src/test_helpers/echo.rs | 7 ++--- src/test_helpers/mod.rs | 12 ++++++-- src/tests/test_app.rs | 2 +- src/tests/test_custom_handler.rs | 4 +-- 7 files changed, 80 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d73d2e36..192ec4fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -227,9 +227,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "cfg-if" @@ -245,15 +245,15 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-core" -version = "2.1.3" +version = "2.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d905990ef3afb5753bb709dc7de88e9e370aa32bcc2f31731d4b533b63e82490" +checksum = "5f6ceb8624260d0d3a67c4e1a1d43fc7e9406720afbcb124521501dd138f90aa" [[package]] name = "cosmwasm-crypto" -version = "2.1.3" +version = "2.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b2a7bd9c1dd9a377a4dc0f4ad97d24b03c33798cd5a6d7ceb8869b41c5d2f2d" +checksum = "4125381e5fd7fefe9f614640049648088015eca2b60d861465329a5d87dfa538" dependencies = [ "ark-bls12-381", "ark-ec", @@ -274,9 +274,9 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "2.1.3" +version = "2.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029910b409398fdf81955d7301b906caf81f2c42b013ea074fbd89720229c424" +checksum = "1b5658b1dc64e10b56ae7a449f678f96932a96f6cfad1769d608d1d1d656480a" dependencies = [ "proc-macro2", "quote", @@ -285,9 +285,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema" -version = "2.1.3" +version = "2.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bc0d4d85e83438ab9a0fea9348446f7268bc016aacfebce37e998559f151294" +checksum = "f86b4d949b6041519c58993a73f4bbfba8083ba14f7001eae704865a09065845" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -298,9 +298,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.1.3" +version = "2.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edf5c8adac41bb7751c050d7c4c18675be19ee128714454454575e894424eeef" +checksum = "c8ef1b5835a65fcca3ab8b9a02b4f4dacc78e233a5c2f20b270efb9db0666d12" dependencies = [ "proc-macro2", "quote", @@ -309,9 +309,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "2.1.3" +version = "2.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51dec99a2e478715c0a4277f0dbeadbb8466500eb7dec873d0924edd086e77f1" +checksum = "70eb7ab0c1e99dd6207496963ba2a457c4128ac9ad9c72a83f8d9808542b849b" dependencies = [ "base64", "bech32", @@ -422,7 +422,6 @@ dependencies = [ "cosmwasm-std", "cw-storage-plus", "cw-utils", - "derivative", "hex", "hex-literal", "itertools 0.13.0", @@ -700,9 +699,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "k256" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if", "ecdsa", @@ -821,9 +820,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" dependencies = [ "bytes", "prost-derive", @@ -831,9 +830,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", "itertools 0.13.0", @@ -1083,18 +1082,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", @@ -1115,9 +1114,9 @@ checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-xid" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "version_check" diff --git a/Cargo.toml b/Cargo.toml index 72b371fc..0855f768 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,16 +29,15 @@ cosmwasm_2_1 = ["cosmwasm_2_0", "cosmwasm-std/cosmwasm_2_1"] [dependencies] anyhow = "1.0.89" bech32 = "0.11.0" -cosmwasm-std = "2.1.3" +cosmwasm-std = "2.1.4" cw-storage-plus = "2.0.0" cw-utils = "2.0.0" -derivative = "2.2.0" itertools = "0.13.0" -prost = "0.13.2" +prost = "0.13.3" schemars = "0.8.21" serde = "1.0.210" sha2 = "0.10.8" -thiserror = "1.0.63" +thiserror = "1.0.64" [dev-dependencies] hex = "0.4.3" diff --git a/src/custom_handler.rs b/src/custom_handler.rs index 1ab9dbeb..a9b0da2b 100644 --- a/src/custom_handler.rs +++ b/src/custom_handler.rs @@ -4,22 +4,33 @@ use crate::app::CosmosRouter; use crate::error::{bail, AnyResult}; use crate::{AppResponse, Module}; use cosmwasm_std::{Addr, Api, Binary, BlockInfo, Empty, Querier, Storage}; -use derivative::Derivative; use std::cell::{Ref, RefCell}; use std::ops::Deref; use std::rc::Rc; /// A cache for messages and queries processes by the custom module. -#[derive(Derivative)] -#[derivative(Default(bound = "", new = "true"), Clone(bound = ""))] -pub struct CachingCustomHandlerState { +#[derive(Default, Clone)] +pub struct CachingCustomHandlerState +where + ExecC: Default + Clone, + QueryC: Default + Clone, +{ /// Cache for processes custom messages. execs: Rc>>, /// Cache for processed custom queries. queries: Rc>>, } -impl CachingCustomHandlerState { +impl CachingCustomHandlerState +where + ExecC: Default + Clone, + QueryC: Default + Clone, +{ + /// Creates a new [CachingCustomHandlerState]. + pub fn new() -> Self { + Default::default() + } + /// Returns a slice of processed custom messages. pub fn execs(&self) -> impl Deref + '_ { Ref::map(self.execs.borrow(), Vec::as_slice) @@ -40,26 +51,41 @@ impl CachingCustomHandlerState { /// Custom handler that stores all received messages and queries. /// /// State is thin shared state, so it can be held after mock is passed to [App](crate::App) to read state. -#[derive(Clone, Derivative)] -#[derivative(Default(bound = "", new = "true"))] -pub struct CachingCustomHandler { +#[derive(Default, Clone)] +pub struct CachingCustomHandler +where + ExecC: Default + Clone, + QueryC: Default + Clone, +{ /// Cached state. state: CachingCustomHandlerState, } -impl CachingCustomHandler { +impl CachingCustomHandler +where + ExecC: Default + Clone, + QueryC: Default + Clone, +{ + /// Creates a new [CachingCustomHandler]. + pub fn new() -> Self { + Default::default() + } + /// Returns the cached state. pub fn state(&self) -> CachingCustomHandlerState { self.state.clone() } } -impl Module for CachingCustomHandler { +impl Module for CachingCustomHandler +where + Exec: Default + Clone, + Query: Default + Clone, +{ type ExecT = Exec; type QueryT = Query; type SudoT = Empty; - // TODO: how to assert like `where ExecC: Exec, QueryC: Query` fn execute( &self, _api: &dyn Api, diff --git a/src/test_helpers/echo.rs b/src/test_helpers/echo.rs index 884df65c..16ab2fbd 100644 --- a/src/test_helpers/echo.rs +++ b/src/test_helpers/echo.rs @@ -9,7 +9,6 @@ use cosmwasm_std::{ Reply, Response, StdError, SubMsg, SubMsgResponse, SubMsgResult, }; use cw_utils::{parse_execute_response_data, parse_instantiate_response_data}; -use derivative::Derivative; use schemars::JsonSchema; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::fmt::Debug; @@ -18,8 +17,7 @@ use std::fmt::Debug; // An Execute message reply otherwise. pub const EXECUTE_REPLY_BASE_ID: u64 = i64::MAX as u64; -#[derive(Debug, Clone, Serialize, Deserialize, Derivative)] -#[derivative(Default(bound = "", new = "true"))] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct Message where ExecC: Debug + PartialEq + Clone + JsonSchema + 'static, @@ -31,8 +29,7 @@ where } // This can take some data... but happy to accept {} -#[derive(Debug, Clone, Serialize, Deserialize, Derivative)] -#[derivative(Default(bound = "", new = "true"))] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct InitMessage where ExecC: Debug + PartialEq + Clone + JsonSchema + 'static, diff --git a/src/test_helpers/mod.rs b/src/test_helpers/mod.rs index c3f47c02..ac053fce 100644 --- a/src/test_helpers/mod.rs +++ b/src/test_helpers/mod.rs @@ -19,11 +19,17 @@ pub mod reflect; pub mod stargate; /// Custom message for testing purposes. -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename = "snake_case")] pub enum CustomHelperMsg { - SetName { name: String }, - SetAge { age: u32 }, + SetName { + name: String, + }, + SetAge { + age: u32, + }, + #[default] + NoOp, } impl CustomMsg for CustomHelperMsg {} diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index 7c078b5b..a7fe0457 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -1656,7 +1656,7 @@ mod custom_messages { #[test] fn triggering_custom_msg() { - let custom_handler = CachingCustomHandler::::new(); + let custom_handler = CachingCustomHandler::::default(); let custom_handler_state = custom_handler.state(); let mut app = AppBuilder::new_custom() diff --git a/src/tests/test_custom_handler.rs b/src/tests/test_custom_handler.rs index 5ba0d70e..d38d6dea 100644 --- a/src/tests/test_custom_handler.rs +++ b/src/tests/test_custom_handler.rs @@ -14,7 +14,7 @@ fn custom_handler_works() { let mut storage = MockStorage::default(); // create custom handler - let custom_handler = CachingCustomHandler::::new(); + let custom_handler = CachingCustomHandler::::default(); // prepare user addresses let sender_addr = app.api().addr_make("sender"); @@ -70,7 +70,7 @@ fn custom_handler_has_no_sudo() { let mut storage = MockStorage::default(); // create custom handler - let custom_handler = CachingCustomHandler::::new(); + let custom_handler = CachingCustomHandler::::default(); // run sudo function assert_eq!( From eb5d459b44d037ff0a515c59e452e8c5ad315991 Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Tue, 24 Sep 2024 16:59:23 +0200 Subject: [PATCH 245/250] Added cw_serde where needed. (#215) --- Cargo.lock | 1 + Cargo.toml | 1 + src/test_helpers/echo.rs | 26 ++++++++++++-------------- src/test_helpers/hackatom.rs | 10 ++++------ src/test_helpers/mod.rs | 6 +++--- src/test_helpers/payout.rs | 11 +++++------ src/test_helpers/reflect.rs | 6 +++--- src/tests/mod.rs | 3 --- src/tests/test_gov.rs | 2 ++ src/tests/test_ibc.rs | 2 ++ src/tests/test_stargate.rs | 2 ++ tests/mod.rs | 7 +++---- tests/test_bank/test_init_balance.rs | 9 +++------ 13 files changed, 41 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 192ec4fa..696c1fc4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -419,6 +419,7 @@ version = "2.2.0" dependencies = [ "anyhow", "bech32", + "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus", "cw-utils", diff --git a/Cargo.toml b/Cargo.toml index 0855f768..4b190537 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ cosmwasm_2_1 = ["cosmwasm_2_0", "cosmwasm-std/cosmwasm_2_1"] [dependencies] anyhow = "1.0.89" bech32 = "0.11.0" +cosmwasm-schema = "2.1.3" cosmwasm-std = "2.1.4" cw-storage-plus = "2.0.0" cw-utils = "2.0.0" diff --git a/src/test_helpers/echo.rs b/src/test_helpers/echo.rs index 16ab2fbd..5da47d26 100644 --- a/src/test_helpers/echo.rs +++ b/src/test_helpers/echo.rs @@ -4,23 +4,23 @@ //! Additionally, it bypasses all events and attributes send to it. use crate::{Contract, ContractWrapper}; +use cosmwasm_schema::cw_serde; use cosmwasm_std::{ to_json_binary, Attribute, Binary, CustomMsg, Deps, DepsMut, Empty, Env, Event, MessageInfo, Reply, Response, StdError, SubMsg, SubMsgResponse, SubMsgResult, }; use cw_utils::{parse_execute_response_data, parse_instantiate_response_data}; -use schemars::JsonSchema; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use std::fmt::Debug; +use serde::de::DeserializeOwned; // Choosing a reply id less than ECHO_EXECUTE_BASE_ID indicates an Instantiate message reply by convention. // An Execute message reply otherwise. pub const EXECUTE_REPLY_BASE_ID: u64 = i64::MAX as u64; -#[derive(Debug, Default, Clone, Serialize, Deserialize)] +#[cw_serde] +#[derive(Default)] pub struct Message where - ExecC: Debug + PartialEq + Clone + JsonSchema + 'static, + ExecC: CustomMsg + 'static, { pub data: Option, pub sub_msg: Vec>, @@ -28,17 +28,16 @@ where pub events: Vec, } -// This can take some data... but happy to accept {} -#[derive(Debug, Default, Clone, Serialize, Deserialize)] +#[cw_serde] +#[derive(Default)] pub struct InitMessage where - ExecC: Debug + PartialEq + Clone + JsonSchema + 'static, + ExecC: CustomMsg + 'static, { pub data: Option, pub sub_msg: Option>>, } -#[allow(clippy::unnecessary_wraps)] fn instantiate( _deps: DepsMut, _env: Env, @@ -46,7 +45,7 @@ fn instantiate( msg: InitMessage, ) -> Result, StdError> where - ExecC: Debug + PartialEq + Clone + JsonSchema + 'static, + ExecC: CustomMsg + 'static, { let mut res = Response::new(); if let Some(data) = msg.data { @@ -58,7 +57,6 @@ where Ok(res) } -#[allow(clippy::unnecessary_wraps)] fn execute( _deps: DepsMut, _env: Env, @@ -66,7 +64,7 @@ fn execute( msg: Message, ) -> Result, StdError> where - ExecC: Debug + PartialEq + Clone + JsonSchema + 'static, + ExecC: CustomMsg + 'static, { let mut resp = Response::new(); @@ -84,12 +82,12 @@ fn query(_deps: Deps, _env: Env, msg: Empty) -> Result { to_json_binary(&msg) } -#[allow(clippy::unnecessary_wraps, deprecated)] fn reply(_deps: DepsMut, _env: Env, msg: Reply) -> Result, StdError> where - ExecC: Debug + PartialEq + Clone + JsonSchema + 'static, + ExecC: CustomMsg + 'static, { let res = Response::new(); + #[allow(deprecated)] if let Reply { id, result: SubMsgResult::Ok(SubMsgResponse { diff --git a/src/test_helpers/hackatom.rs b/src/test_helpers/hackatom.rs index 95df71ba..6c0d7dd6 100644 --- a/src/test_helpers/hackatom.rs +++ b/src/test_helpers/hackatom.rs @@ -1,27 +1,25 @@ //! Simplified contract which when executed releases the funds to beneficiary use crate::{Contract, ContractWrapper}; +use cosmwasm_schema::cw_serde; use cosmwasm_std::{ to_json_binary, BankMsg, Binary, CustomMsg, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError, }; use cw_storage_plus::Item; -use serde::{Deserialize, Serialize}; -use std::fmt::Debug; -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cw_serde] pub struct InstantiateMsg { pub beneficiary: String, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cw_serde] pub struct MigrateMsg { // just use some other string, so we see there are other types pub new_guy: String, } -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] +#[cw_serde] pub enum QueryMsg { // returns InstantiateMsg Beneficiary {}, diff --git a/src/test_helpers/mod.rs b/src/test_helpers/mod.rs index ac053fce..c99736c9 100644 --- a/src/test_helpers/mod.rs +++ b/src/test_helpers/mod.rs @@ -1,9 +1,8 @@ #![cfg(test)] +use cosmwasm_schema::cw_serde; use cosmwasm_std::CustomMsg; use cw_storage_plus::Item; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; pub mod caller; pub mod echo; @@ -19,7 +18,8 @@ pub mod reflect; pub mod stargate; /// Custom message for testing purposes. -#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[cw_serde] +#[derive(Default)] #[serde(rename = "snake_case")] pub enum CustomHelperMsg { SetName { diff --git a/src/test_helpers/payout.rs b/src/test_helpers/payout.rs index 159f6cea..5d0eddb4 100644 --- a/src/test_helpers/payout.rs +++ b/src/test_helpers/payout.rs @@ -1,30 +1,29 @@ use crate::test_helpers::COUNT; use crate::{Contract, ContractWrapper}; +use cosmwasm_schema::cw_serde; use cosmwasm_std::{ to_json_binary, BankMsg, Binary, Coin, CustomMsg, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError, }; use cw_storage_plus::Item; -use serde::{Deserialize, Serialize}; -use std::fmt::Debug; -#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[cw_serde] pub struct InstantiateMessage { pub payout: Coin, } -#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[cw_serde] pub struct SudoMsg { pub set_count: u32, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cw_serde] pub enum QueryMsg { Count {}, Payout {}, } -#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[cw_serde] pub struct CountResponse { pub count: u32, } diff --git a/src/test_helpers/reflect.rs b/src/test_helpers/reflect.rs index 41b4396e..2bfb59ab 100644 --- a/src/test_helpers/reflect.rs +++ b/src/test_helpers/reflect.rs @@ -1,18 +1,18 @@ use crate::test_helpers::{payout, CustomHelperMsg, COUNT}; use crate::{Contract, ContractWrapper}; +use cosmwasm_schema::cw_serde; use cosmwasm_std::{ to_json_binary, Binary, Deps, DepsMut, Empty, Env, Event, MessageInfo, Reply, Response, StdError, SubMsg, }; use cw_storage_plus::Map; -use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[cw_serde] pub struct Message { pub messages: Vec>, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cw_serde] pub enum QueryMsg { Count {}, Reply { id: u64 }, diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 39470562..2f5d2092 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -3,9 +3,6 @@ mod test_app; mod test_custom_handler; mod test_error; -#[cfg(feature = "stargate")] mod test_gov; -#[cfg(feature = "stargate")] mod test_ibc; -#[cfg(feature = "stargate")] mod test_stargate; diff --git a/src/tests/test_gov.rs b/src/tests/test_gov.rs index 68897735..65d560a4 100644 --- a/src/tests/test_gov.rs +++ b/src/tests/test_gov.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "stargate")] + use crate::test_helpers::gov; use crate::{no_init, App, AppBuilder, Executor, GovAcceptingModule}; use cosmwasm_std::Empty; diff --git a/src/tests/test_ibc.rs b/src/tests/test_ibc.rs index ab70567c..c3e7a756 100644 --- a/src/tests/test_ibc.rs +++ b/src/tests/test_ibc.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "stargate")] + use crate::test_helpers::ibc; use crate::{no_init, App, AppBuilder, Executor, IbcAcceptingModule}; use cosmwasm_std::Empty; diff --git a/src/tests/test_stargate.rs b/src/tests/test_stargate.rs index 01f2f975..db00a5ab 100644 --- a/src/tests/test_stargate.rs +++ b/src/tests/test_stargate.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "stargate")] + use crate::test_helpers::stargate; use crate::{no_init, App, AppBuilder, Executor, StargateAccepting}; use cosmwasm_std::Empty; diff --git a/tests/mod.rs b/tests/mod.rs index 6f5d40fe..c7e7a91b 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -15,23 +15,22 @@ mod test_wasm; mod test_contracts { pub mod counter { + use cosmwasm_schema::cw_serde; use cosmwasm_std::{ to_json_binary, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError, WasmMsg, }; use cw_multi_test::{Contract, ContractWrapper}; use cw_storage_plus::Item; - use serde::{Deserialize, Serialize}; const COUNTER: Item = Item::new("counter"); - #[derive(Debug, Clone, Serialize, Deserialize)] - #[serde(rename_all = "snake_case")] + #[cw_serde] pub enum CounterQueryMsg { Counter {}, } - #[derive(Debug, Clone, Serialize, Deserialize)] + #[cw_serde] pub struct CounterResponseMsg { pub value: u64, } diff --git a/tests/test_bank/test_init_balance.rs b/tests/test_bank/test_init_balance.rs index b312b22d..44fd0172 100644 --- a/tests/test_bank/test_init_balance.rs +++ b/tests/test_bank/test_init_balance.rs @@ -1,7 +1,6 @@ +use cosmwasm_schema::cw_serde; use cosmwasm_std::{Coin, CustomMsg, CustomQuery, Uint128}; use cw_multi_test::{custom_app, App, AppBuilder, BasicApp}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; const USER: &str = "user"; const DENOM: &str = "denom"; @@ -52,15 +51,13 @@ fn initializing_balance_without_builder_should_work() { #[test] fn initializing_balance_custom_app_should_work() { - #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] - #[serde(rename = "snake_case")] + #[cw_serde] pub enum CustomHelperMsg { HelperMsg, } impl CustomMsg for CustomHelperMsg {} - #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] - #[serde(rename = "snake_case")] + #[cw_serde] pub enum CustomHelperQuery { HelperQuery, } From 692e90d05e6d876d89b8ef2353f011390b4f2fbe Mon Sep 17 00:00:00 2001 From: Kayanski Date: Tue, 1 Oct 2024 11:08:49 +0000 Subject: [PATCH 246/250] Merge changes --- .circleci/config.yml | 38 +- CHANGELOG.md | 122 +- CLA.md | 23 - Cargo.lock | 2 +- Cargo.toml | 4 +- SECURITY.md | 19 +- src/addons/addresses/mock.rs | 148 -- src/addons/addresses/mod.rs | 1 - src/addons/api/bech32.rs | 187 --- src/addons/api/bech32m.rs | 154 --- src/addons/api/mod.rs | 2 - src/addons/mod.rs | 11 - src/addresses.rs | 180 ++- src/api.rs | 119 ++ src/app.rs | 297 +++- src/app_builder.rs | 152 ++- src/bank.rs | 473 ++++++- src/contracts.rs | 349 +++-- src/custom_handler.rs | 43 +- src/error.rs | 72 +- src/executor.rs | 52 +- src/gov.rs | 11 +- src/ibc.rs | 12 +- src/lib.rs | 148 +- src/module.rs | 68 +- src/prefixed_storage/length_prefixed.rs | 4 +- src/prefixed_storage/mod.rs | 119 +- src/staking.rs | 1652 ++++++++++++++++++++++- src/stargate.rs | 145 ++ src/test_helpers/caller.rs | 6 +- src/test_helpers/echo.rs | 11 +- src/test_helpers/error.rs | 6 +- src/test_helpers/gov.rs | 27 + src/test_helpers/hackatom.rs | 8 +- src/test_helpers/ibc.rs | 26 + src/test_helpers/mod.rs | 7 +- src/test_helpers/payout.rs | 7 +- src/test_helpers/reflect.rs | 12 +- src/test_helpers/stargate.rs | 30 +- src/tests/mod.rs | 2 + src/tests/test_app.rs | 467 ++++--- src/tests/test_custom_handler.rs | 26 +- src/tests/test_error.rs | 43 + src/tests/test_gov.rs | 102 +- src/tests/test_ibc.rs | 44 +- src/tests/test_stargate.rs | 54 + src/transactions.rs | 47 +- src/wasm.rs | 1320 +++++++++++++++--- src/wasm_emulation/api/mod.rs | 29 +- src/wasm_emulation/input.rs | 6 +- src/wasm_emulation/query/wasm.rs | 3 +- 51 files changed, 5210 insertions(+), 1680 deletions(-) delete mode 100644 CLA.md delete mode 100644 src/addons/addresses/mock.rs delete mode 100644 src/addons/addresses/mod.rs delete mode 100644 src/addons/api/bech32.rs delete mode 100644 src/addons/api/bech32m.rs delete mode 100644 src/addons/api/mod.rs delete mode 100644 src/addons/mod.rs create mode 100644 src/api.rs create mode 100644 src/stargate.rs create mode 100644 src/test_helpers/gov.rs create mode 100644 src/test_helpers/ibc.rs create mode 100644 src/tests/test_error.rs create mode 100644 src/tests/test_stargate.rs diff --git a/.circleci/config.yml b/.circleci/config.yml index e9a3a574..50ebb17b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -30,7 +30,7 @@ workflows: jobs: build_and_test: docker: - - image: rust:1.65.0 + - image: rust:1.70 working_directory: ~/project steps: - checkout @@ -42,8 +42,8 @@ jobs: command: cargo update - restore_cache: keys: - - cargocache-v2-multi-test:1.65.0-{{ checksum "Cargo.lock" }} - - cargocache-v2-multi-test:1.65.0- + - cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} + - cargocache-v2-multi-test:1.70- - run: name: Build library for native target command: cargo build --locked @@ -54,7 +54,7 @@ jobs: paths: - /usr/local/cargo/registry - target - key: cargocache-v2-multi-test:1.65.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} build_minimal: docker: @@ -70,22 +70,22 @@ jobs: command: rm Cargo.lock - restore_cache: keys: - - cargocache-v2-multi-test:1.65.0-minimal-{{ checksum "Cargo.toml" }} + - cargocache-v2-multi-test:1.70-minimal-{{ checksum "Cargo.toml" }} - run: name: Build library for native target - command: cargo build -Zminimal-versions --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 + command: cargo build -Zminimal-versions --all-features - run: name: Run unit tests - command: cargo test --workspace -Zminimal-versions --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 + command: cargo test --workspace -Zminimal-versions --all-features - save_cache: paths: - /usr/local/cargo/registry - target - key: cargocache-v2-multi-test:1.65.0-minimal-{{ checksum "Cargo.toml" }} + key: cargocache-v2-multi-test:1.70-minimal-{{ checksum "Cargo.toml" }} build_maximal: docker: - - image: rust:1.65.0 + - image: rust:1.70 working_directory: ~/project/ steps: - checkout @@ -97,22 +97,22 @@ jobs: command: cargo update - restore_cache: keys: - - cargocache-v2-multi-test:1.65.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} - run: name: Build library for native target command: cargo build --locked --all-features - run: name: Run unit tests - command: cargo test --workspace --locked --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 + command: cargo test --workspace --locked --all-features - save_cache: paths: - /usr/local/cargo/registry - target - key: cargocache-v2-multi-test:1.65.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-multi-test:1.70-{{ checksum "Cargo.lock" }} lint: docker: - - image: rust:1.65.0 + - image: rust:1.70 steps: - checkout - run: @@ -123,8 +123,8 @@ jobs: command: cargo update - restore_cache: keys: - - cargocache-v2-lint-rust:1.65.0-{{ checksum "Cargo.lock" }} - - cargocache-v2-lint-rust:1.65.0- + - cargocache-v2-lint-rust:1.70-{{ checksum "Cargo.lock" }} + - cargocache-v2-lint-rust:1.70- - run: name: Add rustfmt component command: rustup component add rustfmt @@ -143,19 +143,19 @@ jobs: - target/debug/.fingerprint - target/debug/build - target/debug/deps - key: cargocache-v2-lint-rust:1.65.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-lint-rust:1.70-{{ checksum "Cargo.lock" }} coverage: # https://circleci.com/developer/images?imageType=machine machine: - image: ubuntu-2004:202201-02 + image: ubuntu-2204:2024.01.1 steps: - checkout - run: name: Run tests with coverage command: | mkdir -p cov - docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin \ - sh -c "cargo tarpaulin --workspace --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4 --force-clean --engine llvm --out xml --output-dir cov" + docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.27.1 \ + sh -c "cargo tarpaulin --workspace --all-features --force-clean --engine llvm --out xml --output-dir cov" - codecov/upload: file: cov/cobertura.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index d84531fb..c2758683 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,83 @@ # Changelog +## [v2.0.1](https://github.com/CosmWasm/cw-multi-test/tree/v2.0.1) (2024-04-22) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v2.0.0...v2.0.1) + +**Closed issues:** + +- Restore support for `Stargate` messages [\#159](https://github.com/CosmWasm/cw-multi-test/issues/159) + +**Merged pull requests:** + +- Distinctive Stargate [\#163](https://github.com/CosmWasm/cw-multi-test/pull/163) ([DariuszDepta](https://github.com/DariuszDepta)) +- Expose contract storage [\#153](https://github.com/CosmWasm/cw-multi-test/pull/153) ([DariuszDepta](https://github.com/DariuszDepta)) +- Expose prefixed storage [\#154](https://github.com/CosmWasm/cw-multi-test/pull/154) ([DariuszDepta](https://github.com/DariuszDepta)) +- Upgraded dependencies [\#164](https://github.com/CosmWasm/cw-multi-test/pull/164) ([DariuszDepta](https://github.com/DariuszDepta)) +- Fixes typos [\#167](https://github.com/CosmWasm/cw-multi-test/pull/157) ([DariuszDepta](https://github.com/DariuszDepta)) + +## [v2.0.0](https://github.com/CosmWasm/cw-multi-test/tree/v2.0.0) (2024-03-22) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v1.0.0...v2.0.0) + +**Closed issues:** + +- Forward port: Fixing contract wrapper [\#146](https://github.com/CosmWasm/cw-multi-test/issues/146) +- Forward port: `store_code_with_id` helper [#131](https://github.com/CosmWasm/cw-multi-test/issues/131) + +**Merged pull requests:** + +- V2: upgrading dependencies and refactoring [\#128](https://github.com/CosmWasm/cw-multi-test/pull/128) ([DariuszDepta](https://github.com/DariuszDepta)) + +## [v1.0.0](https://github.com/CosmWasm/cw-multi-test/tree/v1.0.0) (2024-03-22) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.20.1...v1.0.0) + +**Closed issues:** + +- Forward port: Fixing contract wrapper [\#145](https://github.com/CosmWasm/cw-multi-test/issues/145) +- Implement `store_code_with_id` helper [\#22](https://github.com/CosmWasm/cw-multi-test/issues/22) +- New `App::store_code` function definition [\#69](https://github.com/CosmWasm/cw-multi-test/issues/69) (wontfix) +- Make `App::store_code_with_creator` deprecated [\#70](https://github.com/CosmWasm/cw-multi-test/issues/70) (wontfix) +- Remove function `next_address` from `AddressGenerator` trait [\#90](https://github.com/CosmWasm/cw-multi-test/issues/90) +- Remove `new_with_custom_address_generator` function from `WasmKeeper` [\#91](https://github.com/CosmWasm/cw-multi-test/issues/91) + +**Merged pull requests:** + +- Refactored contract wrapper [\#149](https://github.com/CosmWasm/cw-multi-test/pull/149) ([DariuszDepta](https://github.com/DariuszDepta)) +- Fixed contract wrapper [\#148](https://github.com/CosmWasm/cw-multi-test/pull/148) ([DariuszDepta](https://github.com/DariuszDepta)) +- Remove `Addr::unchecked` where possible [\#141](https://github.com/CosmWasm/cw-multi-test/pull/141) ([DariuszDepta](https://github.com/DariuszDepta)) +- Refactored wasm trait [\#139](https://github.com/CosmWasm/cw-multi-test/pull/139) ([DariuszDepta](https://github.com/DariuszDepta)) +- Added `IntoAddr` trait [\#138](https://github.com/CosmWasm/cw-multi-test/pull/138) ([DariuszDepta](https://github.com/DariuszDepta)) +- Removed `new_with_custom_address_generator` function [\#135](https://github.com/CosmWasm/cw-multi-test/pull/135) ([DariuszDepta](https://github.com/DariuszDepta)) +- Removed `next_address` function [\#134](https://github.com/CosmWasm/cw-multi-test/pull/134) ([DariuszDepta](https://github.com/DariuszDepta)) +- Added `store_code_with_id` function to `App` [\#117](https://github.com/CosmWasm/cw-multi-test/pull/117) ([DariuszDepta](https://github.com/DariuszDepta)) + +## [v0.20.1](https://github.com/CosmWasm/cw-multi-test/tree/v0.20.1) (2024-03-15) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.20.0...v0.20.1) + +**Merged pull requests:** + +- Fixed contract wrapper [\#147](https://github.com/CosmWasm/cw-multi-test/pull/147) ([DariuszDepta](https://github.com/DariuszDepta)) + +## [v0.20.0](https://github.com/CosmWasm/cw-multi-test/tree/v0.20.0) (2023-12-06) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.19.0...v0.20.0) + +**Closed issues:** + +- Unit testing IBC with mock module fails: Cannot execute Stargate [\#37](https://github.com/CosmWasm/cw-multi-test/issues/37) +- Allow mocking Stargate messages [\#40](https://github.com/CosmWasm/cw-multi-test/issues/40) +- MultiTest does not support CosmosMsg::Stargate [\#88](https://github.com/CosmWasm/cw-multi-test/issues/88) + +**Merged pull requests:** + +- Stargate mock support [\#106](https://github.com/CosmWasm/cw-multi-test/pull/106) ([DariuszDepta](https://github.com/DariuszDepta)) +- Made `no_init` function public [\#107](https://github.com/CosmWasm/cw-multi-test/pull/107) ([DariuszDepta](https://github.com/DariuszDepta)) +- Separated test helper contracts for Gov and IBC [\#108](https://github.com/CosmWasm/cw-multi-test/pull/108) ([DariuszDepta](https://github.com/DariuszDepta)) +- Add test to check custom `AddressGenerator` implementation [\#110](https://github.com/CosmWasm/cw-multi-test/pull/110) ([epanchee](https://github.com/epanchee)) + ## [v0.19.0](https://github.com/CosmWasm/cw-multi-test/tree/v0.19.0) (2023-11-28) [Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.18.1...v0.19.0) @@ -68,6 +146,15 @@ - Adds BankQuery::Supply support [\#51](https://github.com/CosmWasm/cw-multi-test/pull/51) ([JakeHartnell](https://github.com/JakeHartnell)) - Remove direct k256 dependencies [\#47](https://github.com/CosmWasm/cw-multi-test/pull/47) ([webmaster128](https://github.com/webmaster128)) +## [v0.16.6](https://github.com/CosmWasm/cw-multi-test/tree/v0.16.6) (2024-03-15) + +[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.16.5...v0.16.6) + +**Merged pull requests:** + +- Fixed contract + wrapper [\#143](https://github.com/CosmWasm/cw-multi-test/pull/143) ([DariuszDepta](https://github.com/DariuszDepta)) + ## [v0.16.5](https://github.com/CosmWasm/cw-multi-test/tree/v0.16.5) (2023-06-07) [Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.16.4...v0.16.5) @@ -131,6 +218,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. ## [v0.16.1](https://github.com/CosmWasm/cw-plus/tree/v0.16.1) (2022-11-23) [Full Changelog](https://github.com/CosmWasm/cw-plus/compare/v0.16.0...v0.16.1) + - Modules for Stargate (IBC and Gov) messages - failing by default, but possible to exchange ## [v0.16.0](https://github.com/CosmWasm/cw-plus/tree/v0.16.0) (2022-10-14) @@ -329,7 +417,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Update changelog add upcoming [\#675](https://github.com/CosmWasm/cw-plus/pull/675) ([maurolacy](https://github.com/maurolacy)) - Reject proposals early [\#668](https://github.com/CosmWasm/cw-plus/pull/668) ([Callum-A](https://github.com/Callum-A)) - cw20-base: validate addresses are unique in initial balances [\#659](https://github.com/CosmWasm/cw-plus/pull/659) ([harryscholes](https://github.com/harryscholes)) -- New SECURITY.md refering to wasmd [\#624](https://github.com/CosmWasm/cw-plus/pull/624) ([ethanfrey](https://github.com/ethanfrey)) +- New SECURITY.md referring to wasmd [\#624](https://github.com/CosmWasm/cw-plus/pull/624) ([ethanfrey](https://github.com/ethanfrey)) ## [v0.13.0](https://github.com/CosmWasm/cw-plus/tree/v0.13.0) (2022-03-09) @@ -389,7 +477,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. **Merged pull requests:** - Prepare release v0.12.0 [\#654](https://github.com/CosmWasm/cw-plus/pull/654) ([uint](https://github.com/uint)) -- Ics20 same ack handling as ibctransfer [\#653](https://github.com/CosmWasm/cw-plus/pull/653) ([ethanfrey](https://github.com/ethanfrey)) +- Ics20 same ack handling as IBC transfer [\#653](https://github.com/CosmWasm/cw-plus/pull/653) ([ethanfrey](https://github.com/ethanfrey)) - packages: support custom queries [\#652](https://github.com/CosmWasm/cw-plus/pull/652) ([uint](https://github.com/uint)) - CW20 - Fix Docs URL [\#649](https://github.com/CosmWasm/cw-plus/pull/649) ([entrancedjames](https://github.com/entrancedjames)) - CW3: Add proposal\_id field to VoteInfo structure [\#648](https://github.com/CosmWasm/cw-plus/pull/648) ([ueco-jb](https://github.com/ueco-jb)) @@ -539,7 +627,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - ics20: Handle send errors with reply [\#520](https://github.com/CosmWasm/cw-plus/pull/520) ([ethanfrey](https://github.com/ethanfrey)) - Proper execute responses [\#519](https://github.com/CosmWasm/cw-plus/pull/519) ([ethanfrey](https://github.com/ethanfrey)) - Publish MsgInstantiate / Execute responses [\#518](https://github.com/CosmWasm/cw-plus/pull/518) ([maurolacy](https://github.com/maurolacy)) -- Fix instaniate reply data [\#517](https://github.com/CosmWasm/cw-plus/pull/517) ([ethanfrey](https://github.com/ethanfrey)) +- Fix instantiate reply data [\#517](https://github.com/CosmWasm/cw-plus/pull/517) ([ethanfrey](https://github.com/ethanfrey)) - Use protobuf de helpers [\#515](https://github.com/CosmWasm/cw-plus/pull/515) ([maurolacy](https://github.com/maurolacy)) - Add tests for the claims controller [\#514](https://github.com/CosmWasm/cw-plus/pull/514) ([sgoya](https://github.com/sgoya)) - Implement cw3-flex-multisig helper [\#479](https://github.com/CosmWasm/cw-plus/pull/479) ([orkunkl](https://github.com/orkunkl)) @@ -558,9 +646,9 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Prepare 0.10.1 release [\#513](https://github.com/CosmWasm/cw-plus/pull/513) ([ethanfrey](https://github.com/ethanfrey)) - Added cw1-whitelist-ng to CI [\#512](https://github.com/CosmWasm/cw-plus/pull/512) ([hashedone](https://github.com/hashedone)) -- cw1-subkeys-ng: Additional follow up improvements [\#506](https://github.com/CosmWasm/cw-plus/pull/506) ([hashedone](https://github.com/hashedone)) +- cw1-subkeys-ng: Additional follow-up improvements [\#506](https://github.com/CosmWasm/cw-plus/pull/506) ([hashedone](https://github.com/hashedone)) - Parse reply helpers [\#502](https://github.com/CosmWasm/cw-plus/pull/502) ([maurolacy](https://github.com/maurolacy)) -- cw1-whitelist-ng: Contract implementation in terms of semantical structures [\#499](https://github.com/CosmWasm/cw-plus/pull/499) ([hashedone](https://github.com/hashedone)) +- cw1-whitelist-ng: Contract implementation in terms of semantic structures [\#499](https://github.com/CosmWasm/cw-plus/pull/499) ([hashedone](https://github.com/hashedone)) - range\_de for IndexMap [\#498](https://github.com/CosmWasm/cw-plus/pull/498) ([uint](https://github.com/uint)) - Implement range\_de for SnapshotMap [\#497](https://github.com/CosmWasm/cw-plus/pull/497) ([uint](https://github.com/uint)) - Fix publish script [\#486](https://github.com/CosmWasm/cw-plus/pull/486) ([ethanfrey](https://github.com/ethanfrey)) @@ -608,7 +696,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Release v0.10.0-soon4 [\#477](https://github.com/CosmWasm/cw-plus/pull/477) ([ethanfrey](https://github.com/ethanfrey)) - Update to CosmWasm 1.0.0-soon2 [\#475](https://github.com/CosmWasm/cw-plus/pull/475) ([ethanfrey](https://github.com/ethanfrey)) - Allow error type conversions in ensure! and ensure\_eq! [\#474](https://github.com/CosmWasm/cw-plus/pull/474) ([webmaster128](https://github.com/webmaster128)) -- Improve error handling / remove FIXMEs [\#470](https://github.com/CosmWasm/cw-plus/pull/470) ([maurolacy](https://github.com/maurolacy)) +- Improve error handling / remove FIXME markers [\#470](https://github.com/CosmWasm/cw-plus/pull/470) ([maurolacy](https://github.com/maurolacy)) - Add ensure [\#469](https://github.com/CosmWasm/cw-plus/pull/469) ([ethanfrey](https://github.com/ethanfrey)) - Key deserializer improvements [\#467](https://github.com/CosmWasm/cw-plus/pull/467) ([maurolacy](https://github.com/maurolacy)) - Upgrade to cosmwasm/workspace-optimizer:0.12.3 [\#465](https://github.com/CosmWasm/cw-plus/pull/465) ([webmaster128](https://github.com/webmaster128)) @@ -659,7 +747,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - storage-plus: Improve in-code documentation of map primitives, in particular `MultiIndex` [\#407](https://github.com/CosmWasm/cw-plus/issues/407) - Remove use of dyn in multitest Router [\#404](https://github.com/CosmWasm/cw-plus/issues/404) - Define generic multitest module [\#387](https://github.com/CosmWasm/cw-plus/issues/387) -- Cw20 state key compatibity with previous versions [\#346](https://github.com/CosmWasm/cw-plus/issues/346) +- Cw20 state key compatibility with previous versions [\#346](https://github.com/CosmWasm/cw-plus/issues/346) - Refactor cw20-base to use controller pattern [\#205](https://github.com/CosmWasm/cw-plus/issues/205) **Merged pull requests:** @@ -715,7 +803,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Snapshot item [\#409](https://github.com/CosmWasm/cw-plus/pull/409) ([maurolacy](https://github.com/maurolacy)) - cw20-base: upgrade helper.ts to cosmjs 0.26.0 [\#406](https://github.com/CosmWasm/cw-plus/pull/406) ([spacepotahto](https://github.com/spacepotahto)) - CW1-whitelist execute multitest [\#402](https://github.com/CosmWasm/cw-plus/pull/402) ([ueco-jb](https://github.com/ueco-jb)) -- Implementing all messages handling in mutlitest App [\#398](https://github.com/CosmWasm/cw-plus/pull/398) ([hashedone](https://github.com/hashedone)) +- Implementing all messages handling in MultiTest App [\#398](https://github.com/CosmWasm/cw-plus/pull/398) ([hashedone](https://github.com/hashedone)) - Make it easier to assert events on reply statements [\#395](https://github.com/CosmWasm/cw-plus/pull/395) ([ethanfrey](https://github.com/ethanfrey)) - Add helpers to check events [\#392](https://github.com/CosmWasm/cw-plus/pull/392) ([ethanfrey](https://github.com/ethanfrey)) - Switching from String to anyhow::Error for error type in multi-test [\#389](https://github.com/CosmWasm/cw-plus/pull/389) ([hashedone](https://github.com/hashedone)) @@ -788,7 +876,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Responses validation in multi-test [\#373](https://github.com/CosmWasm/cw-plus/pull/373) ([hashedone](https://github.com/hashedone)) - Cw20 logo spec [\#370](https://github.com/CosmWasm/cw-plus/pull/370) ([ethanfrey](https://github.com/ethanfrey)) - Properly handling data in submessages in multi-test [\#369](https://github.com/CosmWasm/cw-plus/pull/369) ([hashedone](https://github.com/hashedone)) -- Abstracting API out of tests internals so it is clearly owned by `App` [\#368](https://github.com/CosmWasm/cw-plus/pull/368) ([hashedone](https://github.com/hashedone)) +- Abstracting API out of tests internals, so it is clearly owned by `App` [\#368](https://github.com/CosmWasm/cw-plus/pull/368) ([hashedone](https://github.com/hashedone)) - Storage plus doc correction [\#367](https://github.com/CosmWasm/cw-plus/pull/367) ([hashedone](https://github.com/hashedone)) - Multitest migrate support [\#366](https://github.com/CosmWasm/cw-plus/pull/366) ([ethanfrey](https://github.com/ethanfrey)) - Reorganizations of contracts in `multi-test::test_utils` [\#365](https://github.com/CosmWasm/cw-plus/pull/365) ([hashedone](https://github.com/hashedone)) @@ -841,7 +929,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Proper event/data handling on reply in multitest [\#326](https://github.com/CosmWasm/cw-plus/issues/326) - Messages differ for cw20 & cw20\_base [\#320](https://github.com/CosmWasm/cw-plus/issues/320) - Upgrade cw20-staking to cw 15 [\#312](https://github.com/CosmWasm/cw-plus/issues/312) -- Uprade cw20-ics20 to cw 0.15 [\#311](https://github.com/CosmWasm/cw-plus/issues/311) +- Upgrade cw20-ics20 to cw 0.15 [\#311](https://github.com/CosmWasm/cw-plus/issues/311) - Upgrade cw20-escrow to 0.15 [\#309](https://github.com/CosmWasm/cw-plus/issues/309) - Upgrade cw20-bonding to 0.15 [\#307](https://github.com/CosmWasm/cw-plus/issues/307) - cw1-subkeys [\#305](https://github.com/CosmWasm/cw-plus/issues/305) @@ -911,7 +999,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. **Merged pull requests:** - Clarify index\_key\(\) range\(\) vs prefix\(\) behaviour [\#291](https://github.com/CosmWasm/cw-plus/pull/291) ([maurolacy](https://github.com/maurolacy)) -- Pkowned to vec u8 [\#290](https://github.com/CosmWasm/cw-plus/pull/290) ([maurolacy](https://github.com/maurolacy)) +- PkOwned to vec u8 [\#290](https://github.com/CosmWasm/cw-plus/pull/290) ([maurolacy](https://github.com/maurolacy)) - Update to CosmWasm v0.14.0 [\#289](https://github.com/CosmWasm/cw-plus/pull/289) ([ethanfrey](https://github.com/ethanfrey)) - Primary key / index key helpers [\#288](https://github.com/CosmWasm/cw-plus/pull/288) ([maurolacy](https://github.com/maurolacy)) @@ -961,7 +1049,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. **Merged pull requests:** -- Bump dependency to cosmasm v0.14.0-beta3 [\#269](https://github.com/CosmWasm/cw-plus/pull/269) ([ethanfrey](https://github.com/ethanfrey)) +- Bump dependency to cosmwasm v0.14.0-beta3 [\#269](https://github.com/CosmWasm/cw-plus/pull/269) ([ethanfrey](https://github.com/ethanfrey)) - Remove unused PrimaryKey::parse\_key [\#267](https://github.com/CosmWasm/cw-plus/pull/267) ([webmaster128](https://github.com/webmaster128)) - Use workspace-optimizer:0.11.0 [\#262](https://github.com/CosmWasm/cw-plus/pull/262) ([webmaster128](https://github.com/webmaster128)) - Update cosmwasm-std [\#260](https://github.com/CosmWasm/cw-plus/pull/260) ([yihuang](https://github.com/yihuang)) @@ -1072,7 +1160,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Don't use hooks for snapshotting on cw3-cw4 interface [\#162](https://github.com/CosmWasm/cw-plus/issues/162) - Refactor snapshotting into reusable module [\#161](https://github.com/CosmWasm/cw-plus/issues/161) - Distinguish between weight 0 and not member in cw3 queries [\#154](https://github.com/CosmWasm/cw-plus/issues/154) -- Migrate strorage-plus to v0.12.0 [\#149](https://github.com/CosmWasm/cw-plus/issues/149) +- Migrate storage-plus to v0.12.0 [\#149](https://github.com/CosmWasm/cw-plus/issues/149) - Asymmetries between query and execute in CW1 \(subkeys\) [\#145](https://github.com/CosmWasm/cw-plus/issues/145) - Add token-weighted group [\#142](https://github.com/CosmWasm/cw-plus/issues/142) - Multisig handles changes to group membership [\#141](https://github.com/CosmWasm/cw-plus/issues/141) @@ -1180,7 +1268,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. **Closed issues:** -- Migration to 0.11: errors of shared functions accross contracts [\#103](https://github.com/CosmWasm/cw-plus/issues/103) +- Migration to 0.11: errors of shared functions across contracts [\#103](https://github.com/CosmWasm/cw-plus/issues/103) - Look at serde\(flatten\) to simplify return value composition [\#57](https://github.com/CosmWasm/cw-plus/issues/57) **Merged pull requests:** @@ -1222,7 +1310,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. **Closed issues:** - Implement Copy for Coin / Vec\ [\#77](https://github.com/CosmWasm/cw-plus/issues/77) -- Why does not cw20 pass the received native token? [\#74](https://github.com/CosmWasm/cw-plus/issues/74) +- Why cw20 does not pass the received native token? [\#74](https://github.com/CosmWasm/cw-plus/issues/74) - Cw20Coin duplication [\#73](https://github.com/CosmWasm/cw-plus/issues/73) - Fix docker run script in all contract README [\#69](https://github.com/CosmWasm/cw-plus/issues/69) - Add cw20 support to atomic swap contract [\#27](https://github.com/CosmWasm/cw-plus/issues/27) @@ -1275,7 +1363,7 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Bump all CosmWasm dependencies to 0.10.1 [\#56](https://github.com/CosmWasm/cw-plus/pull/56) ([ethanfrey](https://github.com/ethanfrey)) - Add new query to return all allowances on subkeys [\#54](https://github.com/CosmWasm/cw-plus/pull/54) ([ethanfrey](https://github.com/ethanfrey)) - Add CanSend query to the cw1 spec [\#53](https://github.com/CosmWasm/cw-plus/pull/53) ([ethanfrey](https://github.com/ethanfrey)) -- Add Expration to cw0 [\#51](https://github.com/CosmWasm/cw-plus/pull/51) ([ethanfrey](https://github.com/ethanfrey)) +- Add expiration to cw0 [\#51](https://github.com/CosmWasm/cw-plus/pull/51) ([ethanfrey](https://github.com/ethanfrey)) - Nft 721 spec [\#50](https://github.com/CosmWasm/cw-plus/pull/50) ([ethanfrey](https://github.com/ethanfrey)) - Add Subkeys helper [\#49](https://github.com/CosmWasm/cw-plus/pull/49) ([ethanfrey](https://github.com/ethanfrey)) - Add helpers to cw20-base [\#46](https://github.com/CosmWasm/cw-plus/pull/46) ([ethanfrey](https://github.com/ethanfrey)) @@ -1331,6 +1419,4 @@ changelog will be noisy - not everything is relevant to `cw-multi-test` there. - Define all Message and Query types [\#11](https://github.com/CosmWasm/cw-plus/pull/11) ([ethanfrey](https://github.com/ethanfrey)) - Set up basic CI script [\#10](https://github.com/CosmWasm/cw-plus/pull/10) ([ethanfrey](https://github.com/ethanfrey)) - - \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* diff --git a/CLA.md b/CLA.md deleted file mode 100644 index 17a701ee..00000000 --- a/CLA.md +++ /dev/null @@ -1,23 +0,0 @@ -## Contributor License Agreement -The following terms are used throughout this agreement: - -* You - the person or legal entity including its affiliates asked to accept this agreement. An affiliate is any entity that controls or is controlled by the legal entity, or is under common control with it. -* Project - is an umbrella term that refers to any and all Confio OÜ open source projects. -* Contribution - any type of work that is submitted to a Project, including any modifications or additions to existing work. -* Submitted - conveyed to a Project via a pull request, commit, issue, or any form of electronic, written, or verbal communication with Confio OÜ, contributors or maintainers. - -## 1. Grant of Copyright License. - -Subject to the terms and conditions of this agreement, You grant to the Projects’ maintainers, contributors, users and to Confio OÜ a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your contributions and such derivative works. Except for this license, You reserve all rights, title, and interest in your contributions. - -## 2. Grant of Patent License. - -Subject to the terms and conditions of this agreement, You grant to the Projects’ maintainers, contributors, users and to Confio OÜ a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer your contributions, where such license applies only to those patent claims licensable by you that are necessarily infringed by your contribution or by combination of your contribution with the project to which this contribution was submitted. - -If any entity institutes patent litigation - including cross-claim or counterclaim in a lawsuit - against You alleging that your contribution or any project it was submitted to constitutes or is responsible for direct or contributory patent infringement, then any patent licenses granted to that entity under this agreement shall terminate as of the date such litigation is filed. - -## 3. Source of Contribution. - -Your contribution is either your original creation, based upon previous work that, to the best of your knowledge, is covered under an appropriate open source license and you have the right under that license to submit that work with modifications, whether created in whole or in part by you, or you have clearly identified the source of the contribution and any license or other restriction (like related patents, trademarks, and license agreements) of which you are personally aware. - -_Based in [GitHub's CLA](https://cla.github.com/agreement)__ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 6ce5bb86..e3f565c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -673,7 +673,7 @@ name = "clone-cw-multi-test" version = "0.6.2" dependencies = [ "anyhow", - "bech32 0.9.1", + "bech32 0.11.0", "cargo_metadata", "cosmrs", "cosmwasm-schema 2.1.3", diff --git a/Cargo.toml b/Cargo.toml index 640b110a..b2c1a004 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ backtrace = ["anyhow/backtrace"] [dependencies] anyhow = "1.0.75" -bech32 = "0.9.1" +bech32 = "0.11.0" cosmwasm-std = { version = "2.1", features = [ "iterator", "staking", @@ -29,7 +29,7 @@ prost = "0.13.0" schemars = "0.8.16" serde = "1.0.193" sha2 = "0.10.8" -thiserror = "1.0.50" +thiserror = "1.0.61" # Clone testing deps ## Network diff --git a/SECURITY.md b/SECURITY.md index 830ec171..e5fc15ed 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,16 +1,11 @@ # Security Policy This repository is maintained by Confio as part of the CosmWasm stack. -Please see https://github.com/CosmWasm/advisories/blob/main/SECURITY.md -for our security policy. -## Supported Versions - -cw-plus is still pre v1.0. A best effort has been made that the contracts here are secure, and we have moved the more -experimental contracts into community repositories like [cw-nfts](https://github.com/CosmWasm/cw-nfts) and -[cw-tokens](https://github.com/CosmWasm/cw-tokens). That said, we have not done an audit on them (formal or informal) -and you can use them at your own risk. We highly suggest doing your own audit on any contract you plan to deploy -with significant token value, and please inform us if it detects any issues so we can upstream them. - -Until v1.0 APIs are subject to change. The contracts APIs are pretty much stable, most work is currently -in `storage-plus` and `multi-test`. +The code here is not intended to be used in production +(i.e. cw-multi-test should only be used as a [Development dependency](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#development-dependencies)). +Thus it is not covered by the Cosmos bug bounty program and is not treated as strict +as other components when it comes to bugs. +However, if you still think you found a security critical +issue please find the contact information at +https://github.com/CosmWasm/advisories/blob/main/SECURITY.md. diff --git a/src/addons/addresses/mock.rs b/src/addons/addresses/mock.rs deleted file mode 100644 index 081199cc..00000000 --- a/src/addons/addresses/mock.rs +++ /dev/null @@ -1,148 +0,0 @@ -use crate::error::AnyResult; -use crate::AddressGenerator; -use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage}; -use sha2::digest::Update; -use sha2::{Digest, Sha256}; - -/// Address generator that mimics the original `wasmd` behavior. -/// -/// [MockAddressGenerator] implements [AddressGenerator] trait in terms of -/// [`contract_address`](AddressGenerator::contract_address) and -/// [`predictable_contract_address`](AddressGenerator::predictable_contract_address) functions: -/// - `contract_address` generates non-predictable addresses for contracts, -/// using the same algorithm as `wasmd`, see: [`BuildContractAddressClassic`] for details. -/// - `predictable_contract_address` generates predictable addresses for contracts using -/// [`instantiate2_address`] function defined in `cosmwasm-std`. -/// -/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41 -/// [`instantiate2_address`]:https://github.com/CosmWasm/cosmwasm/blob/8a652d7cd8071f71139deca6be8194ed4a278b2c/packages/std/src/addresses.rs#L309-L318 -#[derive(Default)] -pub struct MockAddressGenerator; - -impl AddressGenerator for MockAddressGenerator { - /// Generates a _non-predictable_ contract address, like `wasmd` does it in real-life chain. - /// - /// Note that addresses generated by `wasmd` may change and users **should not** - /// rely on this value in any extend. - /// - /// Returns the contract address after its instantiation. - /// Address generated by this function is returned as a result - /// of processing `WasmMsg::Instantiate` message. - /// - /// **NOTES** - /// > 👉 The canonical address generated by this function is humanized using the - /// > `Api::addr_humanize` function, so the resulting value depends on used `Api` implementation. - /// > The following example uses Bech32 format for humanizing canonical addresses. - /// - /// > 👉 Do NOT use this function **directly** to generate a contract address, - /// > pass this address generator to `WasmKeeper`: - /// > `WasmKeeper::new().with_address_generator(MockAddressGenerator::default());` - /// - /// # Example - /// - /// ``` - /// # use cosmwasm_std::testing::MockStorage; - /// # use cw_multi_test::AddressGenerator; - /// # use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; - /// // use `Api` that implements Bech32 format - /// let api = MockApiBech32::new("juno"); - /// // prepare mock storage - /// let mut storage = MockStorage::default(); - /// // initialize the address generator - /// let address_generator = MockAddressGenerator::default(); - /// // generate the address - /// let addr = address_generator.contract_address(&api, &mut storage, 1, 1).unwrap(); - /// - /// assert_eq!(addr.to_string(), - /// "juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8"); - /// ``` - fn contract_address( - &self, - api: &dyn Api, - _storage: &mut dyn Storage, - code_id: u64, - instance_id: u64, - ) -> AnyResult { - let canonical_addr = instantiate_address(code_id, instance_id); - Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) - } - - /// Generates a _predictable_ contract address, like `wasmd` does it in real-life chain. - /// - /// Returns a contract address after its instantiation. - /// Address generated by this function is returned as a result - /// of processing `WasmMsg::Instantiate2` message. - /// - /// **NOTES** - /// > 👉 The canonical address generated by this function is humanized using the - /// > `Api::addr_humanize` function, so the resulting value depends on used `Api` implementation. - /// > The following example uses Bech32 format for humanizing canonical addresses. - /// - /// > 👉 Do NOT use this function **directly** to generate a contract address, - /// > pass this address generator to WasmKeeper: - /// > `WasmKeeper::new().with_address_generator(MockAddressGenerator::default());` - /// - /// # Example - /// - /// ``` - /// # use cosmwasm_std::Api; - /// # use cosmwasm_std::testing::MockStorage; - /// # use cw_multi_test::AddressGenerator; - /// # use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; - /// // use `Api` that implements Bech32 format - /// let api = MockApiBech32::new("juno"); - /// // prepare mock storage - /// let mut storage = MockStorage::default(); - /// // initialize the address generator - /// let address_generator = MockAddressGenerator::default(); - /// // checksum of the contract code base - /// let checksum = [0, 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10, - /// 11,12,13,14,15,16,17,18,19,20,21, - /// 22,23,24,25,26,27,28,29,30,31]; - /// // creator address - /// let creator = api.addr_canonicalize(api.addr_make("creator").as_str()).unwrap(); - /// // salt - /// let salt = [10,11,12]; - /// // generate the address - /// let addr = address_generator - /// .predictable_contract_address(&api, &mut storage, 1, 1, &checksum, &creator, &salt) - /// .unwrap(); - /// - /// assert_eq!(addr.to_string(), - /// "juno1sv3gjp85m3xxluxreruards8ruxk5ykys8qfljwrdj5tv8kqxuhsmlfyud"); - /// ``` - fn predictable_contract_address( - &self, - api: &dyn Api, - _storage: &mut dyn Storage, - _code_id: u64, - _instance_id: u64, - checksum: &[u8], - - creator: &CanonicalAddr, - salt: &[u8], - ) -> AnyResult { - let canonical_addr = instantiate2_address(checksum, creator, salt)?; - Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) - } -} - -/// Returns non-predictable contract address. -/// -/// Address is generated using the same algorithm as [`BuildContractAddressClassic`] -/// implementation in `wasmd`. -/// -/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41 -fn instantiate_address(code_id: u64, instance_id: u64) -> CanonicalAddr { - let mut key = Vec::::new(); - key.extend_from_slice(b"wasm\0"); - key.extend_from_slice(&code_id.to_be_bytes()); - key.extend_from_slice(&instance_id.to_be_bytes()); - let module = Sha256::digest("module".as_bytes()); - Sha256::new() - .chain(module) - .chain(key) - .finalize() - .to_vec() - .into() -} diff --git a/src/addons/addresses/mod.rs b/src/addons/addresses/mod.rs deleted file mode 100644 index 9afc1d5e..00000000 --- a/src/addons/addresses/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod mock; diff --git a/src/addons/api/bech32.rs b/src/addons/api/bech32.rs deleted file mode 100644 index 55b21cc3..00000000 --- a/src/addons/api/bech32.rs +++ /dev/null @@ -1,187 +0,0 @@ -use bech32::{decode, encode, FromBase32, ToBase32, Variant}; -use cosmwasm_std::testing::MockApi; -use cosmwasm_std::{ - Addr, Api, CanonicalAddr, RecoverPubkeyError, StdError, StdResult, VerificationError, -}; -use sha2::{Digest, Sha256}; - -/// Implementation of the `Api` trait that uses [`Bech32`] format -/// for humanizing canonical addresses. -/// -/// [`Bech32`]:https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki -pub struct MockApiBech32 { - api: MockApi, - prefix: String, - variant: Variant, -} - -impl MockApiBech32 { - /// Returns `Api` implementation that uses specified prefix - /// to generate addresses in **Bech32** format. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(addr.as_str(), - /// "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"); - /// ``` - pub fn new(prefix: &str) -> Self { - Self::new_with_variant(prefix, Variant::Bech32) - } - - /// Creates `Api` implementation that uses specified prefix - /// to generate addresses in format defined by provided Bech32 variant. - pub(crate) fn new_with_variant(prefix: &str, variant: Variant) -> Self { - Self { - api: MockApi::default(), - prefix: prefix.to_string(), - variant, - } - } -} - -impl Api for MockApiBech32 { - /// Takes a human readable address in **Bech32** format and checks if it is valid. - /// - /// If the validation succeeds, an `Addr` containing the same string as the input is returned. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(api.addr_validate(addr.as_str()).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_validate(&self, input: &str) -> StdResult { - self.addr_humanize(&self.addr_canonicalize(input)?) - } - - /// Takes a human readable address in **Bech32** format and returns - /// a canonical binary representation of it. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(api.addr_canonicalize(addr.as_str()).unwrap().to_string(), - /// "BC6BFD848EBD7819C9A82BF124D65E7F739D08E002601E23BB906AACD40A3D81"); - /// ``` - fn addr_canonicalize(&self, input: &str) -> StdResult { - if let Ok((prefix, decoded, variant)) = decode(input) { - if prefix == self.prefix && variant == self.variant { - if let Ok(bytes) = Vec::::from_base32(&decoded) { - return Ok(bytes.into()); - } - } - } - Err(StdError::generic_err("Invalid input")) - } - - /// Takes a canonical address and returns a human readable address in **Bech32** format. - /// - /// This is the inverse operation of [`addr_canonicalize`]. - /// - /// [`addr_canonicalize`]: MockApiBech32::addr_canonicalize - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// let canonical_addr = api.addr_canonicalize(addr.as_str()).unwrap(); - /// assert_eq!(api.addr_humanize(&canonical_addr).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - if let Ok(encoded) = encode(&self.prefix, canonical.as_slice().to_base32(), self.variant) { - Ok(Addr::unchecked(encoded)) - } else { - Err(StdError::generic_err("Invalid canonical address")) - } - } - - fn secp256k1_verify( - &self, - message_hash: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.api - .secp256k1_verify(message_hash, signature, public_key) - } - - fn secp256k1_recover_pubkey( - &self, - message_hash: &[u8], - signature: &[u8], - recovery_param: u8, - ) -> Result, RecoverPubkeyError> { - self.api - .secp256k1_recover_pubkey(message_hash, signature, recovery_param) - } - - fn ed25519_verify( - &self, - message: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.api.ed25519_verify(message, signature, public_key) - } - - fn ed25519_batch_verify( - &self, - messages: &[&[u8]], - signatures: &[&[u8]], - public_keys: &[&[u8]], - ) -> Result { - self.api - .ed25519_batch_verify(messages, signatures, public_keys) - } - - fn debug(&self, message: &str) { - self.api.debug(message) - } -} - -impl MockApiBech32 { - /// Returns an address in **Bech32** format, built from provided input string. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("juno"); - /// let addr = api.addr_make("creator"); - /// assert_eq!(addr.as_str(), - /// "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"); - /// ``` - /// - /// # Panics - /// - /// This function panics when generating a valid address in **Bech32** - /// format is not possible, especially when prefix is too long or empty. - pub fn addr_make(&self, input: &str) -> Addr { - let digest = Sha256::digest(input).to_vec(); - match encode(&self.prefix, digest.to_base32(), self.variant) { - Ok(address) => Addr::unchecked(address), - Err(reason) => panic!("Generating address failed with reason: {}", reason), - } - } -} diff --git a/src/addons/api/bech32m.rs b/src/addons/api/bech32m.rs deleted file mode 100644 index d630f2b0..00000000 --- a/src/addons/api/bech32m.rs +++ /dev/null @@ -1,154 +0,0 @@ -use crate::addons::MockApiBech32; -use bech32::Variant; -use cosmwasm_std::{Addr, Api, CanonicalAddr, RecoverPubkeyError, StdResult, VerificationError}; - -/// Implementation of the `Api` trait that uses [`Bech32m`] format -/// for humanizing canonical addresses. -/// -/// [`Bech32m`]:https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki -pub struct MockApiBech32m(MockApiBech32); - -impl MockApiBech32m { - /// Returns `Api` implementation that uses specified prefix - /// to generate addresses in **Bech32m** format. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::addons::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmosis"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(addr.as_str(), - /// "osmosis1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qgv9940"); - /// ``` - pub fn new(prefix: &'static str) -> Self { - Self(MockApiBech32::new_with_variant(prefix, Variant::Bech32m)) - } -} - -impl Api for MockApiBech32m { - /// Takes a human readable address in **Bech32m** format and checks if it is valid. - /// - /// If the validation succeeds, an `Addr` containing the same string as the input is returned. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmosis"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(api.addr_validate(addr.as_str()).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_validate(&self, input: &str) -> StdResult { - self.0.addr_validate(input) - } - - /// Takes a human readable address in **Bech32m** format and returns - /// a canonical binary representation of it. - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32; - /// - /// let api = MockApiBech32::new("osmosis"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(api.addr_canonicalize(addr.as_str()).unwrap().to_string(), - /// "0A367B92CF0B037DFD89960EE832D56F7FC151681BB41E53690E776F5786998A"); - /// ``` - fn addr_canonicalize(&self, input: &str) -> StdResult { - self.0.addr_canonicalize(input) - } - - /// Takes a canonical address and returns a human readable address in **Bech32m** format. - /// - /// This is the inverse operation of [`addr_canonicalize`]. - /// - /// [`addr_canonicalize`]: MockApiBech32m::addr_canonicalize - /// - /// # Example - /// - /// ``` - /// use cosmwasm_std::Api; - /// use cw_multi_test::addons::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmosis"); - /// let addr = api.addr_make("sender"); - /// let canonical_addr = api.addr_canonicalize(addr.as_str()).unwrap(); - /// assert_eq!(api.addr_humanize(&canonical_addr).unwrap().as_str(), - /// addr.as_str()); - /// ``` - fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - self.0.addr_humanize(canonical) - } - - fn secp256k1_verify( - &self, - message_hash: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.0.secp256k1_verify(message_hash, signature, public_key) - } - - fn secp256k1_recover_pubkey( - &self, - message_hash: &[u8], - signature: &[u8], - recovery_param: u8, - ) -> Result, RecoverPubkeyError> { - self.0 - .secp256k1_recover_pubkey(message_hash, signature, recovery_param) - } - - fn ed25519_verify( - &self, - message: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - self.0.ed25519_verify(message, signature, public_key) - } - - fn ed25519_batch_verify( - &self, - messages: &[&[u8]], - signatures: &[&[u8]], - public_keys: &[&[u8]], - ) -> Result { - self.0 - .ed25519_batch_verify(messages, signatures, public_keys) - } - - fn debug(&self, message: &str) { - self.0.debug(message) - } -} - -impl MockApiBech32m { - /// Returns an address in **Bech32m** format, built from provided input string. - /// - /// # Example - /// - /// ``` - /// use cw_multi_test::addons::MockApiBech32m; - /// - /// let api = MockApiBech32m::new("osmosis"); - /// let addr = api.addr_make("sender"); - /// assert_eq!(addr.as_str(), - /// "osmosis1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qgv9940"); - /// ``` - /// - /// # Panics - /// - /// This function panics when generating a valid address in **Bech32** - /// format is not possible, especially when prefix is too long or empty. - pub fn addr_make(&self, input: &str) -> Addr { - self.0.addr_make(input) - } -} diff --git a/src/addons/api/mod.rs b/src/addons/api/mod.rs deleted file mode 100644 index d59bbae5..00000000 --- a/src/addons/api/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod bech32; -pub mod bech32m; diff --git a/src/addons/mod.rs b/src/addons/mod.rs deleted file mode 100644 index c31658c3..00000000 --- a/src/addons/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! # MultiTest add-ons -//! -//! Additional components and functionalities used to enhance -//! or customize tests of CosmWasm smart contracts. - -mod addresses; -mod api; - -pub use addresses::mock::MockAddressGenerator; -pub use api::bech32::MockApiBech32; -pub use api::bech32m::MockApiBech32m; diff --git a/src/addresses.rs b/src/addresses.rs index 3a0b1669..43d49341 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -1,9 +1,78 @@ -//! # Implementation of address generators +//! # Implementation of address conversions and generators use crate::error::AnyResult; -use crate::prefixed_storage::prefixed_read; -use crate::wasm::{CONTRACTS, NAMESPACE_WASM}; -use cosmwasm_std::{Addr, Api, CanonicalAddr, HexBinary, Order, Storage}; +use crate::{MockApiBech32, MockApiBech32m}; +use cosmwasm_std::testing::MockApi; +use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage}; +use sha2::digest::Update; +use sha2::{Digest, Sha256}; + +const DEFAULT_PREFIX: &str = "cosmwasm"; + +/// Defines conversions to [Addr], this conversion is format agnostic +/// and should be aligned with the format generated by [MockApi]. +/// +/// [MockApi]: https://github.com/CosmWasm/cosmwasm/blob/9a239838baba50f4f47230da306f39a8bb4ea697/packages/std/src/testing/mock.rs#L251-L257 +pub trait IntoAddr { + /// Converts into [Addr]. + fn into_addr(self) -> Addr; + + /// Converts into [Addr] with custom prefix. + fn into_addr_with_prefix(self, prefix: &'static str) -> Addr; +} + +impl IntoAddr for &str { + /// Converts [&str] into [Addr]. + fn into_addr(self) -> Addr { + MockApi::default().addr_make(self) + } + + /// Converts [&str] into [Addr] with custom prefix. + fn into_addr_with_prefix(self, prefix: &'static str) -> Addr { + MockApi::default().with_prefix(prefix).addr_make(self) + } +} + +/// Defines conversions to `Bech32` compatible addresses. +pub trait IntoBech32 { + /// Converts into [Addr] containing a string compatible with `Bech32` format with default prefix. + fn into_bech32(self) -> Addr; + + /// Converts into [Addr] containing a string compatible with `Bech32` format with custom prefix. + fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr; +} + +impl IntoBech32 for &str { + /// Converts [&str] into [Addr] containing a string compatible with `Bech32` format with default prefix. + fn into_bech32(self) -> Addr { + MockApiBech32::new(DEFAULT_PREFIX).addr_make(self) + } + + /// Converts [&str] into [Addr] containing a string compatible with `Bech32` format with custom prefix. + fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr { + MockApiBech32::new(prefix).addr_make(self) + } +} + +/// Defines conversions to `Bech32m` compatible addresses. +pub trait IntoBech32m { + /// Converts into [Addr] containing a string compatible with `Bech32m` format with default prefix. + fn into_bech32m(self) -> Addr; + /// Converts into [Addr] containing a string compatible with `Bech32m` format with custom prefix. + fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr; +} + +impl IntoBech32m for &str { + /// Converts [&str] into [Addr] containing a string compatible with `Bech32m` format with default prefix. + fn into_bech32m(self) -> Addr { + MockApiBech32m::new(DEFAULT_PREFIX).addr_make(self) + } + + /// Converts [&str] into [Addr] containing a string compatible with `Bech32m` format with custom prefix. + fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr { + MockApiBech32m::new(prefix).addr_make(self) + } +} /// Common address generator interface. /// @@ -12,30 +81,13 @@ use cosmwasm_std::{Addr, Api, CanonicalAddr, HexBinary, Order, Storage}; /// or [predictable_contract_address](AddressGenerator::predictable_contract_address) is used, /// but users should not make any assumptions about the value of the generated address. pub trait AddressGenerator { - #[deprecated( - since = "0.18.0", - note = "use `contract_address` or `predictable_contract_address` instead; will be removed in version 1.0.0" - )] - fn next_address(&self, storage: &mut dyn Storage) -> Addr { - //TODO After removing this function in version 1.0, make `CONTRACTS` and `NAMESPACE_WASM` private in `wasm.rs`. - let count = CONTRACTS - .range_raw( - &prefixed_read(storage, NAMESPACE_WASM), - None, - None, - Order::Ascending, - ) - .count(); - Addr::unchecked(format!("contract{}", count)) - } - /// Generates a _non-predictable_ contract address, just like the real-life chain /// returns contract address after its instantiation. /// Address generated by this function is returned as a result of processing /// `WasmMsg::Instantiate` message. /// /// The default implementation generates a contract address based - /// on contract's instance identifier only. + /// on contract's code and instance identifier. /// /// # Example /// @@ -50,26 +102,18 @@ pub trait AddressGenerator { /// /// let my_address_generator = MyAddressGenerator{}; /// - /// let addr = my_address_generator.contract_address(&api, &mut storage, 100, 0).unwrap(); - /// assert_eq!(addr.to_string(),"contract0"); - /// /// let addr = my_address_generator.contract_address(&api, &mut storage, 100, 1).unwrap(); - /// assert_eq!(addr.to_string(),"contract1"); - /// - /// let addr = my_address_generator.contract_address(&api, &mut storage, 200, 5).unwrap(); - /// assert_eq!(addr.to_string(),"contract5"); - /// - /// let addr = my_address_generator.contract_address(&api, &mut storage, 200, 6).unwrap(); - /// assert_eq!(addr.to_string(),"contract6"); + /// assert!(addr.as_str().starts_with("cosmwasm1")); /// ``` fn contract_address( &self, - _api: &dyn Api, + api: &dyn Api, _storage: &mut dyn Storage, - _code_id: u64, + code_id: u64, instance_id: u64, ) -> AnyResult { - Ok(Addr::unchecked(format!("contract{instance_id}"))) + let canonical_addr = instantiate_address(code_id, instance_id); + Ok(api.addr_humanize(&canonical_addr)?) } /// Generates a _predictable_ contract address, just like the real-life chain @@ -77,52 +121,76 @@ pub trait AddressGenerator { /// Address generated by this function is returned as a result of processing /// `WasmMsg::Instantiate2` message. /// - /// The default implementation generates a contract address based on provided salt only. + /// The default implementation generates a contract address based on provided + /// creator address and salt. /// /// # Example /// /// ``` - /// # use cosmwasm_std::Api; + /// # use cosmwasm_std::{Api, Checksum}; /// # use cosmwasm_std::testing::{MockApi, MockStorage}; /// # use cw_multi_test::{AddressGenerator, SimpleAddressGenerator}; /// # let api = MockApi::default(); /// # let mut storage = MockStorage::default(); - /// # let creator = api.addr_canonicalize("creator").unwrap(); /// struct MyAddressGenerator; /// /// impl AddressGenerator for MyAddressGenerator {} /// /// let my_address_generator = MyAddressGenerator{}; /// - /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 100, 0, &[0], &creator, &[0]).unwrap(); - /// assert_eq!(addr.to_string(),"contract00"); - /// - /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 100, 1, &[1], &creator, &[0]).unwrap(); - /// assert_eq!(addr.to_string(),"contract00"); - /// - /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 200, 0, &[2], &creator, &[1]).unwrap(); - /// assert_eq!(addr.to_string(),"contract01"); - /// - /// let addr = my_address_generator.predictable_contract_address(&api, &mut storage, 200, 1, &[3], &creator, &[1]).unwrap(); - /// assert_eq!(addr.to_string(),"contract01"); + /// let creator1 = api.addr_canonicalize(&api.addr_make("creator1").to_string()).unwrap(); + /// let creator2 = api.addr_canonicalize(&api.addr_make("creator2").to_string()).unwrap(); + /// let salt1 = [0xc0,0xff,0xee]; + /// let salt2 = [0xbe,0xef]; + /// let chs = Checksum::generate(&[1]); + /// + /// let addr11 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator1, &salt1).unwrap(); + /// let addr12 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator1, &salt2).unwrap(); + /// let addr21 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator2, &salt1).unwrap(); + /// let addr22 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator2, &salt2).unwrap(); + /// + /// assert_ne!(addr11, addr12); + /// assert_ne!(addr11, addr21); + /// assert_ne!(addr11, addr22); + /// assert_ne!(addr12, addr21); + /// assert_ne!(addr12, addr22); + /// assert_ne!(addr21, addr22); /// ``` fn predictable_contract_address( &self, - _api: &dyn Api, + api: &dyn Api, _storage: &mut dyn Storage, _code_id: u64, _instance_id: u64, - _checksum: &[u8], - _creator: &CanonicalAddr, + checksum: &[u8], + creator: &CanonicalAddr, salt: &[u8], ) -> AnyResult { - Ok(Addr::unchecked(format!( - "contract{}", - HexBinary::from(salt).to_hex() - ))) + let canonical_addr = instantiate2_address(checksum, creator, salt)?; + Ok(api.addr_humanize(&canonical_addr)?) } } +/// Returns non-predictable contract address. +/// +/// Address is generated using the same algorithm as [`BuildContractAddressClassic`] +/// implementation in `wasmd`. +/// +/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41 +fn instantiate_address(code_id: u64, instance_id: u64) -> CanonicalAddr { + let mut key = Vec::::new(); + key.extend_from_slice(b"wasm\0"); + key.extend_from_slice(&code_id.to_be_bytes()); + key.extend_from_slice(&instance_id.to_be_bytes()); + let module = Sha256::digest("module".as_bytes()); + Sha256::new() + .chain(module) + .chain(key) + .finalize() + .to_vec() + .into() +} + /// Default contract address generator used in [WasmKeeper](crate::WasmKeeper). pub struct SimpleAddressGenerator; diff --git a/src/api.rs b/src/api.rs new file mode 100644 index 00000000..bd3fa9ed --- /dev/null +++ b/src/api.rs @@ -0,0 +1,119 @@ +use bech32::primitives::decode::CheckedHrpstring; +use bech32::{encode, Bech32, Bech32m, Hrp}; +use cosmwasm_std::testing::MockApi; +use cosmwasm_std::{ + Addr, Api, CanonicalAddr, RecoverPubkeyError, StdError, StdResult, VerificationError, +}; +use sha2::{Digest, Sha256}; + +pub struct MockApiBech { + api: MockApi, + prefix: String, + _phantom_data: std::marker::PhantomData, +} + +impl MockApiBech { + /// Returns `Api` implementation that uses specified prefix + /// to generate addresses in `Bech32` or `Bech32m` format. + pub fn new(prefix: &str) -> Self { + Self { + api: MockApi::default(), + prefix: prefix.to_string(), + _phantom_data: std::marker::PhantomData, + } + } +} + +impl Api for MockApiBech { + fn addr_validate(&self, input: &str) -> StdResult { + self.addr_humanize(&self.addr_canonicalize(input)?) + } + + fn addr_canonicalize(&self, input: &str) -> StdResult { + if let Ok(s) = CheckedHrpstring::new::(input) { + if s.hrp().to_string() == self.prefix { + return Ok(s.byte_iter().collect::>().into()); + } + } + Err(StdError::generic_err("Invalid input")) + } + + fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { + let hrp = Hrp::parse(&self.prefix).map_err(|e| StdError::generic_err(e.to_string()))?; + if let Ok(encoded) = encode::(hrp, canonical.as_slice()) { + Ok(Addr::unchecked(encoded)) + } else { + Err(StdError::generic_err("Invalid canonical address")) + } + } + + fn secp256k1_verify( + &self, + message_hash: &[u8], + signature: &[u8], + public_key: &[u8], + ) -> Result { + self.api + .secp256k1_verify(message_hash, signature, public_key) + } + + fn secp256k1_recover_pubkey( + &self, + message_hash: &[u8], + signature: &[u8], + recovery_param: u8, + ) -> Result, RecoverPubkeyError> { + self.api + .secp256k1_recover_pubkey(message_hash, signature, recovery_param) + } + + fn ed25519_verify( + &self, + message: &[u8], + signature: &[u8], + public_key: &[u8], + ) -> Result { + self.api.ed25519_verify(message, signature, public_key) + } + + fn ed25519_batch_verify( + &self, + messages: &[&[u8]], + signatures: &[&[u8]], + public_keys: &[&[u8]], + ) -> Result { + self.api + .ed25519_batch_verify(messages, signatures, public_keys) + } + + fn debug(&self, message: &str) { + self.api.debug(message) + } +} + +impl MockApiBech { + /// Returns an address in `Bech32` or `Bech32m` format, built from provided input string. + /// + /// # Panics + /// + /// This function panics when generating a valid address in `Bech32` or `Bech32m` + /// format is not possible, especially when the prefix is too long or empty. + pub fn addr_make(&self, input: &str) -> Addr { + match Hrp::parse(&self.prefix) { + Ok(hrp) => Addr::unchecked(encode::(hrp, Sha256::digest(input).as_slice()).unwrap()), + Err(reason) => panic!("Generating address failed with reason: {}", reason), + } + } +} + +/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32] format +/// for humanizing canonical addresses. +/// +/// [Bech32]: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki +pub type MockApiBech32 = MockApiBech; + +/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32m] format +/// for humanizing canonical addresses. +/// +/// [Bech32m]: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki +pub type MockApiBech32m = MockApiBech; diff --git a/src/app.rs b/src/app.rs index 4d10958e..9e32bba4 100644 --- a/src/app.rs +++ b/src/app.rs @@ -10,29 +10,34 @@ use crate::executor::{AppResponse, Executor}; use crate::gov::Gov; use crate::ibc::Ibc; use crate::module::{FailingModule, Module}; +use crate::prefixed_storage::{ + prefixed, prefixed_multilevel, prefixed_multilevel_read, prefixed_read, +}; use crate::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking, StakingSudo}; use crate::transactions::transactional; use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; -use crate::{AppBuilder, Contract, GovFailingModule, IbcFailingModule}; +use crate::{AppBuilder, Contract, GovFailingModule, IbcFailingModule, Stargate, StargateFailing}; use cosmwasm_std::testing::{MockApi, MockStorage}; use cosmwasm_std::{ from_json, to_json_binary, Addr, Api, Binary, BlockInfo, ContractResult, CosmosMsg, CustomQuery, Empty, Querier, QuerierResult, QuerierWrapper, QueryRequest, Record, Storage, SystemError, SystemResult, }; -use schemars::JsonSchema; use serde::{de::DeserializeOwned, Serialize}; use std::fmt::Debug; use std::marker::PhantomData; const ADDRESSES: Item> = Item::new("addresses"); +/// Advances the blockchain environment to the next block in tests, enabling developers to simulate +/// time-dependent contract behaviors and block-related triggers efficiently. pub fn next_block(block: &mut BlockInfo) { block.time = block.time.plus_seconds(5); block.height += 1; } -/// Type alias for default build `App` to make its storing simpler in typical scenario +/// A type alias for the default-built App. It simplifies storage and handling in typical scenarios, +/// streamlining the use of the App structure in standard test setups. pub type BasicApp = App< BankKeeper, MockApi, @@ -43,11 +48,12 @@ pub type BasicApp = App< DistributionKeeper, IbcFailingModule, GovFailingModule, + StargateFailing, >; -/// 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. +/// # Blockchain application simulator +/// +/// This structure is the main component of the real-life blockchain simulator. #[derive(Clone)] pub struct App< Bank = BankKeeper, @@ -59,17 +65,27 @@ pub struct App< Distr = DistributionKeeper, Ibc = IbcFailingModule, Gov = GovFailingModule, + Stargate = StargateFailing, > { - pub(crate) router: Router, + pub(crate) router: Router, pub(crate) api: Api, pub(crate) storage: Storage, pub(crate) block: BlockInfo, pub(crate) remote: RemoteChannel, } +/// No-op application initialization function. +pub fn no_init( + router: &mut Router, + api: &dyn Api, + storage: &mut dyn Storage, +) { + let _ = (router, api, storage); +} + impl BasicApp { /// Creates new default `App` implementation working with Empty custom messages. - pub fn new(remote: RemoteChannel, init_fn: F) -> AnyResult + pub fn new(remote: RemoteChannel, init_fn: F) -> Self where F: FnOnce( &mut Router< @@ -80,6 +96,7 @@ impl BasicApp { DistributionKeeper, IbcFailingModule, GovFailingModule, + StargateFailing, >, &dyn Api, &mut dyn Storage, @@ -90,11 +107,8 @@ impl BasicApp { } /// 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( - remote: RemoteChannel, - init_fn: F, -) -> AnyResult> +/// Outside the `App` implementation to make type elision better. +pub fn custom_app(remote: RemoteChannel, init_fn: F) -> BasicApp where ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: Debug + CustomQuery + DeserializeOwned + 'static, @@ -107,6 +121,7 @@ where DistributionKeeper, IbcFailingModule, GovFailingModule, + StargateFailing, >, &dyn Api, &mut dyn Storage, @@ -115,10 +130,10 @@ where AppBuilder::new_custom().with_remote(remote).build(init_fn) } -impl Querier - for App +impl Querier + for App where - CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, @@ -129,6 +144,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { self.router @@ -137,10 +153,11 @@ where } } -impl Executor - for App +impl + Executor + for App where - CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, @@ -151,6 +168,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])?; @@ -159,8 +177,8 @@ where } } -impl - App +impl + App where WasmT: Wasm, BankT: Bank, @@ -171,14 +189,16 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, - CustomT::QueryT: CustomQuery, + StargateT: Stargate, { /// Returns a shared reference to application's router. - pub fn router(&self) -> &Router { + pub fn router( + &self, + ) -> &Router { &self.router } - /// Returns a shared reference to application's api. + /// Returns a shared reference to application's API. pub fn api(&self) -> &ApiT { &self.api } @@ -193,10 +213,11 @@ where &mut self.storage } + /// Initializes modules. pub fn init_modules(&mut self, init_fn: F) -> T where F: FnOnce( - &mut Router, + &mut Router, &dyn Api, &mut dyn Storage, ) -> T, @@ -204,10 +225,11 @@ where init_fn(&mut self.router, &self.api, &mut self.storage) } + /// Queries a module. pub fn read_module(&self, query_fn: F) -> T where F: FnOnce( - &Router, + &Router, &dyn Api, &dyn Storage, ) -> T, @@ -218,8 +240,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 +252,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, { @@ -247,11 +270,9 @@ where /// 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 { - self.init_modules(|router, _, _| { - router - .wasm - .store_code(Addr::unchecked("code-creator"), code) - }) + self.router + .wasm + .store_code(MockApi::default().addr_make("creator"), code) } /// Registers contract code (like [store_code](Self::store_code)), @@ -267,24 +288,128 @@ where creator: Addr, code: Box>, ) -> u64 { - self.init_modules(|router, _, _| router.wasm.store_code(creator, code)) + self.router.wasm.store_code(creator, code) + } + + /// Registers contract code (like [store_code_with_creator](Self::store_code_with_creator)), + /// but takes the code identifier as an additional argument. + pub fn store_code_with_id( + &mut self, + creator: Addr, + code_id: u64, + code: Box>, + ) -> AnyResult { + self.router.wasm.store_code_with_id(creator, code_id, code) + } + + /// Duplicates the contract code identified by `code_id` and returns + /// the identifier of the newly created copy of the contract code. + /// + /// # Examples + /// + /// ``` + /// use cosmwasm_std::Addr; + /// use cw_multi_test::App; + /// + /// // contract implementation + /// mod echo { + /// // contract entry points not shown here + /// # use std::todo; + /// # use cosmwasm_std::{Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError, SubMsg, WasmMsg}; + /// # use serde::{Deserialize, Serialize}; + /// # use cw_multi_test::{Contract, ContractWrapper}; + /// # + /// # fn instantiate(_: DepsMut, _: Env, _: MessageInfo, _: Empty) -> Result { + /// # todo!() + /// # } + /// # + /// # fn execute(_: DepsMut, _: Env, _info: MessageInfo, msg: WasmMsg) -> Result { + /// # todo!() + /// # } + /// # + /// # fn query(_deps: Deps, _env: Env, _msg: Empty) -> Result { + /// # todo!() + /// # } + /// # + /// pub fn contract() -> Box> { + /// // should return the contract + /// # Box::new(ContractWrapper::new(execute, instantiate, query)) + /// } + /// } + /// + /// let mut app = App::default(); + /// + /// // store a new contract, save the code id + /// let code_id = app.store_code(echo::contract()); + /// + /// // duplicate the existing contract, duplicated contract has different code id + /// assert_ne!(code_id, app.duplicate_code(code_id).unwrap()); + /// + /// // zero is an invalid identifier for contract code, returns an error + /// assert_eq!("code id: invalid", app.duplicate_code(0).unwrap_err().to_string()); + /// + /// // there is no contract code with identifier 100 stored yet, returns an error + /// assert_eq!("code id 100: no such code", app.duplicate_code(100).unwrap_err().to_string()); + /// ``` + pub fn duplicate_code(&mut self, code_id: u64) -> AnyResult { + self.router.wasm.duplicate_code(code_id) } /// Returns `ContractData` for the contract with specified address. pub fn contract_data(&self, address: &Addr) -> AnyResult { - self.read_module(|router, _, storage| router.wasm.contract_data(storage, address)) + self.router.wasm.contract_data(&self.storage, address) } /// Returns a raw state dump of all key-values held by a contract with specified address. pub fn dump_wasm_raw(&self, address: &Addr) -> Vec { - self.read_module(|router, _, storage| router.wasm.dump_wasm_raw(storage, address)) + self.router.wasm.dump_wasm_raw(&self.storage, address) + } + + /// Returns **read-only** storage for a contract with specified address. + pub fn contract_storage<'a>(&'a self, contract_addr: &Addr) -> Box { + self.router + .wasm + .contract_storage(&self.storage, contract_addr) + } + + /// Returns **read-write** storage for a contract with specified address. + pub fn contract_storage_mut<'a>(&'a mut self, contract_addr: &Addr) -> Box { + self.router + .wasm + .contract_storage_mut(&mut self.storage, contract_addr) + } + + /// Returns **read-only** prefixed storage with specified namespace. + pub fn prefixed_storage<'a>(&'a self, namespace: &[u8]) -> Box { + Box::new(prefixed_read(&self.storage, namespace)) + } + + /// Returns **mutable** prefixed storage with specified namespace. + pub fn prefixed_storage_mut<'a>(&'a mut self, namespace: &[u8]) -> Box { + Box::new(prefixed(&mut self.storage, namespace)) + } + + /// Returns **read-only** prefixed, multilevel storage with specified namespaces. + pub fn prefixed_multilevel_storage<'a>( + &'a self, + namespaces: &[&[u8]], + ) -> Box { + Box::new(prefixed_multilevel_read(&self.storage, namespaces)) + } + + /// Returns **mutable** prefixed, multilevel storage with specified namespaces. + pub fn prefixed_multilevel_storage_mut<'a>( + &'a mut self, + namespaces: &[&[u8]], + ) -> Box { + Box::new(prefixed_multilevel(&mut self.storage, namespaces)) } } -impl - App +impl + App where - CustomT::ExecT: Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, @@ -295,25 +420,27 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { + /// Sets the initial block properties. pub fn set_block(&mut self, block: BlockInfo) { + self.block = block; self.router .staking .process_queue(&self.api, &mut self.storage, &self.router, &self.block) .unwrap(); - self.block = block; } - // this let's use use "next block" steps that add eg. one height and 5 seconds + /// Updates the current block applying the specified closure, usually [next_block]. pub fn update_block(&mut self, action: F) { + action(&mut self.block); self.router .staking .process_queue(&self.api, &mut self.storage, &self.router, &self.block) .unwrap(); - action(&mut self.block); } - /// Returns a copy of the current block_info + /// Returns a copy of the current block info. pub fn block_info(&self) -> BlockInfo { self.block.clone() } @@ -335,7 +462,7 @@ where } /// Simple helper so we get access to all the QuerierWrapper helpers, - /// eg. wrap().query_wasm_smart, query_all_balances, ... + /// e.g. wrap().query_wasm_smart, query_all_balances, ... pub fn wrap(&self) -> QuerierWrapper { QuerierWrapper::new(self) } @@ -382,7 +509,10 @@ where contract_addr: U, msg: &T, ) -> AnyResult { - let msg = to_json_binary(msg)?; + let msg = WasmSudo { + contract_addr: contract_addr.into(), + message: to_json_binary(msg)?, + }; let Self { block, @@ -393,9 +523,7 @@ where } = self; transactional(&mut *storage, |write_cache, _| { - router - .wasm - .sudo(&*api, contract_addr.into(), write_cache, router, block, msg) + router.wasm.sudo(&*api, write_cache, router, block, msg) }) } @@ -419,25 +547,32 @@ where }) } } - +/// The Router plays a critical role in managing and directing +/// transactions within the Cosmos blockchain. #[derive(Clone)] -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 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 + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, CustomT: Module, WasmT: Wasm, @@ -446,7 +581,9 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { + /// Returns a querier populated with the instance of this [Router]. pub fn querier<'a>( &'a self, api: &'a dyn Api, @@ -465,9 +602,13 @@ where /// We use it to allow calling into modules from another module in sudo mode. /// Things like gov proposals belong here. pub enum SudoMsg { + /// Bank privileged actions. Bank(BankSudo), + /// Custom privileged actions. Custom(Empty), + /// Staking privileged actions. Staking(StakingSudo), + /// Wasm privileged actions. Wasm(WasmSudo), } @@ -488,11 +629,18 @@ impl From for SudoMsg { SudoMsg::Staking(staking) } } - +/// A trait representing the Cosmos based chain's router. +/// +/// This trait is designed for routing messages within the Cosmos ecosystem. +/// It is key to ensure that transactions and contract calls are directed to the +/// correct destinations during testing, simulating real-world blockchain operations. pub trait CosmosRouter { - type ExecC; + /// Type of the executed custom message. + type ExecC: CustomMsg; + /// Type of the query custom message. type QueryC: CustomQuery; + /// Executes messages. fn execute( &self, api: &dyn Api, @@ -502,6 +650,7 @@ pub trait CosmosRouter { msg: CosmosMsg, ) -> AnyResult; + /// Evaluates queries. fn query( &self, api: &dyn Api, @@ -510,6 +659,7 @@ pub trait CosmosRouter { request: QueryRequest, ) -> AnyResult; + /// Evaluates privileged actions. fn sudo( &self, api: &dyn Api, @@ -521,10 +671,10 @@ pub trait CosmosRouter { fn get_querier_storage(&self, storage: &dyn Storage) -> AnyResult; } -impl CosmosRouter - for Router +impl CosmosRouter + for Router where - CustomT::ExecT: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, CustomT: Module, WasmT: Wasm, @@ -533,6 +683,7 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, { type ExecC = CustomT::ExecT; type QueryC = CustomT::QueryT; @@ -555,11 +706,19 @@ 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), + #[allow(deprecated)] + CosmosMsg::Stargate { type_url, value } => self + .stargate + .execute_stargate(api, storage, self, block, sender, type_url, value), + #[cfg(feature = "cosmwasm_2_0")] + CosmosMsg::Any(msg) => self + .stargate + .execute_any(api, storage, self, block, sender, msg), _ => bail!("Cannot execute {:?}", msg), } } - /// this is used by `RouterQuerier` to actual implement the `Querier` interface. + /// 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 fn query( @@ -576,6 +735,12 @@ 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), + #[allow(deprecated)] + QueryRequest::Stargate { path, data } => self + .stargate + .query_stargate(api, storage, &querier, block, path, data), + #[cfg(feature = "cosmwasm_2_0")] + QueryRequest::Grpc(req) => self.stargate.query_grpc(api, storage, &querier, block, req), _ => unimplemented!(), } } @@ -588,10 +753,7 @@ where msg: SudoMsg, ) -> AnyResult { match msg { - SudoMsg::Wasm(msg) => { - self.wasm - .sudo(api, msg.contract_addr, storage, self, block, msg.msg) - } + SudoMsg::Wasm(msg) => self.wasm.sudo(api, storage, self, block, msg), SudoMsg::Bank(msg) => self.bank.sudo(api, storage, self, block, msg), SudoMsg::Staking(msg) => self.staking.sudo(api, storage, self, block, msg), SudoMsg::Custom(_) => unimplemented!(), @@ -625,6 +787,7 @@ impl MockRouter { impl CosmosRouter for MockRouter where + ExecC: CustomMsg, QueryC: CustomQuery, { type ExecC = ExecC; @@ -691,7 +854,7 @@ impl<'a, ExecC, QueryC> RouterQuerier<'a, ExecC, QueryC> { impl<'a, ExecC, QueryC> Querier for RouterQuerier<'a, ExecC, QueryC> where - ExecC: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { diff --git a/src/app_builder.rs b/src/app_builder.rs index ad747509..73339430 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -1,11 +1,11 @@ -//! Implementation of the builder for [App]. +//! AppBuilder helps you set up your test blockchain environment step by step [App]. use crate::wasm_emulation::channel::RemoteChannel; use crate::{ App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingModule, Gov, GovFailingModule, - Ibc, IbcFailingModule, Module, Router, StakeKeeper, Staking, Wasm, WasmKeeper, + Ibc, IbcFailingModule, Module, Router, StakeKeeper, Staking, Stargate, StargateFailing, Wasm, + WasmKeeper, }; -use anyhow::Result as AnyResult; use cosmwasm_std::testing::{mock_env, MockApi, MockStorage}; use cosmwasm_std::{Api, BlockInfo, CustomMsg, CustomQuery, Empty, Storage}; use serde::de::DeserializeOwned; @@ -17,15 +17,18 @@ use std::fmt::Debug; /// /// ``` /// # use cosmwasm_std::Empty; -/// # use cw_multi_test::{BasicAppBuilder, FailingModule, Module}; +/// # use cw_multi_test::{BasicAppBuilder, FailingModule, Module, no_init}; /// # type MyHandler = FailingModule; /// # type MyExecC = Empty; /// # type MyQueryC = Empty; /// /// let mut app = BasicAppBuilder::::new_custom() /// .with_custom(MyHandler::default()) -/// .build(|_, _, _| {}); +/// .build(no_init); /// ``` +/// This type alias is crucial for constructing a custom app with specific modules. +/// It provides a streamlined approach to building and configuring an App tailored to +/// particular testing needs or scenarios. pub type BasicAppBuilder = AppBuilder< BankKeeper, MockApi, @@ -36,11 +39,12 @@ pub type BasicAppBuilder = AppBuilder< DistributionKeeper, IbcFailingModule, GovFailingModule, + StargateFailing, >; /// 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, @@ -52,6 +56,7 @@ pub struct AppBuilder, + stargate: Stargate, } impl Default @@ -65,6 +70,7 @@ impl Default DistributionKeeper, IbcFailingModule, GovFailingModule, + StargateFailing, > { fn default() -> Self { @@ -83,6 +89,7 @@ impl DistributionKeeper, IbcFailingModule, GovFailingModule, + StargateFailing, > { /// Creates builder with default components working with empty exec and query messages. @@ -93,11 +100,12 @@ impl storage: MockStorage::new(), bank: BankKeeper::new(), wasm: WasmKeeper::new(), - custom: FailingModule::new("custom"), + custom: FailingModule::new(), staking: StakeKeeper::new(), distribution: DistributionKeeper::new(), - ibc: IbcFailingModule::new("ibc"), - gov: GovFailingModule::new("gov"), + ibc: IbcFailingModule::new(), + gov: GovFailingModule::new(), + stargate: StargateFailing, remote: None, } } @@ -114,6 +122,7 @@ impl DistributionKeeper, IbcFailingModule, GovFailingModule, + StargateFailing, > where ExecC: CustomMsg + DeserializeOwned + 'static, @@ -128,18 +137,19 @@ where storage: MockStorage::new(), bank: BankKeeper::new(), wasm: WasmKeeper::new(), - custom: FailingModule::new("custom"), + custom: FailingModule::new(), staking: StakeKeeper::new(), distribution: DistributionKeeper::new(), - ibc: IbcFailingModule::new("ibc"), - gov: GovFailingModule::new("gov"), + ibc: IbcFailingModule::new(), + gov: GovFailingModule::new(), + stargate: StargateFailing, remote: None, } } } -impl - AppBuilder +impl + AppBuilder where CustomT: Module, WasmT: Wasm, @@ -153,7 +163,8 @@ where pub fn with_wasm>( self, wasm: NewWasm, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { bank, api, @@ -165,6 +176,7 @@ where ibc, gov, remote, + stargate, .. } = self; @@ -180,6 +192,7 @@ where ibc, gov, remote, + stargate, } } @@ -187,7 +200,8 @@ where pub fn with_bank( self, bank: NewBank, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -199,6 +213,7 @@ where ibc, gov, remote, + stargate, .. } = self; @@ -213,6 +228,7 @@ where distribution, ibc, gov, + stargate, remote, } } @@ -221,7 +237,8 @@ where pub fn with_api( self, api: NewApi, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, bank, @@ -232,6 +249,7 @@ where distribution, ibc, gov, + stargate, remote, .. } = self; @@ -247,6 +265,7 @@ where distribution, ibc, gov, + stargate, remote, } } @@ -255,7 +274,8 @@ where pub fn with_storage( self, storage: NewStorage, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -266,6 +286,7 @@ where distribution, ibc, gov, + stargate, remote, .. } = self; @@ -281,11 +302,12 @@ where distribution, ibc, gov, + stargate, remote, } } - /// Overwrites the default custom messages handler. + /// Overwrites the default handler for custom messages. /// /// At this point it is needed that new custom implements some `Module` trait, but it doesn't need /// to be bound to ExecC or QueryC yet - as those may change. The cross-components validation is @@ -293,7 +315,8 @@ where pub fn with_custom( self, custom: NewCustom, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, bank, @@ -304,6 +327,7 @@ where distribution, ibc, gov, + stargate, remote, .. } = self; @@ -319,6 +343,7 @@ where distribution, ibc, gov, + stargate, remote, } } @@ -327,7 +352,8 @@ where pub fn with_staking( self, staking: NewStaking, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -338,6 +364,7 @@ where distribution, ibc, gov, + stargate, remote, .. } = self; @@ -353,6 +380,7 @@ where distribution, ibc, gov, + stargate, remote, } } @@ -361,8 +389,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, @@ -373,6 +411,7 @@ where bank, ibc, gov, + stargate, remote, .. } = self; @@ -388,6 +427,7 @@ where distribution, ibc, gov, + stargate, remote, } } @@ -402,7 +442,8 @@ where pub fn with_ibc( self, ibc: NewIbc, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -414,6 +455,7 @@ where distribution, gov, remote, + stargate, .. } = self; @@ -425,6 +467,7 @@ where wasm, custom, staking, + stargate, distribution, ibc, gov, @@ -436,7 +479,8 @@ where pub fn with_gov( self, gov: NewGov, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -448,6 +492,7 @@ where distribution, ibc, remote, + stargate, .. } = self; @@ -462,6 +507,7 @@ where distribution, ibc, gov, + stargate, remote, } } @@ -470,7 +516,8 @@ where pub fn with_remote( self, remote: RemoteChannel, - ) -> AppBuilder { + ) -> AppBuilder + { let AppBuilder { wasm, api, @@ -482,6 +529,7 @@ where distribution, ibc, gov, + stargate, .. } = self; @@ -495,8 +543,46 @@ where staking, distribution, ibc, + gov, + stargate, remote: Some(remote), + } + } + + /// 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, + remote, + .. + } = self; + + AppBuilder { + api, + block, + storage, + bank, + wasm, + custom, + staking, + distribution, + ibc, + gov, + stargate, + remote, } } @@ -513,7 +599,7 @@ where pub fn build( self, init_fn: F, - ) -> AnyResult> + ) -> App where BankT: Bank, ApiT: Api, @@ -524,8 +610,9 @@ where DistrT: Distribution, IbcT: Ibc, GovT: Gov, + StargateT: Stargate, F: FnOnce( - &mut Router, + &mut Router, &dyn Api, &mut dyn Storage, ), @@ -538,6 +625,7 @@ where distribution: self.distribution, ibc: self.ibc, gov: self.gov, + stargate: self.stargate, }; let mut app = App { @@ -545,11 +633,11 @@ where api: self.api, block: self.block, storage: self.storage, - remote: self.remote.ok_or(anyhow::anyhow!( - "Remote has to be defined to use clone-testing" - ))?, + remote: self + .remote + .expect("Remote has to be defined to use clone-testing"), }; app.init_modules(init_fn); - Ok(app) + app } } diff --git a/src/bank.rs b/src/bank.rs index ca08475f..213c7912 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -9,39 +9,59 @@ use crate::wasm_emulation::input::BankStorage; use crate::wasm_emulation::query::AllBankQuerier; use cosmwasm_std::{ coin, to_json_binary, Addr, AllBalanceResponse, Api, BalanceResponse, BankMsg, BankQuery, - Binary, BlockInfo, Coin, Event, Order, Querier, Storage, + Binary, BlockInfo, Coin, DenomMetadata, Event, Order, Querier, Storage, }; -use cosmwasm_std::{StdResult, SupplyResponse, Uint128}; +use cosmwasm_std::{StdResult, Uint128}; use cw_storage_plus::Map; use cw_utils::NativeBalance; use itertools::Itertools; use schemars::JsonSchema; -pub(crate) const BALANCES: Map<&Addr, NativeBalance> = Map::new("balances"); +/// Collection of bank balances. +const BALANCES: Map<&Addr, NativeBalance> = Map::new("balances"); -pub const NAMESPACE_BANK: &[u8] = b"bank"; +/// Collection of metadata for denomination. +const DENOM_METADATA: Map = Map::new("metadata"); -#[derive(Clone, std::fmt::Debug, PartialEq, Eq, JsonSchema)] +/// Default storage namespace for bank module. +const NAMESPACE_BANK: &[u8] = b"bank"; + +/// A message representing privileged actions in bank module. +#[derive(Clone, Debug, PartialEq, Eq, JsonSchema)] pub enum BankSudo { + /// Minting privileged action. Mint { + /// Destination address the tokens will be minted for. to_address: String, + /// Amount of the minted tokens. amount: Vec, }, } +/// This trait defines the interface for simulating banking operations. +/// +/// In the test environment, it is essential for testing financial transactions, +/// like transfers and balance checks, within your smart contracts. +/// This trait implements all of these functionalities. pub trait Bank: Module + AllBankQuerier { } +/// A structure representing a default bank keeper. +/// +/// Manages financial interactions in CosmWasm tests, such as simulating token transactions +/// and account balances. This is particularly important for contracts that deal with financial +/// operations in the Cosmos ecosystem. #[derive(Default)] pub struct BankKeeper { remote: Option, } impl BankKeeper { + /// Creates a new instance of a bank keeper with default settings. pub fn new() -> Self { - BankKeeper::default() + Self::default() } pub fn with_remote(mut self, remote: RemoteChannel) -> Self { @@ -49,7 +69,7 @@ impl BankKeeper { self } - // this is an "admin" function to let us adjust bank accounts in genesis + /// Administration function for adjusting bank accounts in genesis. pub fn init_balance( &self, storage: &mut dyn Storage, @@ -60,7 +80,7 @@ impl BankKeeper { self.set_balance(&mut bank_storage, account, amount) } - // this is an "admin" function to let us adjust bank accounts + /// Administration function for adjusting bank accounts. fn set_balance( &self, bank_storage: &mut dyn Storage, @@ -74,6 +94,18 @@ impl BankKeeper { .map_err(Into::into) } + /// Administration function for adjusting denomination metadata. + pub fn set_denom_metadata( + &self, + bank_storage: &mut dyn Storage, + denom: String, + metadata: DenomMetadata, + ) -> AnyResult<()> { + DENOM_METADATA + .save(bank_storage, denom, &metadata) + .map_err(Into::into) + } + fn get_balance(&self, bank_storage: &dyn Storage, account: &Addr) -> AnyResult> { // If there is no balance present, we query it on the distant chain if let Some(val) = BALANCES.may_load(bank_storage, account)? { @@ -136,7 +168,7 @@ impl BankKeeper { self.set_balance(bank_storage, &from_address, a.into_vec()) } - /// Filters out all 0 value coins and returns an error if the resulting Vec is empty + /// Filters out all `0` value coins and returns an error if the resulting vector is empty. fn normalize_amount(&self, amount: Vec) -> AnyResult> { let res: Vec<_> = amount.into_iter().filter(|x| !x.amount.is_zero()).collect(); if res.is_empty() { @@ -191,25 +223,7 @@ impl Module for BankKeeper { self.burn(&mut bank_storage, sender, amount)?; Ok(AppResponse::default()) } - m => bail!("Unsupported bank message: {:?}", m), - } - } - - fn sudo( - &self, - api: &dyn Api, - storage: &mut dyn Storage, - _router: &dyn CosmosRouter, - _block: &BlockInfo, - msg: BankSudo, - ) -> AnyResult { - let mut bank_storage = prefixed(storage, NAMESPACE_BANK); - match msg { - BankSudo::Mint { to_address, amount } => { - let to_address = api.addr_validate(&to_address)?; - self.mint(&mut bank_storage, to_address, amount)?; - Ok(AppResponse::default()) - } + other => unimplemented!("bank message: {other:?}"), } } @@ -227,7 +241,7 @@ impl Module for BankKeeper { let address = api.addr_validate(&address)?; let amount = self.get_balance(&bank_storage, &address)?; let res = AllBalanceResponse::new(amount); - Ok(to_json_binary(&res)?) + to_json_binary(&res).map_err(Into::into) } BankQuery::Balance { address, denom } => { let address = api.addr_validate(&address)?; @@ -237,14 +251,48 @@ impl Module for BankKeeper { .find(|c| c.denom == denom) .unwrap_or_else(|| coin(0, denom)); let res = BalanceResponse::new(amount); - Ok(to_json_binary(&res)?) + to_json_binary(&res).map_err(Into::into) } + #[cfg(feature = "cosmwasm_1_1")] BankQuery::Supply { denom } => { let amount = self.get_supply(&bank_storage, denom)?; let res = SupplyResponse::new(amount); - Ok(to_json_binary(&res)?) + to_json_binary(&res).map_err(Into::into) + } + #[cfg(feature = "cosmwasm_1_3")] + BankQuery::DenomMetadata { denom } => { + let meta = DENOM_METADATA.may_load(storage, denom)?.unwrap_or_default(); + let res = DenomMetadataResponse::new(meta); + to_json_binary(&res).map_err(Into::into) + } + #[cfg(feature = "cosmwasm_1_3")] + BankQuery::AllDenomMetadata { pagination: _ } => { + let mut metadata = vec![]; + for key in DENOM_METADATA.keys(storage, None, None, Order::Ascending) { + metadata.push(DENOM_METADATA.may_load(storage, key?)?.unwrap_or_default()); + } + let res = AllDenomMetadataResponse::new(metadata, None); + to_json_binary(&res).map_err(Into::into) + } + other => unimplemented!("bank query: {other:?}"), + } + } + + fn sudo( + &self, + api: &dyn Api, + storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + msg: BankSudo, + ) -> AnyResult { + let mut bank_storage = prefixed(storage, NAMESPACE_BANK); + match msg { + BankSudo::Mint { to_address, amount } => { + let to_address = api.addr_validate(&to_address)?; + self.mint(&mut bank_storage, to_address, amount)?; + Ok(AppResponse::default()) } - q => bail!("Unsupported bank query: {:?}", q), } } } @@ -258,3 +306,364 @@ impl AllBankQuerier for BankKeeper { Ok(BankStorage { storage: balances? }) } } + +#[cfg(test)] +mod test { + use super::*; + + use crate::app::MockRouter; + use cosmwasm_std::testing::{mock_env, MockApi, MockQuerier, MockStorage}; + use cosmwasm_std::{coins, from_json, Empty, StdError}; + + fn query_balance( + bank: &BankKeeper, + api: &dyn Api, + store: &dyn Storage, + rcpt: &Addr, + ) -> Vec { + let req = BankQuery::AllBalances { + address: rcpt.clone().into(), + }; + let block = mock_env().block; + let querier: MockQuerier = MockQuerier::new(&[]); + + let raw = bank.query(api, store, &querier, &block, req).unwrap(); + let res: AllBalanceResponse = from_json(raw).unwrap(); + res.amount + } + + #[test] + #[cfg(feature = "cosmwasm_1_1")] + fn get_set_balance() { + let api = MockApi::default(); + let mut store = MockStorage::new(); + let block = mock_env().block; + let querier: MockQuerier = MockQuerier::new(&[]); + let router = MockRouter::default(); + + let owner = api.addr_make("owner"); + let rcpt = api.addr_make("receiver"); + let init_funds = vec![coin(100, "eth"), coin(20, "btc")]; + let norm = vec![coin(20, "btc"), coin(100, "eth")]; + + // set money + let bank = BankKeeper::new(); + bank.init_balance(&mut store, &owner, init_funds).unwrap(); + let bank_storage = prefixed_read(&store, NAMESPACE_BANK); + + // get balance work + let rich = bank.get_balance(&bank_storage, &owner).unwrap(); + assert_eq!(rich, norm); + let poor = bank.get_balance(&bank_storage, &rcpt).unwrap(); + assert_eq!(poor, vec![]); + + // proper queries work + let req = BankQuery::AllBalances { + address: owner.clone().into(), + }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: AllBalanceResponse = from_json(raw).unwrap(); + assert_eq!(res.amount, norm); + + let req = BankQuery::AllBalances { + address: rcpt.clone().into(), + }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: AllBalanceResponse = from_json(raw).unwrap(); + assert_eq!(res.amount, vec![]); + + let req = BankQuery::Balance { + address: owner.clone().into(), + denom: "eth".into(), + }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: BalanceResponse = from_json(raw).unwrap(); + assert_eq!(res.amount, coin(100, "eth")); + + let req = BankQuery::Balance { + address: owner.into(), + denom: "foobar".into(), + }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: BalanceResponse = from_json(raw).unwrap(); + assert_eq!(res.amount, coin(0, "foobar")); + + let req = BankQuery::Balance { + address: rcpt.clone().into(), + denom: "eth".into(), + }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: BalanceResponse = from_json(raw).unwrap(); + assert_eq!(res.amount, coin(0, "eth")); + + // Query total supply of a denom + let req = BankQuery::Supply { + denom: "eth".into(), + }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: SupplyResponse = from_json(raw).unwrap(); + assert_eq!(res.amount, coin(100, "eth")); + + // Mint tokens for recipient account + let msg = BankSudo::Mint { + to_address: rcpt.to_string(), + amount: norm.clone(), + }; + bank.sudo(&api, &mut store, &router, &block, msg).unwrap(); + + // Check that the recipient account has the expected balance + let req = BankQuery::AllBalances { + address: rcpt.into(), + }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: AllBalanceResponse = from_json(raw).unwrap(); + assert_eq!(res.amount, norm); + + // Check that the total supply of a denom is updated + let req = BankQuery::Supply { + denom: "eth".into(), + }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: SupplyResponse = from_json(raw).unwrap(); + assert_eq!(res.amount, coin(200, "eth")); + } + + #[test] + fn send_coins() { + let api = MockApi::default(); + let mut store = MockStorage::new(); + let block = mock_env().block; + let router = MockRouter::default(); + + let owner = api.addr_make("owner"); + let rcpt = api.addr_make("receiver"); + let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; + let rcpt_funds = vec![coin(5, "btc")]; + + // set money + let bank = BankKeeper::new(); + bank.init_balance(&mut store, &owner, init_funds).unwrap(); + bank.init_balance(&mut store, &rcpt, rcpt_funds).unwrap(); + + // send both tokens + let to_send = vec![coin(30, "eth"), coin(5, "btc")]; + let msg = BankMsg::Send { + to_address: rcpt.clone().into(), + amount: to_send, + }; + bank.execute( + &api, + &mut store, + &router, + &block, + owner.clone(), + msg.clone(), + ) + .unwrap(); + let rich = query_balance(&bank, &api, &store, &owner); + assert_eq!(vec![coin(15, "btc"), coin(70, "eth")], rich); + let poor = query_balance(&bank, &api, &store, &rcpt); + assert_eq!(vec![coin(10, "btc"), coin(30, "eth")], poor); + + // can send from any account with funds + bank.execute(&api, &mut store, &router, &block, rcpt.clone(), msg) + .unwrap(); + + // cannot send too much + let msg = BankMsg::Send { + to_address: rcpt.into(), + amount: coins(20, "btc"), + }; + bank.execute(&api, &mut store, &router, &block, owner.clone(), msg) + .unwrap_err(); + + let rich = query_balance(&bank, &api, &store, &owner); + assert_eq!(vec![coin(15, "btc"), coin(70, "eth")], rich); + } + + #[test] + fn burn_coins() { + let api = MockApi::default(); + let mut store = MockStorage::new(); + let block = mock_env().block; + let router = MockRouter::default(); + + let owner = api.addr_make("owner"); + let rcpt = api.addr_make("recipient"); + let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; + + // set money + let bank = BankKeeper::new(); + bank.init_balance(&mut store, &owner, init_funds).unwrap(); + + // burn both tokens + let to_burn = vec![coin(30, "eth"), coin(5, "btc")]; + let msg = BankMsg::Burn { amount: to_burn }; + bank.execute(&api, &mut store, &router, &block, owner.clone(), msg) + .unwrap(); + let rich = query_balance(&bank, &api, &store, &owner); + assert_eq!(vec![coin(15, "btc"), coin(70, "eth")], rich); + + // cannot burn too much + let msg = BankMsg::Burn { + amount: coins(20, "btc"), + }; + let err = bank + .execute(&api, &mut store, &router, &block, owner.clone(), msg) + .unwrap_err(); + assert!(matches!(err.downcast().unwrap(), StdError::Overflow { .. })); + + let rich = query_balance(&bank, &api, &store, &owner); + assert_eq!(vec![coin(15, "btc"), coin(70, "eth")], rich); + + // cannot burn from empty account + let msg = BankMsg::Burn { + amount: coins(1, "btc"), + }; + let err = bank + .execute(&api, &mut store, &router, &block, rcpt, msg) + .unwrap_err(); + assert!(matches!(err.downcast().unwrap(), StdError::Overflow { .. })); + } + + #[test] + #[cfg(feature = "cosmwasm_1_3")] + fn set_get_denom_metadata_should_work() { + let api = MockApi::default(); + let mut store = MockStorage::new(); + let block = mock_env().block; + let querier: MockQuerier = MockQuerier::new(&[]); + let bank = BankKeeper::new(); + // set metadata for Ether + let denom_eth_name = "eth".to_string(); + bank.set_denom_metadata( + &mut store, + denom_eth_name.clone(), + DenomMetadata { + name: denom_eth_name.clone(), + ..Default::default() + }, + ) + .unwrap(); + // query metadata + let req = BankQuery::DenomMetadata { + denom: denom_eth_name.clone(), + }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: DenomMetadataResponse = from_json(raw).unwrap(); + assert_eq!(res.metadata.name, denom_eth_name); + } + + #[test] + #[cfg(feature = "cosmwasm_1_3")] + fn set_get_all_denom_metadata_should_work() { + let api = MockApi::default(); + let mut store = MockStorage::new(); + let block = mock_env().block; + let querier: MockQuerier = MockQuerier::new(&[]); + let bank = BankKeeper::new(); + // set metadata for Bitcoin + let denom_btc_name = "btc".to_string(); + bank.set_denom_metadata( + &mut store, + denom_btc_name.clone(), + DenomMetadata { + name: denom_btc_name.clone(), + ..Default::default() + }, + ) + .unwrap(); + // set metadata for Ether + let denom_eth_name = "eth".to_string(); + bank.set_denom_metadata( + &mut store, + denom_eth_name.clone(), + DenomMetadata { + name: denom_eth_name.clone(), + ..Default::default() + }, + ) + .unwrap(); + // query metadata + let req = BankQuery::AllDenomMetadata { pagination: None }; + let raw = bank.query(&api, &store, &querier, &block, req).unwrap(); + let res: AllDenomMetadataResponse = from_json(raw).unwrap(); + assert_eq!(res.metadata[0].name, denom_btc_name); + assert_eq!(res.metadata[1].name, denom_eth_name); + } + + #[test] + fn fail_on_zero_values() { + let api = MockApi::default(); + let mut store = MockStorage::new(); + let block = mock_env().block; + let router = MockRouter::default(); + + let owner = api.addr_make("owner"); + let rcpt = api.addr_make("recipient"); + let init_funds = vec![coin(5000, "atom"), coin(100, "eth")]; + + // set money + let bank = BankKeeper::new(); + bank.init_balance(&mut store, &owner, init_funds).unwrap(); + + // can send normal amounts + let msg = BankMsg::Send { + to_address: rcpt.to_string(), + amount: coins(100, "atom"), + }; + bank.execute(&api, &mut store, &router, &block, owner.clone(), msg) + .unwrap(); + + // fails send on no coins + let msg = BankMsg::Send { + to_address: rcpt.to_string(), + amount: vec![], + }; + bank.execute(&api, &mut store, &router, &block, owner.clone(), msg) + .unwrap_err(); + + // fails send on 0 coins + let msg = BankMsg::Send { + to_address: rcpt.to_string(), + amount: coins(0, "atom"), + }; + bank.execute(&api, &mut store, &router, &block, owner.clone(), msg) + .unwrap_err(); + + // fails burn on no coins + let msg = BankMsg::Burn { amount: vec![] }; + bank.execute(&api, &mut store, &router, &block, owner.clone(), msg) + .unwrap_err(); + + // fails burn on 0 coins + let msg = BankMsg::Burn { + amount: coins(0, "atom"), + }; + bank.execute(&api, &mut store, &router, &block, owner, msg) + .unwrap_err(); + + // can mint via sudo + let msg = BankSudo::Mint { + to_address: rcpt.to_string(), + amount: coins(4321, "atom"), + }; + bank.sudo(&api, &mut store, &router, &block, msg).unwrap(); + + // mint fails with 0 tokens + let msg = BankSudo::Mint { + to_address: rcpt.to_string(), + amount: coins(0, "atom"), + }; + bank.sudo(&api, &mut store, &router, &block, msg) + .unwrap_err(); + + // mint fails with no tokens + let msg = BankSudo::Mint { + to_address: rcpt.to_string(), + amount: vec![], + }; + bank.sudo(&api, &mut store, &router, &block, msg) + .unwrap_err(); + } +} diff --git a/src/contracts.rs b/src/contracts.rs index e6d218ff..ef364be7 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -1,80 +1,49 @@ -use std::{ - error::Error, - fmt::{self, Debug, Display}, -}; - -use schemars::JsonSchema; +//! # Implementation of the contract trait and contract wrapper +use crate::error::{anyhow, bail, AnyError, AnyResult}; +use crate::wasm_emulation::query::mock_querier::ForkState; +use crate::wasm_emulation::query::MockQuerier; +use crate::wasm_emulation::storage::dual_std_storage::DualStorage; +use crate::wasm_emulation::storage::storage_wrappers::{ReadonlyStorageWrapper, StorageWrapper}; use cosmwasm_std::{ - from_json, Binary, Checksum, CustomMsg, CustomQuery, Deps, DepsMut, Empty, Env, MessageInfo, QuerierWrapper, Reply, Response, StdError + from_json, Binary, Checksum, CosmosMsg, CustomMsg, CustomQuery, Deps, DepsMut, Empty, Env, + MessageInfo, QuerierWrapper, Reply, Response, StdError, SubMsg, }; - -use anyhow::Result as AnyResult; use serde::de::DeserializeOwned; +use std::fmt::{Debug, Display}; +use std::ops::Deref; -use crate::wasm_emulation::{ - query::{mock_querier::ForkState, MockQuerier}, - storage::{ - dual_std_storage::DualStorage, - storage_wrappers::{ReadonlyStorageWrapper, StorageWrapper}, - }, -}; -use anyhow::{anyhow, bail}; -/// Interface to call into a [Contract]. -pub trait Contract +/// This trait serves as a primary interface for interacting with contracts. +#[rustfmt::skip] +pub trait Contract where - T: CustomMsg + DeserializeOwned + Clone + std::fmt::Debug + PartialEq + JsonSchema, + C: CustomMsg, Q: CustomQuery + DeserializeOwned, { - fn execute( - &self, - deps: DepsMut, - env: Env, - info: MessageInfo, - msg: Vec, - fork_state: ForkState, - ) -> AnyResult>; + /// Evaluates contract's `execute` entry-point. + fn execute(&self, deps: DepsMut, env: Env, info: MessageInfo, msg: Vec, + fork_state: ForkState,) -> AnyResult>; - fn instantiate( - &self, - deps: DepsMut, - env: Env, - info: MessageInfo, - msg: Vec, - fork_state: ForkState, - ) -> AnyResult>; + /// Evaluates contract's `instantiate` entry-point. + fn instantiate(&self, deps: DepsMut, env: Env, info: MessageInfo, msg: Vec, + fork_state: ForkState,) -> AnyResult>; - fn query( - &self, - deps: Deps, - env: Env, - msg: Vec, - fork_state: ForkState, - ) -> AnyResult; + /// Evaluates contract's `query` entry-point. + fn query(&self, deps: Deps, env: Env, msg: Vec, + fork_state: ForkState,) -> AnyResult; - fn sudo( - &self, - deps: DepsMut, - env: Env, - msg: Vec, - fork_state: ForkState, - ) -> AnyResult>; + /// Evaluates contract's `sudo` entry-point. + fn sudo(&self, deps: DepsMut, env: Env, msg: Vec, + fork_state: ForkState,) -> AnyResult>; - fn reply( - &self, - deps: DepsMut, - env: Env, - msg: Reply, - fork_state: ForkState, - ) -> AnyResult>; + /// Evaluates contract's `reply` entry-point. + fn reply(&self, deps: DepsMut, env: Env, msg: Reply, + fork_state: ForkState,) -> AnyResult>; + + /// Evaluates contract's `migrate` entry-point. + fn migrate(&self, deps: DepsMut, env: Env, msg: Vec, + fork_state: ForkState,) -> AnyResult>; - fn migrate( - &self, - deps: DepsMut, - env: Env, - msg: Vec, - fork_state: ForkState, - ) -> AnyResult>; /// Returns the provided checksum of the contract's Wasm blob. fn checksum(&self) -> Option { @@ -82,20 +51,92 @@ where } } -type ContractFn = - fn(deps: DepsMut, env: Env, info: MessageInfo, msg: T) -> Result, E>; -type PermissionedFn = fn(deps: DepsMut, env: Env, msg: T) -> Result, E>; -type ReplyFn = fn(deps: DepsMut, env: Env, msg: Reply) -> Result, E>; -type QueryFn = fn(deps: Deps, env: Env, msg: T) -> Result; - -type ContractClosure = fn(DepsMut, Env, MessageInfo, T) -> Result, E>; -type PermissionedClosure = fn(DepsMut, Env, T) -> Result, E>; -type ReplyClosure = fn(DepsMut, Env, Reply) -> Result, E>; -type QueryClosure = fn(Deps, Env, T) -> Result; +#[rustfmt::skip] +mod closures { + use super::*; + + // function types + pub type ContractFn = fn(deps: DepsMut, env: Env, info: MessageInfo, msg: T) -> Result, E>; + pub type PermissionedFn = fn(deps: DepsMut, env: Env, msg: T) -> Result, E>; + pub type ReplyFn = fn(deps: DepsMut, env: Env, msg: Reply) -> Result, E>; + pub type QueryFn = fn(deps: Deps, env: Env, msg: T) -> Result; + + // closure types + pub type ContractClosure = Box, Env, MessageInfo, T) -> Result, E>>; + pub type PermissionedClosure = Box, Env, T) -> Result, E>>; + pub type ReplyClosure = Box, Env, Reply) -> Result, E>>; + pub type QueryClosure = Box, Env, T) -> Result>; +} -#[derive(Clone, Copy)] -/// Wraps the exported functions from a contract and provides the normalized format -/// Place T4 and E4 at the end, as we just want default placeholders for most contracts that don't have sudo +use closures::*; + +/// This structure wraps the [Contract] trait implementor +/// and provides generic access to the contract's entry-points. +/// +/// List of generic types used in [ContractWrapper]: +/// - **T1** type of message passed to [execute] entry-point. +/// - **T2** type of message passed to [instantiate] entry-point. +/// - **T3** type of message passed to [query] entry-point. +/// - **T4** type of message passed to [sudo] entry-point. +/// - instead of **~~T5~~**, always the `Reply` type is used in [reply] entry-point. +/// - **T6** type of message passed to [migrate] entry-point. +/// - **E1** type of error returned from [execute] entry-point. +/// - **E2** type of error returned from [instantiate] entry-point. +/// - **E3** type of error returned from [query] entry-point. +/// - **E4** type of error returned from [sudo] entry-point. +/// - **E5** type of error returned from [reply] entry-point. +/// - **E6** type of error returned from [migrate] entry-point. +/// - **C** type of custom message returned from all entry-points except [query]. +/// - **Q** type of custom query in `Querier` passed as 'Deps' or 'DepsMut' to all entry-points. +/// +/// The following table summarizes the purpose of all generic types used in [ContractWrapper]. +/// ```text +/// ┌─────────────┬────────────────┬─────────────────────┬─────────┬─────────┬───────┬───────┐ +/// │ Contract │ Contract │ │ │ │ │ │ +/// │ entry-point │ wrapper │ Closure type │ Message │ Message │ Error │ Query │ +/// │ │ member │ │ IN │ OUT │ OUT │ │ +/// ╞═════════════╪════════════════╪═════════════════════╪═════════╪═════════╪═══════╪═══════╡ +/// │ (1) │ │ │ │ │ │ │ +/// ╞═════════════╪════════════════╪═════════════════════╪═════════╪═════════╪═══════╪═══════╡ +/// │ execute │ execute_fn │ ContractClosure │ T1 │ C │ E1 │ Q │ +/// ├─────────────┼────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ instantiate │ instantiate_fn │ ContractClosure │ T2 │ C │ E2 │ Q │ +/// ├─────────────┼────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ query │ query_fn │ QueryClosure │ T3 │ Binary │ E3 │ Q │ +/// ├─────────────┼────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ sudo │ sudo_fn │ PermissionedClosure │ T4 │ C │ E4 │ Q │ +/// ├─────────────┼────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ reply │ reply_fn │ ReplyClosure │ Reply │ C │ E5 │ Q │ +/// ├─────────────┼────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤ +/// │ migrate │ migrate_fn │ PermissionedClosure │ T6 │ C │ E6 │ Q │ +/// └─────────────┴────────────────┴─────────────────────┴─────────┴─────────┴───────┴───────┘ +/// ``` +/// The general schema depicting which generic type is used in entry points is shown below. +/// Entry point, when called, is provided minimum two arguments: custom query of type **Q** +/// (inside `Deps` or `DepsMut`) and input message of type **T1**, **T2**, **T3**, **T4**, +/// **Reply** or **T6**. As a result, entry point returns custom output message of type +/// Response<**C**> or **Binary** and an error of type **E1**, **E2**, **E3**, **E4**, **E5** +/// or **E6**. +/// +/// ```text +/// entry_point(query, .., message_in) -> Result +/// ┬ ┬ ┬ ┬ +/// Q >──┘ │ │ └──> E1,E2,E3,E4,E5,E6 +/// T1,T2,T3,T4,Reply,T6 >────┘ └─────────────> C,Binary +/// ``` +/// Generic type **C** defines a custom message that is specific for the **whole blockchain**. +/// Similarly, the generic type **Q** defines a custom query that is also specific +/// to the **whole blockchain**. Other generic types are specific to the implemented contract. +/// So all smart contracts used in the same blockchain will have the same types for **C** and **Q**, +/// but each contract may use different type for other generic types. +/// It means that e.g. **T1** in smart contract `A` may differ from **T1** in smart contract `B`. +/// +/// [execute]: Contract::execute +/// [instantiate]: Contract::instantiate +/// [query]: Contract::query +/// [sudo]: Contract::sudo +/// [reply]: Contract::reply +/// [migrate]: Contract::migrate pub struct ContractWrapper< T1, T2, @@ -111,19 +152,19 @@ pub struct ContractWrapper< T6 = Empty, E6 = StdError, > where - T1: DeserializeOwned + Debug, - T2: DeserializeOwned, - T3: DeserializeOwned, - T4: DeserializeOwned, - T6: DeserializeOwned, - E1: Display + Debug + Send + Sync + 'static, - E2: Display + Debug + Send + Sync + 'static, - E3: Display + Debug + Send + Sync + 'static, - E4: Display + Debug + Send + Sync + 'static, - E5: Display + Debug + Send + Sync + 'static, - E6: Display + Debug + Send + Sync + 'static, - C: Clone + fmt::Debug + PartialEq + JsonSchema, - Q: CustomQuery + DeserializeOwned + 'static, + T1: DeserializeOwned, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned, // Type of message passed to `query` entry-point. + T4: DeserializeOwned, // Type of message passed to `sudo` entry-point. + T6: DeserializeOwned, // Type of message passed to `migrate` entry-point. + E1: Display + Debug + Send + Sync, // Type of error returned from `execute` entry-point. + E2: Display + Debug + Send + Sync, // Type of error returned from `instantiate` entry-point. + E3: Display + Debug + Send + Sync, // Type of error returned from `query` entry-point. + E4: Display + Debug + Send + Sync, // Type of error returned from `sudo` entry-point. + E5: Display + Debug + Send + Sync, // Type of error returned from `reply` entry-point. + E6: Display + Debug + Send + Sync, // Type of error returned from `migrate` entry-point. + C: CustomMsg, // Type of custom message returned from all entry-points except `query`. + Q: CustomQuery + DeserializeOwned, // Type of custom query in querier passed as deps/deps_mut to all entry-points. { execute_fn: ContractClosure, instantiate_fn: ContractClosure, @@ -136,24 +177,25 @@ pub struct ContractWrapper< impl ContractWrapper where - T1: DeserializeOwned + Debug + 'static, - T2: DeserializeOwned + 'static, - T3: DeserializeOwned + 'static, - E1: Display + Debug + Send + Sync + 'static, - E2: Display + Debug + Send + Sync + 'static, - E3: Display + Debug + Send + Sync + 'static, - C: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, - Q: CustomQuery + DeserializeOwned + 'static, + T1: DeserializeOwned + 'static, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned + 'static, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned + 'static, // Type of message passed to `query` entry-point. + E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point. + E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point. + E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point. + C: CustomMsg + 'static, // Type of custom message returned from all entry-points except `query`. + Q: CustomQuery + DeserializeOwned + 'static, // Type of custom query in querier passed as deps/deps_mut to all entry-points. { + /// Creates a new contract wrapper with default settings. pub fn new( execute_fn: ContractFn, instantiate_fn: ContractFn, query_fn: QueryFn, ) -> Self { Self { - execute_fn, - instantiate_fn, - query_fn, + execute_fn: Box::new(execute_fn), + instantiate_fn: Box::new(instantiate_fn), + query_fn: Box::new(query_fn), sudo_fn: None, reply_fn: None, migrate_fn: None, @@ -162,23 +204,25 @@ where } } +#[allow(clippy::type_complexity)] impl ContractWrapper where - T1: DeserializeOwned + Debug + 'static, - T2: DeserializeOwned + 'static, - T3: DeserializeOwned + 'static, - T4: DeserializeOwned + 'static, - T6: DeserializeOwned + 'static, - E1: Display + Debug + Send + Sync + 'static, - E2: Display + Debug + Send + Sync + 'static, - E3: Display + Debug + Send + Sync + 'static, - E4: Display + Debug + Send + Sync + 'static, - E5: Display + Debug + Send + Sync + 'static, - E6: Display + Debug + Send + Sync + 'static, - C: Clone + fmt::Debug + PartialEq + JsonSchema + 'static, - Q: CustomQuery + DeserializeOwned + 'static, + T1: DeserializeOwned, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned, // Type of message passed to `query` entry-point. + T4: DeserializeOwned, // Type of message passed to `sudo` entry-point. + T6: DeserializeOwned, // Type of message passed to `migrate` entry-point. + E1: Display + Debug + Send + Sync, // Type of error returned from `execute` entry-point. + E2: Display + Debug + Send + Sync, // Type of error returned from `instantiate` entry-point. + E3: Display + Debug + Send + Sync, // Type of error returned from `query` entry-point. + E4: Display + Debug + Send + Sync, // Type of error returned from `sudo` entry-point. + E5: Display + Debug + Send + Sync, // Type of error returned from `reply` entry-point. + E6: Display + Debug + Send + Sync, // Type of error returned from `migrate` entry-point. + C: CustomMsg + 'static, // Type of custom message returned from all entry-points except `query`. + Q: CustomQuery + DeserializeOwned + 'static, // Type of custom query in querier passed as deps/deps_mut to all entry-points. { + /// Populates [ContractWrapper] with contract's `sudo` entry-point and custom message type. pub fn with_sudo( self, sudo_fn: PermissionedFn, @@ -191,13 +235,14 @@ where execute_fn: self.execute_fn, instantiate_fn: self.instantiate_fn, query_fn: self.query_fn, - sudo_fn: Some(sudo_fn), + sudo_fn: Some(Box::new(sudo_fn)), reply_fn: self.reply_fn, migrate_fn: self.migrate_fn, checksum: None, } } + /// Populates [ContractWrapper] with contract's `reply` entry-point and custom message type. pub fn with_reply( self, reply_fn: ReplyFn, @@ -210,12 +255,13 @@ where instantiate_fn: self.instantiate_fn, query_fn: self.query_fn, sudo_fn: self.sudo_fn, - reply_fn: Some(reply_fn), + reply_fn: Some(Box::new(reply_fn)), migrate_fn: self.migrate_fn, checksum: None, } } + /// Populates [ContractWrapper] with contract's `migrate` entry-point and custom message type. pub fn with_migrate( self, migrate_fn: PermissionedFn, @@ -230,7 +276,7 @@ where query_fn: self.query_fn, sudo_fn: self.sudo_fn, reply_fn: self.reply_fn, - migrate_fn: Some(migrate_fn), + migrate_fn: Some(Box::new(migrate_fn)), checksum: None, } } @@ -244,20 +290,23 @@ where impl Contract for ContractWrapper where - T1: DeserializeOwned + Debug + Clone, - T2: DeserializeOwned + Debug + Clone, - T3: DeserializeOwned + Debug + Clone, - T4: DeserializeOwned, - T6: DeserializeOwned, - E1: Display + Debug + Send + Sync + Error + 'static, - E2: Display + Debug + Send + Sync + Error + 'static, - E3: Display + Debug + Send + Sync + Error + 'static, - E4: Display + Debug + Send + Sync + 'static, - E5: Display + Debug + Send + Sync + 'static, - E6: Display + Debug + Send + Sync + 'static, - C: CustomMsg + DeserializeOwned + Clone + fmt::Debug + PartialEq + JsonSchema, - Q: CustomQuery + DeserializeOwned, + T1: DeserializeOwned, // Type of message passed to `execute` entry-point. + T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point. + T3: DeserializeOwned, // Type of message passed to `query` entry-point. + T4: DeserializeOwned, // Type of message passed to `sudo` entry-point. + T6: DeserializeOwned, // Type of message passed to `migrate` entry-point. + E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point. + E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point. + E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point. + E4: Display + Debug + Send + Sync + 'static, // Type of error returned from `sudo` entry-point. + E5: Display + Debug + Send + Sync + 'static, // Type of error returned from `reply` entry-point. + E6: Display + Debug + Send + Sync + 'static, // Type of error returned from `migrate` entry-point. + C: CustomMsg + DeserializeOwned, // Type of custom message returned from all entry-points except `query`. + Q: CustomQuery + DeserializeOwned, // Type of custom query in querier passed as deps/deps_mut to all entry-points. { + /// Calls [execute] on wrapped [Contract] trait implementor. + /// + /// [execute]: Contract::execute fn execute( &self, deps: DepsMut, @@ -279,9 +328,12 @@ where }; let msg: T1 = from_json(msg)?; - (self.execute_fn)(deps, env, info, msg).map_err(|err| anyhow!(err)) + (self.execute_fn)(deps, env, info, msg).map_err(|err: E1| anyhow!(err)) } + /// Calls [instantiate] on wrapped [Contract] trait implementor. + /// + /// [instantiate]: Contract::instantiate fn instantiate( &self, deps: DepsMut, @@ -302,9 +354,12 @@ where querier: QuerierWrapper::new(&querier), }; let msg: T2 = from_json(msg)?; - (self.instantiate_fn)(deps, env, info, msg).map_err(|err| anyhow!(err)) + (self.instantiate_fn)(deps, env, info, msg).map_err(|err: E2| anyhow!(err)) } + /// Calls [query] on wrapped [Contract] trait implementor. + /// + /// [query]: Contract::query fn query( &self, deps: Deps, @@ -324,10 +379,13 @@ where querier: QuerierWrapper::new(&querier), }; let msg: T3 = from_json(msg)?; - (self.query_fn)(deps, env, msg).map_err(|err| anyhow!(err)) + (self.query_fn)(deps, env, msg).map_err(|err: E3| anyhow!(err)) } - // this returns an error if the contract doesn't implement sudo + /// Calls [sudo] on wrapped [Contract] trait implementor. + /// Returns an error when the contract does not implement [sudo]. + /// + /// [sudo]: Contract::sudo fn sudo( &self, deps: DepsMut, @@ -348,12 +406,15 @@ where }; let msg = from_json(msg)?; match &self.sudo_fn { - Some(sudo) => sudo(deps, env, msg).map_err(|err| anyhow!(err)), - None => bail!("sudo not implemented for contract"), + Some(sudo) => sudo(deps, env, msg).map_err(|err: E4| anyhow!(err)), + None => bail!("sudo is not implemented for contract"), } } - // this returns an error if the contract doesn't implement reply + /// Calls [reply] on wrapped [Contract] trait implementor. + /// Returns an error when the contract does not implement [reply]. + /// + /// [reply]: Contract::reply fn reply( &self, deps: DepsMut, @@ -361,6 +422,7 @@ where reply_data: Reply, fork_state: ForkState, ) -> AnyResult> { + let msg: Reply = reply_data; let querier = MockQuerier::new(fork_state.clone()); let mut storage = DualStorage::new( fork_state.remote, @@ -373,12 +435,15 @@ where querier: QuerierWrapper::new(&querier), }; match &self.reply_fn { - Some(reply) => reply(deps, env, reply_data).map_err(|err| anyhow!(err)), - None => bail!("reply not implemented for contract"), + Some(reply) => reply(deps, env, msg).map_err(|err: E5| anyhow!(err)), + None => bail!("reply is not implemented for contract"), } } - // this returns an error if the contract doesn't implement migrate + /// Calls [migrate] on wrapped [Contract] trait implementor. + /// Returns an error when the contract does not implement [migrate]. + /// + /// [migrate]: Contract::migrate fn migrate( &self, deps: DepsMut, @@ -399,8 +464,8 @@ where }; let msg = from_json(msg)?; match &self.migrate_fn { - Some(migrate) => migrate(deps, env, msg).map_err(|err| anyhow!(err)), - None => bail!("migrate not implemented for contract"), + Some(migrate) => migrate(deps, env, msg).map_err(|err: E6| anyhow!(err)), + None => bail!("migrate is not implemented for contract"), } } diff --git a/src/custom_handler.rs b/src/custom_handler.rs index cb634b59..1ab9dbeb 100644 --- a/src/custom_handler.rs +++ b/src/custom_handler.rs @@ -1,3 +1,5 @@ +//! # Custom message and query handler + use crate::app::CosmosRouter; use crate::error::{bail, AnyResult}; use crate::{AppResponse, Module}; @@ -7,40 +9,46 @@ use std::cell::{Ref, RefCell}; use std::ops::Deref; use std::rc::Rc; -/// Internal state of `CachingCustomHandler` wrapping internal mutability so it is not exposed to -/// user. Those have to be shared internal state, as after mock is passed to app it is not -/// possible to access mock internals which are not exposed by API. +/// A cache for messages and queries processes by the custom module. #[derive(Derivative)] #[derivative(Default(bound = "", new = "true"), Clone(bound = ""))] pub struct CachingCustomHandlerState { + /// Cache for processes custom messages. execs: Rc>>, + /// Cache for processed custom queries. queries: Rc>>, } impl CachingCustomHandlerState { + /// Returns a slice of processed custom messages. pub fn execs(&self) -> impl Deref + '_ { Ref::map(self.execs.borrow(), Vec::as_slice) } + /// Returns a slice of processed custom queries. pub fn queries(&self) -> impl Deref + '_ { Ref::map(self.queries.borrow(), Vec::as_slice) } + /// Clears the cache. pub fn reset(&self) { self.execs.borrow_mut().clear(); self.queries.borrow_mut().clear(); } } -/// Custom handler storing all the messages it received, so they can be later verified. -/// State is thin shared state, so it can be hold after mock is passed to App to read state. +/// Custom handler that stores all received messages and queries. +/// +/// State is thin shared state, so it can be held after mock is passed to [App](crate::App) to read state. #[derive(Clone, Derivative)] #[derivative(Default(bound = "", new = "true"))] pub struct CachingCustomHandler { + /// Cached state. state: CachingCustomHandlerState, } impl CachingCustomHandler { + /// Returns the cached state. pub fn state(&self) -> CachingCustomHandlerState { self.state.clone() } @@ -51,8 +59,7 @@ impl Module for CachingCustomHandler { type QueryT = Query; type SudoT = Empty; - // TODO: how to assert - // where ExecC: Exec, QueryC: Query + // TODO: how to assert like `where ExecC: Exec, QueryC: Query` fn execute( &self, _api: &dyn Api, @@ -66,17 +73,6 @@ impl Module for CachingCustomHandler { Ok(AppResponse::default()) } - fn sudo( - &self, - _api: &dyn Api, - _storage: &mut dyn Storage, - _router: &dyn CosmosRouter, - _block: &BlockInfo, - msg: Self::SudoT, - ) -> AnyResult { - bail!("Unexpected sudo msg {:?}", msg) - } - fn query( &self, _api: &dyn Api, @@ -88,4 +84,15 @@ impl Module for CachingCustomHandler { self.state.queries.borrow_mut().push(request); Ok(Binary::default()) } + + fn sudo( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + msg: Self::SudoT, + ) -> AnyResult { + bail!("Unexpected custom sudo message {:?}", msg) + } } diff --git a/src/error.rs b/src/error.rs index 289a7949..b6c26c8a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,33 +1,54 @@ +//! # Error definitions + pub use anyhow::{anyhow, bail, Context as AnyContext, Error as AnyError, Result as AnyResult}; use cosmwasm_std::{WasmMsg, WasmQuery}; use thiserror::Error; +/// An enumeration of errors reported across the **CosmWasm MultiTest** library. #[derive(Debug, Error, PartialEq, Eq)] pub enum Error { - #[error("Empty attribute key. Value: {value}")] - EmptyAttributeKey { value: String }, + /// Error variant for reporting an empty attribute key. + #[error("Empty attribute key. Value: {0}")] + EmptyAttributeKey(String), - #[error("Empty attribute value. Key: {key}")] - EmptyAttributeValue { key: String }, + /// Error variant for reporting an empty attribute value. + #[deprecated(note = "This error is not reported anymore. Will be removed in next release.")] + #[error("Empty attribute value. Key: {0}")] + EmptyAttributeValue(String), + /// Error variant for reporting a usage of reserved key prefix. #[error("Attribute key starts with reserved prefix _: {0}")] ReservedAttributeKey(String), + /// Error variant for reporting too short event types. #[error("Event type too short: {0}")] EventTypeTooShort(String), + /// Error variant for reporting that unsupported wasm query was encountered during processing. #[error("Unsupported wasm query: {0:?}")] UnsupportedWasmQuery(WasmQuery), + /// Error variant for reporting that unsupported wasm message was encountered during processing. #[error("Unsupported wasm message: {0:?}")] UnsupportedWasmMsg(WasmMsg), + /// Error variant for reporting invalid contract code. #[error("code id: invalid")] InvalidCodeId, + /// Error variant for reporting unregistered contract code. #[error("code id {0}: no such code")] UnregisteredCodeId(u64), + /// Error variant for reporting duplicated contract code identifier. + #[error("duplicated code id {0}")] + DuplicatedCodeId(u64), + + /// Error variant for reporting a situation when no more contract code identifiers are available. + #[error("no more code identifiers available")] + NoMoreCodeIdAvailable, + + /// Error variant for reporting duplicated contract addresses. #[error("Contract with this address already exists: {0}")] DuplicatedContractAddress(String), @@ -36,24 +57,59 @@ pub enum Error { } impl Error { + /// Creates an instance of the [Error](Self) for empty attribute key. pub fn empty_attribute_key(value: impl Into) -> Self { - Self::EmptyAttributeKey { - value: value.into(), - } + Self::EmptyAttributeKey(value.into()) } + #[deprecated(note = "This error is not reported anymore. Will be removed in next release.")] + /// Creates an instance of the [Error](Self) for empty attribute value. pub fn empty_attribute_value(key: impl Into) -> Self { - Self::EmptyAttributeValue { key: key.into() } + #[allow(deprecated)] + Self::EmptyAttributeValue(key.into()) } + /// Creates an instance of the [Error](Self) when reserved attribute key was used. pub fn reserved_attribute_key(key: impl Into) -> Self { Self::ReservedAttributeKey(key.into()) } + /// Creates an instance of the [Error](Self) for too short event types. pub fn event_type_too_short(ty: impl Into) -> Self { Self::EventTypeTooShort(ty.into()) } + /// Creates an instance of the [Error](Self) for unsupported wasm queries. + pub fn unsupported_wasm_query(query: WasmQuery) -> Self { + Self::UnsupportedWasmQuery(query) + } + + /// Creates an instance of the [Error](Self) for unsupported wasm messages. + pub fn unsupported_wasm_message(msg: WasmMsg) -> Self { + Self::UnsupportedWasmMsg(msg) + } + + /// Creates an instance of the [Error](Self) for invalid contract code identifier. + pub fn invalid_code_id() -> Self { + Self::InvalidCodeId + } + + /// Creates an instance of the [Error](Self) for unregistered contract code identifier. + pub fn unregistered_code_id(code_id: u64) -> Self { + Self::UnregisteredCodeId(code_id) + } + + /// Creates an instance of the [Error](Self) for duplicated contract code identifier. + pub fn duplicated_code_id(code_id: u64) -> Self { + Self::DuplicatedCodeId(code_id) + } + + /// Creates an instance of the [Error](Self) for exhausted contract code identifiers. + pub fn no_more_code_id_available() -> Self { + Self::NoMoreCodeIdAvailable + } + + /// Creates an instance of the [Error](Self) for duplicated contract addresses. pub fn duplicated_contract_address(address: impl Into) -> Self { Self::DuplicatedContractAddress(address.into()) } diff --git a/src/executor.rs b/src/executor.rs index 492be9bb..ed2a5fad 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -1,30 +1,35 @@ use crate::error::AnyResult; use cosmwasm_std::{ - to_json_binary, Addr, Attribute, BankMsg, Binary, Coin, CosmosMsg, Event, SubMsgResponse, - WasmMsg, + to_json_binary, Addr, Attribute, BankMsg, Binary, Coin, CosmosMsg, CustomMsg, Event, + SubMsgResponse, WasmMsg, }; use cw_utils::{parse_execute_response_data, parse_instantiate_response_data}; -use schemars::JsonSchema; use serde::Serialize; use std::fmt::Debug; +/// A subset of data returned as a response of a contract entry point, +/// such as `instantiate`, `execute` or `migrate`. #[derive(Default, Clone, Debug)] pub struct AppResponse { + /// Response events. pub events: Vec, + /// Response data. pub data: Option, } impl AppResponse { - // Return all custom attributes returned by the contract in the `idx` event. - // We assert the type is wasm, and skip the contract_address attribute. + /// Returns all custom attributes returned by the contract in the `idx` event. + /// + /// We assert the type is wasm, and skip the contract_address attribute. #[track_caller] pub fn custom_attrs(&self, idx: usize) -> &[Attribute] { assert_eq!(self.events[idx].ty.as_str(), "wasm"); &self.events[idx].attributes[1..] } - /// Check if there is an Event that is a super-set of this. - /// It has the same type, and all compare.attributes are included in it as well. + /// Checks if there is an Event that is a super-set of this. + /// + /// It has the same type, and all compared attributes are included in it as well. /// You don't need to specify them all. pub fn has_event(&self, expected: &Event) -> bool { self.events.iter().any(|ev| { @@ -36,7 +41,7 @@ impl AppResponse { }) } - /// Like has_event but panics if no match + /// Like [has_event](Self::has_event) but panics if there is no match. #[track_caller] pub fn assert_event(&self, expected: &Event) { assert!( @@ -48,7 +53,7 @@ impl AppResponse { } } -/// They have the same shape, SubMsgExecutionResponse is what is returned in reply. +/// They have the same shape, SubMsgResponse is what is returned in reply. /// This is just to make some test cases easier. impl From for AppResponse { fn from(reply: SubMsgResponse) -> Self { @@ -59,14 +64,19 @@ impl From for AppResponse { } } } - +/// A trait defining a default behavior of the message executor. +/// +/// Defines the interface for executing transactions and contract interactions. +/// It is a central component in the testing framework, managing the operational +/// flow and ensuring that contract _calls_ are processed correctly. pub trait Executor where - C: Clone + Debug + PartialEq + JsonSchema + 'static, + C: CustomMsg + 'static, { - /// Runs arbitrary CosmosMsg. - /// This will create a cache before the execution, so no state changes are persisted if this - /// returns an error, but all are persisted on success. + /// Processes (executes) an arbitrary `CosmosMsg`. + /// This will create a cache before the execution, + /// so no state changes are persisted if this returns an error, + /// but all are persisted on success. fn execute(&mut self, sender: Addr, msg: CosmosMsg) -> AnyResult; /// Create a contract and get the new address. @@ -128,8 +138,9 @@ where } /// Execute a contract and process all returned messages. - /// This is just a helper around execute(), - /// but we parse out the data field to that what is returned by the contract (not the protobuf wrapper) + /// This is just a helper function around [execute()](Self::execute) + /// with `WasmMsg::Execute` message, but in this case we parse out the data field + /// to that what is returned by the contract (not the protobuf wrapper). fn execute_contract( &mut self, sender: Addr, @@ -150,8 +161,10 @@ where Ok(res) } - /// Migrate a contract. Sender must be registered admin. - /// This is just a helper around execute() + /// Migrates a contract. + /// Sender must be registered admin. + /// This is just a helper function around [execute()](Self::execute) + /// with `WasmMsg::Migrate` message. fn migrate_contract( &mut self, sender: Addr, @@ -168,6 +181,9 @@ where self.execute(sender, msg.into()) } + /// Sends tokens to specified recipient. + /// This is just a helper function around [execute()](Self::execute) + /// with `BankMsg::Send` message. fn send_tokens( &mut self, sender: Addr, diff --git a/src/gov.rs b/src/gov.rs index 286333a7..f2c01940 100644 --- a/src/gov.rs +++ b/src/gov.rs @@ -1,12 +1,17 @@ use crate::{AcceptingModule, FailingModule, Module}; use cosmwasm_std::{Empty, GovMsg}; - +/// Handles governance-related operations within the test environment. +/// This trait is essential for testing contracts that interact with governance mechanisms, +/// simulating proposals, voting, and other governance activities. pub trait Gov: Module {} - +/// A type alias for a module that accepts governance-related interactions. +/// It's used in scenarios where you need to test how your contract interacts +/// with governance processes and messages. pub type GovAcceptingModule = AcceptingModule; impl Gov for GovAcceptingModule {} - +/// This type alias represents a module designed to fail in response to governance operations. +/// It's useful for testing how contracts behave when governance actions do not proceed as expected. pub type GovFailingModule = FailingModule; impl Gov for GovFailingModule {} diff --git a/src/ibc.rs b/src/ibc.rs index 97e5b026..e8442c2b 100644 --- a/src/ibc.rs +++ b/src/ibc.rs @@ -1,12 +1,18 @@ use crate::{AcceptingModule, FailingModule, Module}; use cosmwasm_std::{Empty, IbcMsg, IbcQuery}; - +///Manages Inter-Blockchain Communication (IBC) functionalities. +///This trait is critical for testing contracts that involve cross-chain interactions, +///reflecting the interconnected nature of the Cosmos ecosystem. pub trait Ibc: Module {} - +/// Ideal for testing contracts that involve IBC, this module is designed to successfully +/// handle cross-chain messages. It's key for ensuring that your contract can smoothly interact +/// with other blockchains in the Cosmos network. pub type IbcAcceptingModule = AcceptingModule; impl Ibc for IbcAcceptingModule {} - +/// Use this to test how your contract deals with problematic IBC scenarios. +/// It's a module that deliberately fails in handling IBC messages, allowing you +/// to check how your contract behaves in less-than-ideal cross-chain communication situations. pub type IbcFailingModule = FailingModule; impl Ibc for IbcFailingModule {} diff --git a/src/lib.rs b/src/lib.rs index 99a926b7..d933e0a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,18 +1,135 @@ -//! Multitest is a design to simulate a blockchain environment in pure Rust. -//! This allows us to run unit tests that involve contract -> contract, -//! and contract -> bank interactions. This is not intended to be a full blockchain app -//! but to simulate the Cosmos SDK x/wasm module close enough to gain confidence in -//! multi-contract deployments before testing them on a live blockchain. +//! # CosmWasm MultiTest //! -//! To understand the design of this module, please refer to `../DESIGN.md` +//! **CosmWasm MultiTest** is designed to simulate a blockchain environment in pure Rust. +//! This allows to run unit tests that involve **contract 🡘 contract**, +//! and **contract 🡘 module** interactions. **CosmWasm MultiTest** is not intended +//! to be a full blockchain application, but to simulate the Cosmos SDK x/wasm module close enough +//! to gain confidence in multi-contract deployments, before testing them on a live blockchain. +//! +//! The following sections explains some of the design for those who want to use the API, +//! as well as those who want to take a look under the hood of **CosmWasm MultiTest**. +//! +//! ## Key APIs +//! +//! ### App +//! +//! The main entry point to the system is called [App], which represents a blockchain application. +//! It maintains an idea of block height and time, which can be updated to simulate multiple +//! blocks. You can use application's [update_block](App::update_block) method to increment +//! the timestamp by 5 seconds and the height by 1 (simulating a new block) or you can write +//! any other mutator of [BlockInfo](cosmwasm_std::BlockInfo) to advance more. +//! +//! [App] exposes an entry point [execute](App::execute) that allows to execute +//! any [CosmosMsg](cosmwasm_std::CosmosMsg) and wraps it in an atomic transaction. +//! That is, only if [execute](App::execute) returns a success, then the state will be committed. +//! It returns the data and a list of [Event](cosmwasm_std::Event)s on successful execution +//! or an **`Err(String)`** on error. There are some helper methods tied to the [Executor] trait +//! that create the [CosmosMsg](cosmwasm_std::CosmosMsg) for you to provide a less verbose API. +//! [App]'s methods like [instantiate_contract](App::instantiate_contract), +//! [execute_contract](App::execute_contract), and [send_tokens](App::send_tokens) are exposed +//! for your convenience in writing tests. +//! Each method executes one [CosmosMsg](cosmwasm_std::CosmosMsg) atomically, as if it was submitted by a user. +//! You can also use [execute_multi](App::execute_multi) if you wish to execute multiple messages together +//! that revert the state as a whole in case of any failure. +//! +//! The other key entry point to [App] is the [Querier](cosmwasm_std::Querier) interface that it implements. +//! In particular, you can use [wrap](App::wrap) to get a [QuerierWrapper](cosmwasm_std::QuerierWrapper), +//! which provides all kinds of interesting APIs to query the blockchain, like +//! [query_all_balances](cosmwasm_std::QuerierWrapper::query_all_balances) and +//! [query_wasm_smart](cosmwasm_std::QuerierWrapper::query_wasm_smart). +//! Putting this all together, you have one [Storage](cosmwasm_std::Storage) wrapped into an application, +//! where you can execute contracts and bank, query them easily, and update the current +//! [BlockInfo](cosmwasm_std::BlockInfo), in an API that is not very verbose or cumbersome. +//! Under the hood it will process all messages returned from contracts, move _bank_ tokens +//! and call into other contracts. +//! +//! You can easily create an [App] for use in your testcode like shown below. +//! Having a single utility function for creating and configuring the [App] is the common +//! pattern while testing contracts with **CosmWasm MultiTest**. +//! +//! ``` +//! use cw_multi_test::App; +//! +//! fn mock_app() -> App { +//! App::default() +//! } +//! ``` +//! +//! The [App] maintains the root [Storage](cosmwasm_std::Storage), and the [BlockInfo](cosmwasm_std::BlockInfo) +//! for the current block. It also contains a [Router] (discussed below), which can process +//! any [CosmosMsg](cosmwasm_std::CosmosMsg) variant by passing it to the proper keeper. +//! +//! > **Note**: [App] properly handles submessages and reply blocks. +//! +//! > **Note**: While the API currently supports custom messages, we don't currently have an implementation +//! > of the default keeper, except of experimental [CachingCustomHandler](custom_handler::CachingCustomHandler). +//! +//! ### Contracts +//! +//! Before you can call contracts, you must **instantiate** them. And to instantiate them, you need a `code_id`. +//! In `wasmd`, this `code_id` points to some stored Wasm code that is then run. In multitest, we use it to +//! point to a `Box` that should be run. That is, you need to implement the [Contract] trait +//! and then add the contract to the [App] via [store_code](App::store_code) function. +//! +//! The [Contract] trait defines the major entry points to any CosmWasm contract: +//! [instantiate](Contract::instantiate), [execute](Contract::execute), [query](Contract::query), +//! [sudo](Contract::sudo), [reply](Contract::reply) (for submessages) and [migrate](Contract::migrate). +//! +//! In order to easily implement [Contract] from some existing contract code, we use the [ContractWrapper] struct, +//! which takes some function pointers and combines them. You can take a look at **test_helpers** module +//! for some examples or how to do so (and useful mocks for some test cases). +//! Here is an example of wrapping a CosmWasm contract into a [Contract] trait to be added to an [App]: +//! +//! ```ignore +//! use cosmwasm_std::Empty; +//! use cw1_whitelist::contract::{execute, instantiate, query}; +//! use cw_multi_test::{App, Contract, ContractWrapper}; +//! +//! pub fn contract_whitelist() -> Box> { +//! Box::new(ContractWrapper::new(execute, instantiate, query)) +//! } +//! +//! let mut app = App::default(); +//! let code_id = app.store_code(contract_whitelist()); +//! // use this code_id to instantiate a contract +//! ``` +//! +//! ### Modules +//! +//! There is only one root [Storage](cosmwasm_std::Storage), stored inside [App]. +//! This is wrapped into a transaction, and then passed down to other functions to work with. +//! The code that modifies the Storage is divided into _modules_ much like the CosmosSDK. +//! Currently, the message processing logic is divided into one _module_ for every [CosmosMsg](cosmwasm_std) variant. +//! [Bank] handles [BankMsg](cosmwasm_std::BankMsg) and [BankQuery](cosmwasm_std::BankQuery), +//! [Wasm] handles [WasmMsg](cosmwasm_std::WasmMsg) and [WasmQuery](cosmwasm_std::WasmQuery), etc. +//! +//! ### Router +//! +//! The [Router] groups all modules in the system into one "macro-module" that can handle +//! any [CosmosMsg](cosmwasm_std::CosmosMsg). While [Bank] handles [BankMsg](cosmwasm_std::BankMsg), +//! and [Wasm] handles [WasmMsg](cosmwasm_std::WasmMsg), we need to combine them into a larger composite +//! to let them process messages from [App]. This is the whole concept of the [Router]. +//! If you take a look at the [execute](Router::execute) method, you will see it is quite straightforward. +//! +//! Note that the only way one module can call or query another module is by dispatching messages via the [Router]. +//! This allows us to implement an independent [Wasm] in a way that it can process [SubMsg](cosmwasm_std::SubMsg) +//! that call into [Bank]. You can see an example of that in _send_ method of the [WasmKeeper], +//! where it moves bank tokens from one account to another. +//! +//! ### Addons +//! +//! (tbd) + +// #![deny(missing_docs)] +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::missing_crate_level_docs)] -pub mod addons; mod addresses; +mod api; mod app; mod app_builder; mod bank; mod checksums; -#[allow(clippy::type_complexity)] mod contracts; pub mod custom_handler; pub mod error; @@ -23,12 +140,20 @@ mod module; pub(crate) mod prefixed_storage; pub mod queries; mod staking; +mod stargate; +mod test_helpers; +mod tests; mod transactions; mod wasm; pub mod wasm_emulation; -pub use crate::addresses::{AddressGenerator, SimpleAddressGenerator}; -pub use crate::app::{custom_app, next_block, App, BasicApp, CosmosRouter, Router, SudoMsg}; +pub use crate::addresses::{ + AddressGenerator, IntoAddr, IntoBech32, IntoBech32m, SimpleAddressGenerator, +}; +pub use crate::api::{MockApiBech32, MockApiBech32m}; +pub use crate::app::{ + custom_app, next_block, no_init, App, BasicApp, CosmosRouter, Router, SudoMsg, +}; pub use crate::app_builder::{AppBuilder, BasicAppBuilder}; pub use crate::bank::{Bank, BankKeeper, BankSudo}; pub use crate::checksums::ChecksumGenerator; @@ -40,8 +165,7 @@ pub use crate::module::{AcceptingModule, FailingModule, Module}; pub use crate::staking::{ Distribution, DistributionKeeper, StakeKeeper, Staking, StakingInfo, StakingSudo, }; +pub use crate::stargate::{Stargate, StargateAccepting, StargateFailing}; pub use crate::wasm::{ ContractData, Wasm, WasmKeeper, WasmSudo, LOCAL_RUST_CODE_OFFSET, LOCAL_WASM_CODE_OFFSET, }; - -pub use prefixed_storage::{PrefixedStorage, ReadonlyPrefixedStorage}; diff --git a/src/module.rs b/src/module.rs index 470e8d97..7b0dc9d1 100644 --- a/src/module.rs +++ b/src/module.rs @@ -1,16 +1,23 @@ use crate::app::CosmosRouter; use crate::error::{bail, AnyResult}; use crate::AppResponse; -use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomQuery, Querier, Storage}; -use schemars::JsonSchema; +use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomMsg, CustomQuery, Querier, Storage}; use serde::de::DeserializeOwned; use std::fmt::Debug; use std::marker::PhantomData; -/// Module interface. +/// # General module +/// +/// Provides a generic interface for modules within the test environment. +/// It is essential for creating modular and extensible testing setups, +/// allowing developers to integrate custom functionalities +/// or test specific scenarios. pub trait Module { + /// Type of messages processed by the module instance. type ExecT; + /// Type of queries processed by the module instance. type QueryT; + /// Type of privileged messages used by the module instance. type SudoT; /// Runs any [ExecT](Self::ExecT) message, @@ -25,7 +32,7 @@ pub trait Module { msg: Self::ExecT, ) -> AnyResult where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static; /// Runs any [QueryT](Self::QueryT) message, @@ -53,21 +60,26 @@ pub trait Module { msg: Self::SudoT, ) -> AnyResult where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static; } +/// # Always failing module +/// +/// This could be a diagnostic or testing tool within the Cosmos ecosystem, +/// designed to intentionally fail during processing any message, query or privileged action. +pub struct FailingModule(PhantomData<(ExecT, QueryT, SudoT)>); -pub struct FailingModule { - module_type: String, - _t: PhantomData<(ExecT, QueryT, SudoT)>, +impl FailingModule { + /// Creates an instance of a failing module. + pub fn new() -> Self { + Self(PhantomData) + } } -impl FailingModule { - pub fn new(module_type: &str) -> Self { - Self { - module_type: module_type.to_string(), - _t: PhantomData, - } +impl Default for FailingModule { + /// Creates a default instance of a failing module. + fn default() -> Self { + Self::new() } } @@ -91,12 +103,7 @@ where sender: Addr, msg: Self::ExecT, ) -> AnyResult { - bail!( - "Unexpected exec msg {:?} from {:?} on {} module", - msg, - sender, - self.module_type - ) + bail!("Unexpected exec msg {:?} from {:?}", msg, sender,) } /// Runs any [QueryT](Self::QueryT) message, always returns an error. @@ -108,11 +115,7 @@ where _block: &BlockInfo, request: Self::QueryT, ) -> AnyResult { - bail!( - "Unexpected custom query {:?} on {} module", - request, - self.module_type - ) + bail!("Unexpected custom query {:?}", request,) } /// Runs any [SudoT](Self::SudoT) privileged action, always returns an error. @@ -124,23 +127,24 @@ where _block: &BlockInfo, msg: Self::SudoT, ) -> AnyResult { - bail!( - "Unexpected sudo msg {:?} on {} module", - msg, - self.module_type - ) + bail!("Unexpected sudo msg {:?}", msg,) } } - +/// # Always accepting module +/// +/// This struct represents a module in the Cosmos ecosystem designed to +/// always accept all processed messages, queries and privileged actions. pub struct AcceptingModule(PhantomData<(ExecT, QueryT, SudoT)>); impl AcceptingModule { + /// Creates an instance of an accepting module. pub fn new() -> Self { Self(PhantomData) } } impl Default for AcceptingModule { + /// Creates an instance of an accepting module with default settings. fn default() -> Self { Self::new() } @@ -169,7 +173,7 @@ where Ok(AppResponse::default()) } - /// Runs any [QueryT](Self::QueryT) message, always returns an empty binary. + /// Runs any [QueryT](Self::QueryT) message, always returns a default (empty) binary. fn query( &self, _api: &dyn Api, diff --git a/src/prefixed_storage/length_prefixed.rs b/src/prefixed_storage/length_prefixed.rs index 82eaf23b..931b8acd 100644 --- a/src/prefixed_storage/length_prefixed.rs +++ b/src/prefixed_storage/length_prefixed.rs @@ -102,7 +102,7 @@ mod tests { #[test] fn to_length_prefixed_calculates_capacity_correctly() { // Those tests cannot guarantee the required capacity was calculated correctly before - // the vector allocation but increase the likelyhood of a proper implementation. + // the vector allocation but increase the likelihood of a proper implementation. let key = to_length_prefixed(b""); assert_eq!(key.capacity(), key.len()); @@ -161,7 +161,7 @@ mod tests { #[test] fn to_length_prefixed_nested_calculates_capacity_correctly() { // Those tests cannot guarantee the required capacity was calculated correctly before - // the vector allocation but increase the likelyhood of a proper implementation. + // the vector allocation but increase the likelihood of a proper implementation. let key = to_length_prefixed_nested(&[]); assert_eq!(key.capacity(), key.len()); diff --git a/src/prefixed_storage/mod.rs b/src/prefixed_storage/mod.rs index 4506230a..78f05e29 100644 --- a/src/prefixed_storage/mod.rs +++ b/src/prefixed_storage/mod.rs @@ -11,12 +11,12 @@ pub use length_prefixed::{ CONTRACT_STORAGE_PREFIX, }; -/// An alias of PrefixedStorage::new for less verbose usage +/// An alias of [PrefixedStorage::new] for less verbose usage. pub fn prefixed<'a>(storage: &'a mut dyn Storage, namespace: &[u8]) -> PrefixedStorage<'a> { PrefixedStorage::new(storage, namespace) } -/// An alias of ReadonlyPrefixedStorage::new for less verbose usage +/// An alias of [ReadonlyPrefixedStorage::new] for less verbose usage. pub fn prefixed_read<'a>( storage: &'a dyn Storage, namespace: &[u8], @@ -24,12 +24,30 @@ pub fn prefixed_read<'a>( ReadonlyPrefixedStorage::new(storage, namespace) } +/// An alias of [PrefixedStorage::multilevel] for less verbose usage. +pub fn prefixed_multilevel<'a>( + storage: &'a mut dyn Storage, + namespaces: &[&[u8]], +) -> PrefixedStorage<'a> { + PrefixedStorage::multilevel(storage, namespaces) +} + +/// An alias of [ReadonlyPrefixedStorage::multilevel] for less verbose usage. +pub fn prefixed_multilevel_read<'a>( + storage: &'a dyn Storage, + namespaces: &[&[u8]], +) -> ReadonlyPrefixedStorage<'a> { + ReadonlyPrefixedStorage::multilevel(storage, namespaces) +} + +/// Prefixed, mutable storage. pub struct PrefixedStorage<'a> { storage: &'a mut dyn Storage, prefix: Vec, } impl<'a> PrefixedStorage<'a> { + /// Returns a mutable prefixed storage with specified namespace. pub fn new(storage: &'a mut dyn Storage, namespace: &[u8]) -> Self { PrefixedStorage { storage, @@ -37,8 +55,9 @@ impl<'a> PrefixedStorage<'a> { } } - // Nested namespaces as documented in - // https://github.com/webmaster128/key-namespacing#nesting + /// Returns a mutable prefixed storage with [nested namespaces]. + /// + /// [nested namespaces]: https://github.com/webmaster128/key-namespacing#nesting pub fn multilevel(storage: &'a mut dyn Storage, namespaces: &[&[u8]]) -> Self { PrefixedStorage { storage, @@ -52,16 +71,8 @@ impl<'a> Storage for PrefixedStorage<'a> { get_with_prefix(self.storage, &self.prefix, key) } - fn set(&mut self, key: &[u8], value: &[u8]) { - set_with_prefix(self.storage, &self.prefix, key, value); - } - - fn remove(&mut self, key: &[u8]) { - remove_with_prefix(self.storage, &self.prefix, key); - } - - /// range allows iteration over a set of keys, either forwards or backwards - /// uses standard rust range notation, and eg db.range(b"foo"..b"bar") also works reverse + /// Range allows iteration over a set of keys, either forwards or backwards. + /// Uses standard rust range notation, and e.g. `db.range(b"foo"‥b"bar")` and also works reverse. fn range<'b>( &'b self, start: Option<&[u8]>, @@ -70,14 +81,24 @@ impl<'a> Storage for PrefixedStorage<'a> { ) -> Box + 'b> { range_with_prefix(self.storage, &self.prefix, start, end, order) } + + fn set(&mut self, key: &[u8], value: &[u8]) { + set_with_prefix(self.storage, &self.prefix, key, value); + } + + fn remove(&mut self, key: &[u8]) { + remove_with_prefix(self.storage, &self.prefix, key); + } } +/// Prefixed, read-only storage. pub struct ReadonlyPrefixedStorage<'a> { storage: &'a dyn Storage, prefix: Vec, } impl<'a> ReadonlyPrefixedStorage<'a> { + /// Returns a read-only prefixed storage with specified namespace. pub fn new(storage: &'a dyn Storage, namespace: &[u8]) -> Self { ReadonlyPrefixedStorage { storage, @@ -85,8 +106,9 @@ impl<'a> ReadonlyPrefixedStorage<'a> { } } - // Nested namespaces as documented in - // https://github.com/webmaster128/key-namespacing#nesting + /// Returns a read-only prefixed storage with [nested namespaces]. + /// + /// [nested namespaces]: https://github.com/webmaster128/key-namespacing#nesting pub fn multilevel(storage: &'a dyn Storage, namespaces: &[&[u8]]) -> Self { ReadonlyPrefixedStorage { storage, @@ -100,15 +122,7 @@ impl<'a> Storage for ReadonlyPrefixedStorage<'a> { get_with_prefix(self.storage, &self.prefix, key) } - fn set(&mut self, _key: &[u8], _value: &[u8]) { - unimplemented!(); - } - - fn remove(&mut self, _key: &[u8]) { - unimplemented!(); - } - - /// range allows iteration over a set of keys, either forwards or backwards + /// Range allows iteration over a set of keys, either forwards or backwards. fn range<'b>( &'b self, start: Option<&[u8]>, @@ -117,6 +131,14 @@ impl<'a> Storage for ReadonlyPrefixedStorage<'a> { ) -> Box + 'b> { range_with_prefix(self.storage, &self.prefix, start, end, order) } + + fn set(&mut self, _key: &[u8], _value: &[u8]) { + unimplemented!(); + } + + fn remove(&mut self, _key: &[u8]) { + unimplemented!(); + } } #[cfg(test)] @@ -139,6 +161,35 @@ mod tests { assert_eq!(s2.get(b"elsewhere"), None); } + #[test] + fn prefixed_storage_range() { + // prepare prefixed storage + let mut storage = MockStorage::new(); + let mut ps1 = PrefixedStorage::new(&mut storage, b"foo"); + ps1.set(b"a", b"A"); + ps1.set(b"l", b"L"); + ps1.set(b"p", b"P"); + ps1.set(b"z", b"Z"); + assert_eq!(storage.get(b"\x00\x03fooa").unwrap(), b"A".to_vec()); + assert_eq!(storage.get(b"\x00\x03fool").unwrap(), b"L".to_vec()); + assert_eq!(storage.get(b"\x00\x03foop").unwrap(), b"P".to_vec()); + assert_eq!(storage.get(b"\x00\x03fooz").unwrap(), b"Z".to_vec()); + // query prefixed storage using range function + let ps2 = PrefixedStorage::new(&mut storage, b"foo"); + assert_eq!( + vec![b"A".to_vec(), b"L".to_vec(), b"P".to_vec()], + ps2.range(Some(b"a"), Some(b"z"), Order::Ascending) + .map(|(_, value)| value) + .collect::>>() + ); + assert_eq!( + vec![b"Z".to_vec(), b"P".to_vec(), b"L".to_vec(), b"A".to_vec()], + ps2.range(Some(b"a"), None, Order::Descending) + .map(|(_, value)| value) + .collect::>>() + ); + } + #[test] fn prefixed_storage_multilevel_set_and_get() { let mut storage = MockStorage::new(); @@ -172,6 +223,24 @@ mod tests { assert_eq!(s2.get(b"obar"), None); } + #[test] + #[should_panic(expected = "not implemented")] + #[allow(clippy::unnecessary_mut_passed)] + fn readonly_prefixed_storage_set() { + let mut storage = MockStorage::new(); + let mut rps = ReadonlyPrefixedStorage::new(&mut storage, b"foo"); + rps.set(b"bar", b"gotcha"); + } + + #[test] + #[should_panic(expected = "not implemented")] + #[allow(clippy::unnecessary_mut_passed)] + fn readonly_prefixed_storage_remove() { + let mut storage = MockStorage::new(); + let mut rps = ReadonlyPrefixedStorage::new(&mut storage, b"foo"); + rps.remove(b"gotcha"); + } + #[test] fn readonly_prefixed_storage_multilevel_get() { let mut storage = MockStorage::new(); diff --git a/src/staking.rs b/src/staking.rs index fc0048dc..cb311cdc 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -5,16 +5,16 @@ use crate::prefixed_storage::{prefixed, prefixed_read}; use crate::{BankSudo, Module}; use cosmwasm_std::{ coin, ensure, ensure_eq, to_json_binary, Addr, AllDelegationsResponse, AllValidatorsResponse, - Api, BankMsg, Binary, BlockInfo, BondedDenomResponse, Coin, CustomQuery, Decimal, Delegation, - DelegationResponse, DistributionMsg, Empty, Event, FullDelegation, Querier, StakingMsg, - StakingQuery, Storage, Timestamp, Uint128, Validator, ValidatorResponse, + Api, BankMsg, Binary, BlockInfo, BondedDenomResponse, Coin, CustomMsg, CustomQuery, Decimal, + Delegation, DelegationResponse, DistributionMsg, Empty, Event, FullDelegation, Querier, + StakingMsg, StakingQuery, Storage, Timestamp, Uint128, Validator, ValidatorResponse, }; use cw_storage_plus::{Deque, Item, Map}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::collections::{BTreeSet, VecDeque}; -// Contains some general staking parameters +/// A structure containing some general staking parameters. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct StakingInfo { /// The denominator of the staking token @@ -26,6 +26,7 @@ pub struct StakingInfo { } impl Default for StakingInfo { + /// Creates staking info with default settings. fn default() -> Self { StakingInfo { bonded_denom: "TOKEN".to_string(), @@ -101,49 +102,58 @@ pub const NAMESPACE_STAKING: &[u8] = b"staking"; // https://github.com/cosmos/cosmos-sdk/blob/4f6f6c00021f4b5ee486bbb71ae2071a8ceb47c9/x/distribution/types/keys.go#L16 pub const NAMESPACE_DISTRIBUTION: &[u8] = b"distribution"; -// We need to expand on this, but we will need this to properly test out staking -#[derive(Clone, std::fmt::Debug, PartialEq, Eq, JsonSchema)] +/// Staking privileged action definition. +/// +/// We need to expand on this, but we will need this to properly test out staking +#[derive(Clone, Debug, PartialEq, Eq, JsonSchema)] pub enum StakingSudo { /// Slashes the given percentage of the validator's stake. /// For now, you cannot slash retrospectively in tests. Slash { + /// Validator's address. validator: String, + /// Percentage of the validator's stake. percentage: Decimal, }, - /// Causes the unbonding queue to be processed. - /// This needs to be triggered manually, since there is no good place to do this right now. - /// In cosmos-sdk, this is done in `EndBlock`, but we don't have that here. - #[deprecated(note = "This is not needed anymore. Just call `update_block`")] - ProcessQueue {}, } +/// A trait defining a behavior of the stake keeper. +/// +/// Manages staking operations, vital for testing contracts in proof-of-stake (PoS) blockchain environments. +/// This trait simulates staking behaviors, including delegation, validator operations, and reward mechanisms. pub trait Staking: Module { /// This is called from the end blocker (`update_block` / `set_block`) to process the - /// staking queue. - /// Needed because unbonding has a waiting time. + /// staking queue. Needed because unbonding has a waiting time. /// If you're implementing a dummy staking module, this can be a no-op. - fn process_queue( + fn process_queue( &self, - api: &dyn Api, - storage: &mut dyn Storage, - router: &dyn CosmosRouter, - block: &BlockInfo, - ) -> AnyResult; + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + ) -> AnyResult { + Ok(AppResponse::default()) + } } +/// A trait defining a behavior of the distribution keeper. pub trait Distribution: Module {} +/// A structure representing a default stake keeper. pub struct StakeKeeper { + /// Module address of a default stake keeper. module_addr: Addr, } impl Default for StakeKeeper { + /// Creates a new stake keeper with default settings. fn default() -> Self { Self::new() } } impl StakeKeeper { + /// Creates a new stake keeper with default module address. pub fn new() -> Self { StakeKeeper { // The address of the staking module. This holds all staked tokens. @@ -154,7 +164,6 @@ impl StakeKeeper { /// Provides some general parameters to the stake keeper pub fn setup(&self, storage: &mut dyn Storage, staking_info: StakingInfo) -> AnyResult<()> { let mut storage = prefixed(storage, NAMESPACE_STAKING); - STAKING_INFO.save(&mut storage, &staking_info)?; Ok(()) } @@ -270,7 +279,7 @@ impl StakeKeeper { } /// Updates the staking reward for the given validator and their stakers - /// It saves the validator info and it's stakers, so make sure not to overwrite that. + /// It saves the validator info and stakers, so make sure not to overwrite that. /// Always call this to update rewards before changing anything that influences future rewards. fn update_rewards( api: &dyn Api, @@ -532,7 +541,7 @@ impl StakeKeeper { Ok(()) } - fn process_queue( + fn process_queue( &self, api: &dyn Api, storage: &mut dyn Storage, @@ -601,7 +610,7 @@ impl StakeKeeper { } impl Staking for StakeKeeper { - fn process_queue( + fn process_queue( &self, api: &dyn Api, storage: &mut dyn Storage, @@ -617,7 +626,7 @@ impl Module for StakeKeeper { type QueryT = StakingQuery; type SudoT = StakingSudo; - fn execute( + fn execute( &self, api: &dyn Api, storage: &mut dyn Storage, @@ -735,32 +744,6 @@ impl Module for StakeKeeper { } } - fn sudo( - &self, - api: &dyn Api, - storage: &mut dyn Storage, - router: &dyn CosmosRouter, - block: &BlockInfo, - msg: StakingSudo, - ) -> AnyResult { - match msg { - StakingSudo::Slash { - validator, - percentage, - } => { - let mut staking_storage = prefixed(storage, NAMESPACE_STAKING); - let validator = api.addr_validate(&validator)?; - self.validate_percentage(percentage)?; - - self.slash(api, &mut staking_storage, block, &validator, percentage)?; - - Ok(AppResponse::default()) - } - #[allow(deprecated)] - StakingSudo::ProcessQueue {} => self.process_queue(api, storage, router, block), - } - } - fn query( &self, api: &dyn Api, @@ -825,7 +808,7 @@ impl Module for StakeKeeper { let staking_info = Self::get_staking_info(&staking_storage)?; let amount = coin( - (Uint128::new(1).mul_floor(shares.stake)).u128(), + Uint128::new(1).mul_floor(shares.stake).u128(), staking_info.bonded_denom, ); @@ -858,14 +841,42 @@ impl Module for StakeKeeper { q => bail!("Unsupported staking sudo message: {:?}", q), } } + + fn sudo( + &self, + api: &dyn Api, + storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + block: &BlockInfo, + msg: StakingSudo, + ) -> AnyResult { + match msg { + StakingSudo::Slash { + validator, + percentage, + } => { + let mut staking_storage = prefixed(storage, NAMESPACE_STAKING); + let validator = api.addr_validate(&validator)?; + self.validate_percentage(percentage)?; + self.slash(api, &mut staking_storage, block, &validator, percentage)?; + Ok(AppResponse::default()) + } + } + } } +/// A structure representing a default distribution keeper. +/// +/// This module likely manages the distribution of rewards and fees within the blockchain network. +/// It could handle tasks like distributing block rewards to validators and delegators, +/// and managing community funding mechanisms. #[derive(Default)] pub struct DistributionKeeper {} impl DistributionKeeper { + /// Creates a new distribution keeper with default settings. pub fn new() -> Self { - DistributionKeeper {} + Self::default() } /// Removes all rewards from the given (delegator, validator) pair and returns the amount @@ -892,6 +903,7 @@ impl DistributionKeeper { Ok(rewards) } + /// Returns the withdrawal address for specified delegator. pub fn get_withdraw_address(storage: &dyn Storage, delegator: &Addr) -> AnyResult { Ok(match WITHDRAW_ADDRESS.may_load(storage, delegator)? { Some(a) => a, @@ -899,20 +911,22 @@ impl DistributionKeeper { }) } - // https://docs.cosmos.network/main/modules/distribution#msgsetwithdrawaddress + /// Sets (changes) the [withdraw address] of the delegator. + /// + /// [withdraw address]: https://docs.cosmos.network/main/modules/distribution#msgsetwithdrawaddress pub fn set_withdraw_address( storage: &mut dyn Storage, delegator: &Addr, - withdraw_address: &Addr, + withdraw_addr: &Addr, ) -> AnyResult<()> { - if delegator == withdraw_address { + if delegator == withdraw_addr { WITHDRAW_ADDRESS.remove(storage, delegator); Ok(()) } else { // technically we should require that this address is not // the address of a module. TODO: how? WITHDRAW_ADDRESS - .save(storage, delegator, withdraw_address) + .save(storage, delegator, withdraw_addr) .map_err(|e| e.into()) } } @@ -925,7 +939,7 @@ impl Module for DistributionKeeper { type QueryT = Empty; type SudoT = Empty; - fn execute( + fn execute( &self, api: &dyn Api, storage: &mut dyn Storage, @@ -984,6 +998,17 @@ impl Module for DistributionKeeper { } } + fn query( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + _request: Empty, + ) -> AnyResult { + bail!("Something went wrong - Distribution doesn't have query messages") + } + fn sudo( &self, _api: &dyn Api, @@ -994,15 +1019,1510 @@ impl Module for DistributionKeeper { ) -> AnyResult { bail!("Something went wrong - Distribution doesn't have sudo messages") } +} - fn query( - &self, - _api: &dyn Api, - _storage: &dyn Storage, - _querier: &dyn Querier, - _block: &BlockInfo, - _request: Empty, - ) -> AnyResult { - bail!("Something went wrong - Distribution doesn't have query messages") +#[cfg(test)] +mod test { + use super::*; + use crate::{ + app::MockRouter, BankKeeper, FailingModule, GovFailingModule, IbcFailingModule, Router, + StargateFailing, WasmKeeper, + }; + use cosmwasm_std::{ + from_json, + testing::{mock_env, MockApi, MockStorage}, + BalanceResponse, BankQuery, + }; + + /// Type alias for default build `Router` to make its reference in typical scenario + type BasicRouter = Router< + BankKeeper, + FailingModule, + WasmKeeper, + StakeKeeper, + DistributionKeeper, + IbcFailingModule, + GovFailingModule, + StargateFailing, + >; + + fn mock_router() -> BasicRouter { + Router { + wasm: WasmKeeper::new(), + bank: BankKeeper::new(), + custom: FailingModule::new(), + staking: StakeKeeper::new(), + distribution: DistributionKeeper::new(), + ibc: IbcFailingModule::new(), + gov: GovFailingModule::new(), + stargate: StargateFailing, + } + } + + fn setup_test_env( + apr: Decimal, + validator_commission: Decimal, + ) -> (MockApi, MockStorage, BasicRouter, BlockInfo, Addr) { + let api = MockApi::default(); + let router = mock_router(); + let mut store = MockStorage::new(); + let block = mock_env().block; + + let validator_addr = api.addr_make("testvaloper1"); + + router + .staking + .setup( + &mut store, + StakingInfo { + bonded_denom: "TOKEN".to_string(), + unbonding_time: 60, + apr, + }, + ) + .unwrap(); + + // add validator + let valoper1 = Validator::new( + validator_addr.to_string(), + validator_commission, + Decimal::percent(100), + Decimal::percent(1), + ); + router + .staking + .add_validator(&api, &mut store, &block, valoper1) + .unwrap(); + + (api, store, router, block, validator_addr) + } + + #[test] + fn add_get_validators() { + let api = MockApi::default(); + let mut store = MockStorage::new(); + let stake = StakeKeeper::default(); + let block = mock_env().block; + + let validator_addr = api.addr_make("test-validator"); + + // add validator + let validator = Validator::new( + validator_addr.to_string(), + Decimal::percent(10), + Decimal::percent(20), + Decimal::percent(1), + ); + stake + .add_validator(&api, &mut store, &block, validator.clone()) + .unwrap(); + + // get it + let staking_storage = prefixed_read(&store, NAMESPACE_STAKING); + let val = stake + .get_validator(&staking_storage, &validator_addr) + .unwrap() + .unwrap(); + assert_eq!(val, validator); + + // try to add with same address + let validator_fake = Validator::new( + validator_addr.to_string(), + Decimal::percent(1), + Decimal::percent(10), + Decimal::percent(100), + ); + stake + .add_validator(&api, &mut store, &block, validator_fake) + .unwrap_err(); + + // should still be original value + let staking_storage = prefixed_read(&store, NAMESPACE_STAKING); + let val = stake + .get_validator(&staking_storage, &validator_addr) + .unwrap() + .unwrap(); + assert_eq!(val, validator); + } + + #[test] + fn validator_slashing() { + let api = MockApi::default(); + let router = MockRouter::default(); + let mut store = MockStorage::new(); + let stake = StakeKeeper::new(); + let block = mock_env().block; + + let delegator_addr = api.addr_make("delegator"); + let validator_addr = api.addr_make("testvaloper1"); + + // add validator + let valoper1 = Validator::new( + validator_addr.to_string(), + Decimal::percent(10), + Decimal::percent(20), + Decimal::percent(1), + ); + stake + .add_validator(&api, &mut store, &block, valoper1) + .unwrap(); + + // stake 100 tokens + let mut staking_storage = prefixed(&mut store, NAMESPACE_STAKING); + stake + .add_stake( + &api, + &mut staking_storage, + &block, + &delegator_addr, + &validator_addr, + coin(100, "TOKEN"), + ) + .unwrap(); + + // slash 50% + stake + .sudo( + &api, + &mut store, + &router, + &block, + StakingSudo::Slash { + validator: validator_addr.to_string(), + percentage: Decimal::percent(50), + }, + ) + .unwrap(); + + // check stake + let staking_storage = prefixed(&mut store, NAMESPACE_STAKING); + let stake_left = stake + .get_stake(&staking_storage, &delegator_addr, &validator_addr) + .unwrap(); + assert_eq!( + stake_left.unwrap().amount.u128(), + 50, + "should have slashed 50%" + ); + + // slash all + stake + .sudo( + &api, + &mut store, + &router, + &block, + StakingSudo::Slash { + validator: validator_addr.to_string(), + percentage: Decimal::percent(100), + }, + ) + .unwrap(); + + // check stake + let staking_storage = prefixed(&mut store, NAMESPACE_STAKING); + let stake_left = stake + .get_stake(&staking_storage, &delegator_addr, &validator_addr) + .unwrap(); + assert_eq!(stake_left, None, "should have slashed whole stake"); + } + + #[test] + fn rewards_work_for_single_delegator() { + let (api, mut store, router, mut block, validator_addr) = + setup_test_env(Decimal::percent(10), Decimal::percent(10)); + let stake = &router.staking; + let distr = &router.distribution; + let delegator_addr = api.addr_make("delegator"); + + let mut staking_storage = prefixed(&mut store, NAMESPACE_STAKING); + // stake 200 tokens + stake + .add_stake( + &api, + &mut staking_storage, + &block, + &delegator_addr, + &validator_addr, + coin(200, "TOKEN"), + ) + .unwrap(); + + // wait 1/2 year + block.time = block.time.plus_seconds(60 * 60 * 24 * 365 / 2); + + // should now have 200 * 10% / 2 - 10% commission = 9 tokens reward + let rewards = stake + .get_rewards(&store, &block, &delegator_addr, &validator_addr) + .unwrap() + .unwrap(); + assert_eq!(rewards.amount.u128(), 9, "should have 9 tokens reward"); + + // withdraw rewards + distr + .execute( + &api, + &mut store, + &router, + &block, + delegator_addr.clone(), + DistributionMsg::WithdrawDelegatorReward { + validator: validator_addr.to_string(), + }, + ) + .unwrap(); + + // should have no rewards left + let rewards = stake + .get_rewards(&store, &block, &delegator_addr, &validator_addr) + .unwrap() + .unwrap(); + assert_eq!(rewards.amount.u128(), 0); + + // wait another 1/2 year + block.time = block.time.plus_seconds(60 * 60 * 24 * 365 / 2); + // should now have 9 tokens again + let rewards = stake + .get_rewards(&store, &block, &delegator_addr, &validator_addr) + .unwrap() + .unwrap(); + assert_eq!(rewards.amount.u128(), 9); + } + + #[test] + fn rewards_work_for_multiple_delegators() { + let (api, mut store, router, mut block, validator) = + setup_test_env(Decimal::percent(10), Decimal::percent(10)); + let stake = &router.staking; + let distr = &router.distribution; + let bank = &router.bank; + let delegator1 = api.addr_make("delegator1"); + let delegator2 = api.addr_make("delegator2"); + + let mut staking_storage = prefixed(&mut store, NAMESPACE_STAKING); + + // add 100 stake to delegator1 and 200 to delegator2 + stake + .add_stake( + &api, + &mut staking_storage, + &block, + &delegator1, + &validator, + coin(100, "TOKEN"), + ) + .unwrap(); + stake + .add_stake( + &api, + &mut staking_storage, + &block, + &delegator2, + &validator, + coin(200, "TOKEN"), + ) + .unwrap(); + + // wait 1 year + block.time = block.time.plus_seconds(60 * 60 * 24 * 365); + + // delegator1 should now have 100 * 10% - 10% commission = 9 tokens + let rewards = stake + .get_rewards(&store, &block, &delegator1, &validator) + .unwrap() + .unwrap(); + assert_eq!(rewards.amount.u128(), 9); + + // delegator2 should now have 200 * 10% - 10% commission = 18 tokens + let rewards = stake + .get_rewards(&store, &block, &delegator2, &validator) + .unwrap() + .unwrap(); + assert_eq!(rewards.amount.u128(), 18); + + // delegator1 stakes 100 more + let mut staking_storage = prefixed(&mut store, NAMESPACE_STAKING); + stake + .add_stake( + &api, + &mut staking_storage, + &block, + &delegator1, + &validator, + coin(100, "TOKEN"), + ) + .unwrap(); + + // wait another year + block.time = block.time.plus_seconds(60 * 60 * 24 * 365); + + // delegator1 should now have 9 + 200 * 10% - 10% commission = 27 tokens + let rewards = stake + .get_rewards(&store, &block, &delegator1, &validator) + .unwrap() + .unwrap(); + assert_eq!(rewards.amount.u128(), 27); + + // delegator2 should now have 18 + 200 * 10% - 10% commission = 36 tokens + let rewards = stake + .get_rewards(&store, &block, &delegator2, &validator) + .unwrap() + .unwrap(); + assert_eq!(rewards.amount.u128(), 36); + + // delegator2 unstakes 100 (has 100 left after that) + let mut staking_storage = prefixed(&mut store, NAMESPACE_STAKING); + stake + .remove_stake( + &api, + &mut staking_storage, + &block, + &delegator2, + &validator, + coin(100, "TOKEN"), + ) + .unwrap(); + + // and delegator1 withdraws rewards + distr + .execute( + &api, + &mut store, + &router, + &block, + delegator1.clone(), + DistributionMsg::WithdrawDelegatorReward { + validator: validator.to_string(), + }, + ) + .unwrap(); + + let balance: BalanceResponse = from_json( + bank.query( + &api, + &store, + &router.querier(&api, &store, &block), + &block, + BankQuery::Balance { + address: delegator1.to_string(), + denom: "TOKEN".to_string(), + }, + ) + .unwrap(), + ) + .unwrap(); + assert_eq!( + balance.amount.amount.u128(), + 27, + "withdraw should change bank balance" + ); + let rewards = stake + .get_rewards(&store, &block, &delegator1, &validator) + .unwrap() + .unwrap(); + assert_eq!( + rewards.amount.u128(), + 0, + "withdraw should reduce rewards to 0" + ); + + // wait another year + block.time = block.time.plus_seconds(60 * 60 * 24 * 365); + + // delegator1 should now have 0 + 200 * 10% - 10% commission = 18 tokens + let rewards = stake + .get_rewards(&store, &block, &delegator1, &validator) + .unwrap() + .unwrap(); + assert_eq!(rewards.amount.u128(), 18); + + // delegator2 should now have 36 + 100 * 10% - 10% commission = 45 tokens + let rewards = stake + .get_rewards(&store, &block, &delegator2, &validator) + .unwrap() + .unwrap(); + assert_eq!(rewards.amount.u128(), 45); + } + + mod msg { + use cosmwasm_std::{coins, QuerierWrapper}; + use serde::de::DeserializeOwned; + + use super::*; + + // shortens tests a bit + struct TestEnv { + api: MockApi, + store: MockStorage, + router: BasicRouter, + block: BlockInfo, + } + + impl TestEnv { + fn wrap(tuple: (MockApi, MockStorage, BasicRouter, BlockInfo, Addr)) -> (Self, Addr) { + ( + Self { + api: tuple.0, + store: tuple.1, + router: tuple.2, + block: tuple.3, + }, + tuple.4, + ) + } + } + + fn execute_stake( + env: &mut TestEnv, + sender: Addr, + msg: StakingMsg, + ) -> AnyResult { + env.router.staking.execute( + &env.api, + &mut env.store, + &env.router, + &env.block, + sender, + msg, + ) + } + + fn query_stake(env: &TestEnv, msg: StakingQuery) -> AnyResult { + Ok(from_json(env.router.staking.query( + &env.api, + &env.store, + &env.router.querier(&env.api, &env.store, &env.block), + &env.block, + msg, + )?)?) + } + + fn execute_distr( + env: &mut TestEnv, + sender: Addr, + msg: DistributionMsg, + ) -> AnyResult { + env.router.distribution.execute( + &env.api, + &mut env.store, + &env.router, + &env.block, + sender, + msg, + ) + } + + fn query_bank(env: &TestEnv, msg: BankQuery) -> AnyResult { + Ok(from_json(env.router.bank.query( + &env.api, + &env.store, + &env.router.querier(&env.api, &env.store, &env.block), + &env.block, + msg, + )?)?) + } + + fn assert_balances(env: &TestEnv, balances: impl IntoIterator) { + for (addr, amount) in balances { + let balance: BalanceResponse = query_bank( + env, + BankQuery::Balance { + address: addr.to_string(), + denom: "TOKEN".to_string(), + }, + ) + .unwrap(); + assert_eq!(balance.amount.amount.u128(), amount); + } + } + + #[test] + fn execute() { + // test all execute msgs + let (mut test_env, validator1) = + TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + + let delegator1 = test_env.api.addr_make("delegator1"); + let reward_receiver = test_env.api.addr_make("rewardreceiver"); + + // fund delegator1 account + test_env + .router + .bank + .init_balance(&mut test_env.store, &delegator1, vec![coin(1000, "TOKEN")]) + .unwrap(); + + // add second validator + let validator2 = test_env.api.addr_make("validator2"); + test_env + .router + .staking + .add_validator( + &test_env.api, + &mut test_env.store, + &test_env.block, + Validator::new( + validator2.to_string(), + Decimal::zero(), + Decimal::percent(20), + Decimal::percent(1), + ), + ) + .unwrap(); + + // delegate 100 tokens to validator1 + execute_stake( + &mut test_env, + delegator1.clone(), + StakingMsg::Delegate { + validator: validator1.to_string(), + amount: coin(100, "TOKEN"), + }, + ) + .unwrap(); + + // should now have 100 tokens less + assert_balances(&test_env, vec![(delegator1.clone(), 900)]); + + // wait a year + test_env.block.time = test_env.block.time.plus_seconds(60 * 60 * 24 * 365); + + // change the withdrawal address + execute_distr( + &mut test_env, + delegator1.clone(), + DistributionMsg::SetWithdrawAddress { + address: reward_receiver.to_string(), + }, + ) + .unwrap(); + + // withdraw rewards + execute_distr( + &mut test_env, + delegator1.clone(), + DistributionMsg::WithdrawDelegatorReward { + validator: validator1.to_string(), + }, + ) + .unwrap(); + + // withdrawal address received rewards. + assert_balances( + &test_env, + // one year, 10%apr, 10% commission, 100 tokens staked + vec![(reward_receiver, 100 / 10 * 9 / 10)], + ); + + // redelegate to validator2 + execute_stake( + &mut test_env, + delegator1.clone(), + StakingMsg::Redelegate { + src_validator: validator1.to_string(), + dst_validator: validator2.to_string(), + amount: coin(100, "TOKEN"), + }, + ) + .unwrap(); + + // should have same amount as before (rewards receiver received rewards). + assert_balances(&test_env, vec![(delegator1.clone(), 900)]); + + let delegations: AllDelegationsResponse = query_stake( + &test_env, + StakingQuery::AllDelegations { + delegator: delegator1.to_string(), + }, + ) + .unwrap(); + assert_eq!( + delegations.delegations, + [Delegation::new( + delegator1.clone(), + validator2.to_string(), + coin(100, "TOKEN"), + )] + ); + + // undelegate all tokens + execute_stake( + &mut test_env, + delegator1.clone(), + StakingMsg::Undelegate { + validator: validator2.to_string(), + amount: coin(100, "TOKEN"), + }, + ) + .unwrap(); + + // wait for unbonding period (60 seconds in default config) + test_env.block.time = test_env.block.time.plus_seconds(60); + + // need to manually cause queue to get processed + test_env + .router + .staking + .process_queue( + &test_env.api, + &mut test_env.store, + &test_env.router, + &test_env.block, + ) + .unwrap(); + + // check bank balance + assert_balances(&test_env, vec![(delegator1.clone(), 1000)]); + } + + #[test] + fn can_set_withdraw_address() { + let (mut test_env, validator) = + TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + + let delegator = test_env.api.addr_make("delegator"); + let reward_receiver = test_env.api.addr_make("rewardreceiver"); + + test_env + .router + .bank + .init_balance(&mut test_env.store, &delegator, coins(100, "TOKEN")) + .unwrap(); + + // Stake 100 tokens to the validator. + execute_stake( + &mut test_env, + delegator.clone(), + StakingMsg::Delegate { + validator: validator.to_string(), + amount: coin(100, "TOKEN"), + }, + ) + .unwrap(); + + // Change rewards receiver. + execute_distr( + &mut test_env, + delegator.clone(), + DistributionMsg::SetWithdrawAddress { + address: reward_receiver.to_string(), + }, + ) + .unwrap(); + + // A year passes. + test_env.block.time = test_env.block.time.plus_seconds(60 * 60 * 24 * 365); + + // Withdraw rewards to reward receiver. + execute_distr( + &mut test_env, + delegator.clone(), + DistributionMsg::WithdrawDelegatorReward { + validator: validator.to_string(), + }, + ) + .unwrap(); + + // Change reward receiver back to delegator. + execute_distr( + &mut test_env, + delegator.clone(), + DistributionMsg::SetWithdrawAddress { + address: delegator.to_string(), + }, + ) + .unwrap(); + + // Another year passes. + test_env.block.time = test_env.block.time.plus_seconds(60 * 60 * 24 * 365); + + // Withdraw rewards to delegator. + execute_distr( + &mut test_env, + delegator.clone(), + DistributionMsg::WithdrawDelegatorReward { + validator: validator.to_string(), + }, + ) + .unwrap(); + + // one year, 10%apr, 10% commission, 100 tokens staked + let rewards_yr = 100 / 10 * 9 / 10; + + assert_balances( + &test_env, + vec![(reward_receiver, rewards_yr), (delegator, rewards_yr)], + ); + } + + #[test] + fn cannot_steal() { + let (mut test_env, validator1) = + TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + + let delegator1 = test_env.api.addr_make("delegator1"); + + // fund delegator1 account + test_env + .router + .bank + .init_balance(&mut test_env.store, &delegator1, vec![coin(100, "TOKEN")]) + .unwrap(); + + // delegate 100 tokens to validator1 + execute_stake( + &mut test_env, + delegator1.clone(), + StakingMsg::Delegate { + validator: validator1.to_string(), + amount: coin(100, "TOKEN"), + }, + ) + .unwrap(); + + // undelegate more tokens than we have + let e = execute_stake( + &mut test_env, + delegator1.clone(), + StakingMsg::Undelegate { + validator: validator1.to_string(), + amount: coin(200, "TOKEN"), + }, + ) + .unwrap_err(); + + assert_eq!(e.to_string(), "invalid shares amount"); + + // add second validator + let validator2 = test_env.api.addr_make("validator2"); + test_env + .router + .staking + .add_validator( + &test_env.api, + &mut test_env.store, + &test_env.block, + Validator::new( + validator2.to_string(), + Decimal::zero(), + Decimal::percent(20), + Decimal::percent(1), + ), + ) + .unwrap(); + + // redelegate more tokens than we have + let e = execute_stake( + &mut test_env, + delegator1.clone(), + StakingMsg::Redelegate { + src_validator: validator1.to_string(), + dst_validator: validator2.to_string(), + amount: coin(200, "TOKEN"), + }, + ) + .unwrap_err(); + assert_eq!(e.to_string(), "invalid shares amount"); + + // undelegate from non-existing delegation + let e = execute_stake( + &mut test_env, + delegator1.clone(), + StakingMsg::Undelegate { + validator: validator2.to_string(), + amount: coin(100, "TOKEN"), + }, + ) + .unwrap_err(); + assert_eq!( + e.to_string(), + "no delegation for (address, validator) tuple" + ); + } + + #[test] + fn denom_validation() { + let (mut test_env, validator_addr) = + TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + + let delegator_addr = test_env.api.addr_make("delegator"); + + // fund delegator1 account + test_env + .router + .bank + .init_balance( + &mut test_env.store, + &delegator_addr, + vec![coin(100, "FAKE")], + ) + .unwrap(); + + // try to delegate 100 to validator + let e = execute_stake( + &mut test_env, + delegator_addr.clone(), + StakingMsg::Delegate { + validator: validator_addr.to_string(), + amount: coin(100, "FAKE"), + }, + ) + .unwrap_err(); + + assert_eq!( + e.to_string(), + "cannot delegate coins of denominator FAKE, only of TOKEN", + ); + } + + #[test] + fn cannot_slash_nonexistent() { + let (mut test_env, _) = + TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + + let delegator = test_env.api.addr_make("delegator"); + let non_existing_validator = test_env.api.addr_make("nonexistingvaloper"); + + // fund delegator1 account + test_env + .router + .bank + .init_balance(&mut test_env.store, &delegator, vec![coin(100, "FAKE")]) + .unwrap(); + + // try to delegate 100 to validator1 + let e = test_env + .router + .staking + .sudo( + &test_env.api, + &mut test_env.store, + &test_env.router, + &test_env.block, + StakingSudo::Slash { + validator: non_existing_validator.to_string(), + percentage: Decimal::percent(50), + }, + ) + .unwrap_err(); + assert_eq!(e.to_string(), "validator does not exist"); + } + + #[test] + fn non_existent_validator() { + let (mut test_env, _) = + TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + + let delegator = test_env.api.addr_make("delegator1"); + let validator = test_env.api.addr_make("testvaloper2"); + + // init balances + test_env + .router + .bank + .init_balance(&mut test_env.store, &delegator, vec![coin(100, "TOKEN")]) + .unwrap(); + + // try to delegate + let err = execute_stake( + &mut test_env, + delegator.clone(), + StakingMsg::Delegate { + validator: validator.to_string(), + amount: coin(100, "TOKEN"), + }, + ) + .unwrap_err(); + assert_eq!(err.to_string(), "validator does not exist"); + + // try to undelegate + let err = execute_stake( + &mut test_env, + delegator.clone(), + StakingMsg::Undelegate { + validator: validator.to_string(), + amount: coin(100, "TOKEN"), + }, + ) + .unwrap_err(); + assert_eq!(err.to_string(), "validator does not exist"); + } + + #[test] + fn zero_staking_forbidden() { + let (mut test_env, validator) = + TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + + let delegator_addr = test_env.api.addr_make("delegator"); + + // delegate 0 + let err = execute_stake( + &mut test_env, + delegator_addr.clone(), + StakingMsg::Delegate { + validator: validator.to_string(), + amount: coin(0, "TOKEN"), + }, + ) + .unwrap_err(); + assert_eq!(err.to_string(), "invalid delegation amount"); + + // undelegate 0 + let err = execute_stake( + &mut test_env, + delegator_addr, + StakingMsg::Undelegate { + validator: validator.to_string(), + amount: coin(0, "TOKEN"), + }, + ) + .unwrap_err(); + assert_eq!(err.to_string(), "invalid shares amount"); + } + + #[test] + fn query_staking() { + // run all staking queries + let (mut test_env, validator1) = + TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + let delegator1 = test_env.api.addr_make("delegator1"); + let delegator2 = test_env.api.addr_make("delegator2"); + let validator2 = test_env.api.addr_make("testvaloper2"); + let not_validator = test_env.api.addr_make("notvaloper"); + + // init balances + test_env + .router + .bank + .init_balance(&mut test_env.store, &delegator1, vec![coin(260, "TOKEN")]) + .unwrap(); + test_env + .router + .bank + .init_balance(&mut test_env.store, &delegator2, vec![coin(150, "TOKEN")]) + .unwrap(); + + // add another validator + let valoper2 = Validator::new( + validator2.to_string(), + Decimal::percent(0), + Decimal::percent(1), + Decimal::percent(1), + ); + test_env + .router + .staking + .add_validator( + &test_env.api, + &mut test_env.store, + &test_env.block, + valoper2.clone(), + ) + .unwrap(); + + // query validators + let valoper1: ValidatorResponse = query_stake( + &test_env, + StakingQuery::Validator { + address: validator1.to_string(), + }, + ) + .unwrap(); + let validators: AllValidatorsResponse = + query_stake(&test_env, StakingQuery::AllValidators {}).unwrap(); + assert_eq!( + validators.validators, + [valoper1.validator.unwrap(), valoper2] + ); + // query non-existent validator + let response = query_stake::( + &test_env, + StakingQuery::Validator { + address: not_validator.to_string(), + }, + ) + .unwrap(); + assert_eq!(response.validator, None); + + // query bonded denom + let response: BondedDenomResponse = + query_stake(&test_env, StakingQuery::BondedDenom {}).unwrap(); + assert_eq!(response.denom, "TOKEN"); + + // delegate some tokens with delegator1 and delegator2 + execute_stake( + &mut test_env, + delegator1.clone(), + StakingMsg::Delegate { + validator: validator1.to_string(), + amount: coin(100, "TOKEN"), + }, + ) + .unwrap(); + execute_stake( + &mut test_env, + delegator1.clone(), + StakingMsg::Delegate { + validator: validator2.to_string(), + amount: coin(160, "TOKEN"), + }, + ) + .unwrap(); + execute_stake( + &mut test_env, + delegator2.clone(), + StakingMsg::Delegate { + validator: validator1.to_string(), + amount: coin(150, "TOKEN"), + }, + ) + .unwrap(); + // unstake some again + execute_stake( + &mut test_env, + delegator1.clone(), + StakingMsg::Undelegate { + validator: validator1.to_string(), + amount: coin(50, "TOKEN"), + }, + ) + .unwrap(); + execute_stake( + &mut test_env, + delegator2.clone(), + StakingMsg::Undelegate { + validator: validator1.to_string(), + amount: coin(50, "TOKEN"), + }, + ) + .unwrap(); + + // query all delegations + let response1: AllDelegationsResponse = query_stake( + &test_env, + StakingQuery::AllDelegations { + delegator: delegator1.to_string(), + }, + ) + .unwrap(); + assert_eq!( + response1.delegations, + vec![ + Delegation::new( + delegator1.clone(), + validator1.to_string(), + coin(50, "TOKEN"), + ), + Delegation::new( + delegator1.clone(), + validator2.to_string(), + coin(160, "TOKEN"), + ), + ] + ); + let response2: DelegationResponse = query_stake( + &test_env, + StakingQuery::Delegation { + delegator: delegator2.to_string(), + validator: validator1.to_string(), + }, + ) + .unwrap(); + assert_eq!( + response2.delegation.unwrap(), + FullDelegation::new( + delegator2.clone(), + validator1.to_string(), + coin(100, "TOKEN"), + coin(100, "TOKEN"), + vec![], + ), + ); + } + + #[test] + fn delegation_queries_unbonding() { + // run all staking queries + let (mut test_env, validator) = + TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + let delegator1 = test_env.api.addr_make("delegator1"); + let delegator2 = test_env.api.addr_make("delegator2"); + + // init balances + test_env + .router + .bank + .init_balance(&mut test_env.store, &delegator1, vec![coin(100, "TOKEN")]) + .unwrap(); + test_env + .router + .bank + .init_balance(&mut test_env.store, &delegator2, vec![coin(150, "TOKEN")]) + .unwrap(); + + // delegate some tokens with delegator1 and delegator2 + execute_stake( + &mut test_env, + delegator1.clone(), + StakingMsg::Delegate { + validator: validator.to_string(), + amount: coin(100, "TOKEN"), + }, + ) + .unwrap(); + execute_stake( + &mut test_env, + delegator2.clone(), + StakingMsg::Delegate { + validator: validator.to_string(), + amount: coin(150, "TOKEN"), + }, + ) + .unwrap(); + // unstake some of delegator1's stake + execute_stake( + &mut test_env, + delegator1.clone(), + StakingMsg::Undelegate { + validator: validator.to_string(), + amount: coin(50, "TOKEN"), + }, + ) + .unwrap(); + // unstake all of delegator2's stake + execute_stake( + &mut test_env, + delegator2.clone(), + StakingMsg::Undelegate { + validator: validator.to_string(), + amount: coin(150, "TOKEN"), + }, + ) + .unwrap(); + + // query all delegations + let response1: AllDelegationsResponse = query_stake( + &test_env, + StakingQuery::AllDelegations { + delegator: delegator1.to_string(), + }, + ) + .unwrap(); + assert_eq!( + response1.delegations, + vec![Delegation::new( + delegator1.clone(), + validator.to_string(), + coin(50, "TOKEN"), + )] + ); + let response2: DelegationResponse = query_stake( + &test_env, + StakingQuery::Delegation { + delegator: delegator2.to_string(), + validator: validator.to_string(), + }, + ) + .unwrap(); + assert_eq!(response2.delegation, None); + + // unstake rest of delegator1's stake in two steps + execute_stake( + &mut test_env, + delegator1.clone(), + StakingMsg::Undelegate { + validator: validator.to_string(), + amount: coin(25, "TOKEN"), + }, + ) + .unwrap(); + test_env.block.time = test_env.block.time.plus_seconds(10); + execute_stake( + &mut test_env, + delegator1.clone(), + StakingMsg::Undelegate { + validator: validator.to_string(), + amount: coin(25, "TOKEN"), + }, + ) + .unwrap(); + + // query all delegations again + let response1: DelegationResponse = query_stake( + &test_env, + StakingQuery::Delegation { + delegator: delegator1.to_string(), + validator: validator.to_string(), + }, + ) + .unwrap(); + let response2: AllDelegationsResponse = query_stake( + &test_env, + StakingQuery::AllDelegations { + delegator: delegator1.to_string(), + }, + ) + .unwrap(); + assert_eq!( + response1.delegation, None, + "delegator1 should have no delegations left" + ); + assert_eq!(response2.delegations, vec![]); + } + + #[test] + fn partial_unbonding_reduces_stake() { + let (mut test_env, validator) = + TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + let delegator = test_env.api.addr_make("delegator1"); + + // init balance + test_env + .router + .bank + .init_balance(&mut test_env.store, &delegator, vec![coin(100, "TOKEN")]) + .unwrap(); + + // delegate all tokens + execute_stake( + &mut test_env, + delegator.clone(), + StakingMsg::Delegate { + validator: validator.to_string(), + amount: coin(100, "TOKEN"), + }, + ) + .unwrap(); + // unstake in multiple steps + execute_stake( + &mut test_env, + delegator.clone(), + StakingMsg::Undelegate { + validator: validator.to_string(), + amount: coin(50, "TOKEN"), + }, + ) + .unwrap(); + test_env.block.time = test_env.block.time.plus_seconds(10); + execute_stake( + &mut test_env, + delegator.clone(), + StakingMsg::Undelegate { + validator: validator.to_string(), + amount: coin(30, "TOKEN"), + }, + ) + .unwrap(); + test_env.block.time = test_env.block.time.plus_seconds(10); + execute_stake( + &mut test_env, + delegator.clone(), + StakingMsg::Undelegate { + validator: validator.to_string(), + amount: coin(20, "TOKEN"), + }, + ) + .unwrap(); + + // wait for first unbonding to complete (but not the others) and process queue + test_env.block.time = test_env.block.time.plus_seconds(40); + test_env + .router + .staking + .process_queue( + &test_env.api, + &mut test_env.store, + &test_env.router, + &test_env.block, + ) + .unwrap(); + + // query delegations + // we now have 0 stake, 50 unbonding and 50 completed unbonding + let response1: DelegationResponse = query_stake( + &test_env, + StakingQuery::Delegation { + delegator: delegator.to_string(), + validator: validator.to_string(), + }, + ) + .unwrap(); + let response2: AllDelegationsResponse = query_stake( + &test_env, + StakingQuery::AllDelegations { + delegator: delegator.to_string(), + }, + ) + .unwrap(); + assert_eq!(response1.delegation, None); + assert_eq!(response2.delegations, vec![]); + + // wait for the rest to complete + test_env.block.time = test_env.block.time.plus_seconds(20); + test_env + .router + .staking + .process_queue( + &test_env.api, + &mut test_env.store, + &test_env.router, + &test_env.block, + ) + .unwrap(); + + // query delegations again + let response1: DelegationResponse = query_stake( + &test_env, + StakingQuery::Delegation { + delegator: delegator.to_string(), + validator: validator.to_string(), + }, + ) + .unwrap(); + let response2: AllDelegationsResponse = query_stake( + &test_env, + StakingQuery::AllDelegations { + delegator: delegator.to_string(), + }, + ) + .unwrap(); + assert_eq!( + response1.delegation, None, + "delegator should have nothing left" + ); + assert!(response2.delegations.is_empty()); + } + + #[test] + fn delegations_slashed() { + // run all staking queries + let (mut test_env, validator) = + TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::percent(10))); + let delegator = test_env.api.addr_make("delegator"); + + // init balance + test_env + .router + .bank + .init_balance(&mut test_env.store, &delegator, vec![coin(333, "TOKEN")]) + .unwrap(); + + // delegate some tokens + execute_stake( + &mut test_env, + delegator.clone(), + StakingMsg::Delegate { + validator: validator.to_string(), + amount: coin(333, "TOKEN"), + }, + ) + .unwrap(); + // unstake some + execute_stake( + &mut test_env, + delegator.clone(), + StakingMsg::Undelegate { + validator: validator.to_string(), + amount: coin(111, "TOKEN"), + }, + ) + .unwrap(); + + // slash validator + test_env + .router + .staking + .sudo( + &test_env.api, + &mut test_env.store, + &test_env.router, + &test_env.block, + StakingSudo::Slash { + validator: validator.to_string(), + percentage: Decimal::percent(50), + }, + ) + .unwrap(); + + // query all delegations + let response1: AllDelegationsResponse = query_stake( + &test_env, + StakingQuery::AllDelegations { + delegator: delegator.to_string(), + }, + ) + .unwrap(); + assert_eq!( + response1.delegations[0], + Delegation::new(delegator.clone(), validator.to_string(), coin(111, "TOKEN"),) + ); + + // wait until unbonding is complete and check if amount was slashed + test_env.block.time = test_env.block.time.plus_seconds(60); + test_env + .router + .staking + .process_queue( + &test_env.api, + &mut test_env.store, + &test_env.router, + &test_env.block, + ) + .unwrap(); + let balance = QuerierWrapper::::new(&test_env.router.querier( + &test_env.api, + &test_env.store, + &test_env.block, + )) + .query_balance(delegator, "TOKEN") + .unwrap(); + assert_eq!(balance.amount.u128(), 55); + } + + #[test] + fn rewards_initial_wait() { + let (mut test_env, validator) = + TestEnv::wrap(setup_test_env(Decimal::percent(10), Decimal::zero())); + let delegator = test_env.api.addr_make("delegator"); + + // init balance + test_env + .router + .bank + .init_balance(&mut test_env.store, &delegator, vec![coin(100, "TOKEN")]) + .unwrap(); + + // wait a year before staking + const YEAR: u64 = 60 * 60 * 24 * 365; + test_env.block.time = test_env.block.time.plus_seconds(YEAR); + + // delegate some tokens + execute_stake( + &mut test_env, + delegator.clone(), + StakingMsg::Delegate { + validator: validator.to_string(), + amount: coin(100, "TOKEN"), + }, + ) + .unwrap(); + + // wait another year + test_env.block.time = test_env.block.time.plus_seconds(YEAR); + + // query rewards + let response: DelegationResponse = query_stake( + &test_env, + StakingQuery::Delegation { + delegator: delegator.to_string(), + validator: validator.to_string(), + }, + ) + .unwrap(); + assert_eq!( + response.delegation.unwrap().accumulated_rewards, + vec![coin(10, "TOKEN")] // 10% of 100 + ); + } } } diff --git a/src/stargate.rs b/src/stargate.rs new file mode 100644 index 00000000..7228d8a4 --- /dev/null +++ b/src/stargate.rs @@ -0,0 +1,145 @@ +//! # Handler for `CosmosMsg::Stargate`, `CosmosMsg::Any`, `QueryRequest::Stargate` and `QueryRequest::Grpc` messages + +use crate::error::AnyResult; +use crate::{AppResponse, CosmosRouter}; +use anyhow::bail; +use cosmwasm_std::{ + to_json_binary, Addr, AnyMsg, Api, Binary, BlockInfo, CustomMsg, CustomQuery, Empty, GrpcQuery, + Querier, Storage, +}; +use serde::de::DeserializeOwned; + +/// Interface of handlers for processing `Stargate`/`Any` message variants +/// and `Stargate`/`Grpc` queries. +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) + } + + /// Processes `CosmosMsg::Any` message variant. + fn execute_any( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + sender: Addr, + msg: AnyMsg, + ) -> AnyResult + where + ExecC: CustomMsg + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + bail!("Unexpected any execute: msg={:?} from {}", msg, sender) + } + + /// Processes `QueryRequest::Grpc` query. + fn query_grpc( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + request: GrpcQuery, + ) -> AnyResult { + bail!("Unexpected grpc query: request={:?}", request) + } +} + +/// Always failing handler for `Stargate`/`Any` message variants and `Stargate`/`Grpc` queries. +pub struct StargateFailing; + +impl Stargate for StargateFailing {} + +/// Always accepting handler for `Stargate`/`Any` message variants and `Stargate`/`Grpc` 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_json_binary(&Empty {}).map_err(Into::into) + } + + fn execute_any( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + _sender: Addr, + _msg: AnyMsg, + ) -> AnyResult + where + ExecC: CustomMsg + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + Ok(AppResponse::default()) + } + + fn query_grpc( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + _request: GrpcQuery, + ) -> AnyResult { + Ok(Binary::default()) + } +} diff --git a/src/test_helpers/caller.rs b/src/test_helpers/caller.rs index c283cda5..1d50a62a 100644 --- a/src/test_helpers/caller.rs +++ b/src/test_helpers/caller.rs @@ -1,9 +1,7 @@ use crate::{Contract, ContractWrapper}; use cosmwasm_std::{ - Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError, SubMsg, WasmMsg, + Binary, CustomMsg, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError, SubMsg, WasmMsg, }; -use schemars::JsonSchema; -use std::fmt::Debug; fn instantiate( _deps: DepsMut, @@ -33,7 +31,7 @@ fn query(_deps: Deps, _env: Env, _msg: Empty) -> Result { pub fn contract() -> Box> where - C: Clone + Debug + PartialEq + JsonSchema + 'static, + C: CustomMsg + 'static, { let contract = ContractWrapper::new_with_empty(execute, instantiate, query); Box::new(contract) diff --git a/src/test_helpers/echo.rs b/src/test_helpers/echo.rs index 02ab2696..884df65c 100644 --- a/src/test_helpers/echo.rs +++ b/src/test_helpers/echo.rs @@ -1,12 +1,12 @@ //! Very simple echoing contract which just returns incoming string if any, //! but performing sub call of given message to test response. //! -//! Additionally it bypasses all events and attributes send to it. +//! Additionally, it bypasses all events and attributes send to it. use crate::{Contract, ContractWrapper}; use cosmwasm_std::{ - to_json_binary, Attribute, Binary, Deps, DepsMut, Empty, Env, Event, MessageInfo, Reply, - Response, StdError, SubMsg, SubMsgResponse, SubMsgResult, + to_json_binary, Attribute, Binary, CustomMsg, Deps, DepsMut, Empty, Env, Event, MessageInfo, + Reply, Response, StdError, SubMsg, SubMsgResponse, SubMsgResult, }; use cw_utils::{parse_execute_response_data, parse_instantiate_response_data}; use derivative::Derivative; @@ -87,7 +87,7 @@ fn query(_deps: Deps, _env: Env, msg: Empty) -> Result { to_json_binary(&msg) } -#[allow(clippy::unnecessary_wraps)] +#[allow(clippy::unnecessary_wraps, deprecated)] fn reply(_deps: DepsMut, _env: Env, msg: Reply) -> Result, StdError> where ExecC: Debug + PartialEq + Clone + JsonSchema + 'static, @@ -98,6 +98,7 @@ where result: SubMsgResult::Ok(SubMsgResponse { data: Some(data), .. }), + .. } = msg { // We parse out the WasmMsg::Execute wrapper... @@ -130,7 +131,7 @@ pub fn contract() -> Box> { pub fn custom_contract() -> Box> where - C: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + C: CustomMsg + DeserializeOwned + 'static, { let contract = ContractWrapper::new(execute::, instantiate::, query).with_reply(reply::); diff --git a/src/test_helpers/error.rs b/src/test_helpers/error.rs index 033853de..1654440a 100644 --- a/src/test_helpers/error.rs +++ b/src/test_helpers/error.rs @@ -1,7 +1,5 @@ use crate::{Contract, ContractWrapper}; -use cosmwasm_std::{Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError}; -use schemars::JsonSchema; -use std::fmt::Debug; +use cosmwasm_std::{Binary, CustomMsg, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError}; fn instantiate_err( _deps: DepsMut, @@ -36,7 +34,7 @@ fn query(_deps: Deps, _env: Env, _msg: Empty) -> Result { pub fn contract(instantiable: bool) -> Box> where - C: Clone + Debug + PartialEq + JsonSchema + 'static, + C: CustomMsg + 'static, { let contract = if instantiable { ContractWrapper::new_with_empty(execute, instantiate_ok, query) diff --git a/src/test_helpers/gov.rs b/src/test_helpers/gov.rs new file mode 100644 index 00000000..0c885c3a --- /dev/null +++ b/src/test_helpers/gov.rs @@ -0,0 +1,27 @@ +use crate::{Contract, ContractWrapper}; +use cosmwasm_std::{ + Binary, CosmosMsg, Deps, DepsMut, Empty, Env, GovMsg, MessageInfo, Response, StdResult, +}; + +fn instantiate(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { + Ok(Response::new()) +} + +fn execute(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { + let msg: CosmosMsg = GovMsg::Vote { + proposal_id: 1, + option: cosmwasm_std::VoteOption::No, + } + .into(); + let resp = Response::new().add_message(msg); + Ok(resp) +} + +fn query(_deps: Deps, _env: Env, _msg: Empty) -> StdResult { + Ok(Binary::default()) +} + +pub fn contract() -> Box> { + let contract = ContractWrapper::new(execute, instantiate, query); + Box::new(contract) +} diff --git a/src/test_helpers/hackatom.rs b/src/test_helpers/hackatom.rs index 394c7351..95df71ba 100644 --- a/src/test_helpers/hackatom.rs +++ b/src/test_helpers/hackatom.rs @@ -2,10 +2,10 @@ use crate::{Contract, ContractWrapper}; use cosmwasm_std::{ - to_json_binary, BankMsg, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError, + to_json_binary, BankMsg, Binary, CustomMsg, Deps, DepsMut, Empty, Env, MessageInfo, Response, + StdError, }; use cw_storage_plus::Item; -use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::fmt::Debug; @@ -16,7 +16,7 @@ pub struct InstantiateMsg { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MigrateMsg { - // just use some other string so we see there are other types + // just use some other string, so we see there are other types pub new_guy: String, } @@ -77,7 +77,7 @@ pub fn contract() -> Box> { #[allow(dead_code)] pub fn custom_contract() -> Box> where - C: Clone + Debug + PartialEq + JsonSchema + 'static, + C: CustomMsg + 'static, { let contract = ContractWrapper::new_with_empty(execute, instantiate, query).with_migrate_empty(migrate); diff --git a/src/test_helpers/ibc.rs b/src/test_helpers/ibc.rs new file mode 100644 index 00000000..402edda6 --- /dev/null +++ b/src/test_helpers/ibc.rs @@ -0,0 +1,26 @@ +use crate::{Contract, ContractWrapper}; +use cosmwasm_std::{ + Binary, CosmosMsg, Deps, DepsMut, Empty, Env, IbcMsg, MessageInfo, Response, StdResult, +}; + +fn instantiate(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { + Ok(Response::new()) +} + +fn execute(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { + let msg: CosmosMsg = IbcMsg::CloseChannel { + channel_id: "channel".to_string(), + } + .into(); + let resp = Response::new().add_message(msg); + Ok(resp) +} + +fn query(_deps: Deps, _env: Env, _msg: Empty) -> StdResult { + Ok(Binary::default()) +} + +pub fn contract() -> Box> { + let contract = ContractWrapper::new(execute, instantiate, query); + Box::new(contract) +} diff --git a/src/test_helpers/mod.rs b/src/test_helpers/mod.rs index f67efbc5..d6ee1adc 100644 --- a/src/test_helpers/mod.rs +++ b/src/test_helpers/mod.rs @@ -1,5 +1,6 @@ #![cfg(test)] +use cosmwasm_std::CustomMsg; use cw_storage_plus::Item; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -7,7 +8,9 @@ use serde::{Deserialize, Serialize}; pub mod caller; pub mod echo; pub mod error; +pub mod gov; pub mod hackatom; +pub mod ibc; pub mod payout; pub mod reflect; pub mod stargate; @@ -15,10 +18,12 @@ pub mod stargate; /// Custom message for testing purposes. #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename = "snake_case")] -pub enum CustomMsg { +pub enum CustomHelperMsg { SetName { name: String }, SetAge { age: u32 }, } +impl CustomMsg for CustomHelperMsg {} + /// Persisted counter for testing purposes. pub const COUNT: Item = Item::new("count"); diff --git a/src/test_helpers/payout.rs b/src/test_helpers/payout.rs index a1d13ea2..159f6cea 100644 --- a/src/test_helpers/payout.rs +++ b/src/test_helpers/payout.rs @@ -1,11 +1,10 @@ use crate::test_helpers::COUNT; use crate::{Contract, ContractWrapper}; use cosmwasm_std::{ - to_json_binary, BankMsg, Binary, Coin, Deps, DepsMut, Empty, Env, MessageInfo, Response, - StdError, + to_json_binary, BankMsg, Binary, Coin, CustomMsg, Deps, DepsMut, Empty, Env, MessageInfo, + Response, StdError, }; use cw_storage_plus::Item; -use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::fmt::Debug; @@ -76,7 +75,7 @@ fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result { pub fn contract() -> Box> where - C: Clone + Debug + PartialEq + JsonSchema + 'static, + C: CustomMsg + 'static, { let contract = ContractWrapper::new_with_empty(execute, instantiate, query).with_sudo_empty(sudo); diff --git a/src/test_helpers/reflect.rs b/src/test_helpers/reflect.rs index c7b37407..41b4396e 100644 --- a/src/test_helpers/reflect.rs +++ b/src/test_helpers/reflect.rs @@ -1,4 +1,4 @@ -use crate::test_helpers::{payout, CustomMsg, COUNT}; +use crate::test_helpers::{payout, CustomHelperMsg, COUNT}; use crate::{Contract, ContractWrapper}; use cosmwasm_std::{ to_json_binary, Binary, Deps, DepsMut, Empty, Env, Event, MessageInfo, Reply, Response, @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Message { - pub messages: Vec>, + pub messages: Vec>, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -25,7 +25,7 @@ fn instantiate( _env: Env, _info: MessageInfo, _msg: Empty, -) -> Result, StdError> { +) -> Result, StdError> { COUNT.save(deps.storage, &0)?; Ok(Response::default()) } @@ -35,7 +35,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)) @@ -55,7 +55,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") @@ -64,7 +64,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/src/test_helpers/stargate.rs b/src/test_helpers/stargate.rs index 0a31efcb..a4165354 100644 --- a/src/test_helpers/stargate.rs +++ b/src/test_helpers/stargate.rs @@ -1,35 +1,19 @@ use crate::{Contract, ContractWrapper}; use cosmwasm_std::{ - Binary, CosmosMsg, Deps, DepsMut, Empty, Env, GovMsg, IbcMsg, MessageInfo, Response, StdResult, + Binary, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdResult, }; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum ExecMsg { - Ibc {}, - Gov {}, -} fn instantiate(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { Ok(Response::new()) } -fn execute(_deps: DepsMut, _env: Env, _info: MessageInfo, msg: ExecMsg) -> StdResult { - let msg: CosmosMsg = if let ExecMsg::Ibc {} = msg { - IbcMsg::CloseChannel { - channel_id: "channel".to_string(), - } - .into() - } else { - GovMsg::Vote { - proposal_id: 1, - vote: cosmwasm_std::VoteOption::No, - } - .into() +fn execute(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult { + #[allow(deprecated)] + let msg = CosmosMsg::Stargate { + type_url: "/this.is.a.stargate.test.helper".to_string(), + value: Default::default(), }; - - let resp = Response::new().add_message(msg); - Ok(resp) + Ok(Response::new().add_message(msg)) } fn query(_deps: Deps, _env: Env, _msg: Empty) -> StdResult { diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 2a190c34..2f5d2092 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -2,5 +2,7 @@ mod test_app; mod test_custom_handler; +mod test_error; mod test_gov; mod test_ibc; +mod test_stargate; diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index dad2e1b6..7dc5b413 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -1,20 +1,20 @@ -use crate::app::no_init; use crate::custom_handler::CachingCustomHandler; use crate::error::{bail, AnyResult}; use crate::test_helpers::echo::EXECUTE_REPLY_BASE_ID; -use crate::test_helpers::{caller, echo, error, hackatom, payout, reflect, CustomMsg}; +use crate::test_helpers::{caller, echo, error, hackatom, payout, reflect, CustomHelperMsg}; use crate::transactions::{transactional, StorageTransaction}; use crate::wasm::ContractData; -use crate::AppBuilder; use crate::{ - custom_app, next_block, App, AppResponse, Bank, CosmosRouter, Distribution, Executor, Module, - Router, Staking, Wasm, WasmSudo, + custom_app, next_block, no_init, App, AppResponse, Bank, CosmosRouter, Distribution, Executor, + Module, Router, Staking, Wasm, WasmSudo, }; +use crate::{AppBuilder, IntoAddr}; use cosmwasm_std::testing::{mock_env, MockQuerier}; use cosmwasm_std::{ coin, coins, from_json, to_json_binary, Addr, AllBalanceResponse, Api, Attribute, BankMsg, - BankQuery, Binary, BlockInfo, Coin, CosmosMsg, CustomQuery, Empty, Event, OverflowError, - OverflowOperation, Querier, Reply, StdError, StdResult, Storage, SubMsg, WasmMsg, + BankQuery, Binary, BlockInfo, Coin, CosmosMsg, CustomMsg, CustomQuery, Empty, Event, + OverflowError, OverflowOperation, Querier, Reply, StdError, StdResult, Storage, SubMsg, + WasmMsg, }; use cw_storage_plus::Item; use cw_utils::parse_instantiate_response_data; @@ -29,7 +29,7 @@ fn get_balance( addr: &Addr, ) -> Vec where - CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, @@ -40,14 +40,14 @@ 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, ) -> Vec where - CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema, + CustomT::ExecT: CustomMsg, CustomT::QueryT: CustomQuery + DeserializeOwned, WasmT: Wasm, BankT: Bank, @@ -73,7 +73,7 @@ fn query_app( rcpt: &Addr, ) -> Vec where - CustomT::ExecT: Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static, + CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, WasmT: Wasm, BankT: Bank, @@ -91,35 +91,39 @@ where val.amount } +/// Utility function for generating user addresses. +fn addr_make(addr: &str) -> Addr { + addr.into_addr() +} + #[test] fn update_block() { let mut app = App::default(); - let BlockInfo { time, height, .. } = app.block_info(); app.update_block(next_block); - assert_eq!(time.plus_seconds(5), app.block_info().time); assert_eq!(height + 1, app.block_info().height); } #[test] fn multi_level_bank_cache() { + // prepare user addresses + let owner_addr = addr_make("owner"); + let recipient_addr = addr_make("recipient"); + // set personal balance - let owner = Addr::unchecked("owner"); - let rcpt = Addr::unchecked("recipient"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; - let mut app = App::new(|router, _, storage| { router .bank - .init_balance(storage, &owner, init_funds) + .init_balance(storage, &owner_addr, init_funds) .unwrap(); }); // cache 1 - send some tokens let mut cache = StorageTransaction::new(app.storage()); let msg = BankMsg::Send { - to_address: rcpt.clone().into(), + to_address: recipient_addr.clone().into(), amount: coins(25, "eth"), }; app.router() @@ -127,31 +131,31 @@ fn multi_level_bank_cache() { app.api(), &mut cache, &app.block_info(), - owner.clone(), + owner_addr.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, &recipient_addr); assert_eq!(coins(25, "eth"), cached_rcpt); - let router_rcpt = query_app(&app, &rcpt); + let router_rcpt = query_app(&app, &recipient_addr); assert_eq!(router_rcpt, vec![]); // now, second level cache transactional(&mut cache, |cache2, read| { let msg = BankMsg::Send { - to_address: rcpt.clone().into(), + to_address: recipient_addr.clone().into(), amount: coins(12, "eth"), }; app.router() - .execute(app.api(), cache2, &app.block_info(), owner, msg.into()) + .execute(app.api(), cache2, &app.block_info(), owner_addr, 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, &recipient_addr); 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, &recipient_addr); assert_eq!(coins(37, "eth"), cached2_rcpt); Ok(()) }) @@ -160,7 +164,7 @@ fn multi_level_bank_cache() { // apply first to router cache.prepare().commit(app.storage_mut()); - let committed = query_app(&app, &rcpt); + let committed = query_app(&app, &recipient_addr); assert_eq!(coins(37, "eth"), committed); } @@ -186,61 +190,64 @@ fn duplicate_contract_code() { #[test] fn send_tokens() { - let owner = Addr::unchecked("owner"); - let rcpt = Addr::unchecked("receiver"); + // prepare user addresses + let owner_addr = addr_make("owner"); + let recipient_addr = addr_make("recipient"); + + // set personal balance let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let rcpt_funds = vec![coin(5, "btc")]; - let mut app = App::new(|router, _, storage| { // initialization moved to App construction router .bank - .init_balance(storage, &owner, init_funds) + .init_balance(storage, &owner_addr, init_funds) .unwrap(); router .bank - .init_balance(storage, &rcpt, rcpt_funds) + .init_balance(storage, &recipient_addr, rcpt_funds) .unwrap(); }); // send both tokens let to_send = vec![coin(30, "eth"), coin(5, "btc")]; let msg: CosmosMsg = BankMsg::Send { - to_address: rcpt.clone().into(), + to_address: recipient_addr.clone().into(), amount: to_send, } .into(); - app.execute(owner.clone(), msg.clone()).unwrap(); - let rich = get_balance(&app, &owner); + app.execute(owner_addr.clone(), msg.clone()).unwrap(); + let rich = get_balance(&app, &owner_addr); assert_eq!(vec![coin(15, "btc"), coin(70, "eth")], rich); - let poor = get_balance(&app, &rcpt); + let poor = get_balance(&app, &recipient_addr); assert_eq!(vec![coin(10, "btc"), coin(30, "eth")], poor); // can send from other account (but funds will be deducted from sender) - app.execute(rcpt.clone(), msg).unwrap(); + app.execute(recipient_addr.clone(), msg).unwrap(); // cannot send too much let msg = BankMsg::Send { - to_address: rcpt.into(), + to_address: recipient_addr.into(), amount: coins(20, "btc"), } .into(); - app.execute(owner.clone(), msg).unwrap_err(); + app.execute(owner_addr.clone(), msg).unwrap_err(); - let rich = get_balance(&app, &owner); + let rich = get_balance(&app, &owner_addr); assert_eq!(vec![coin(15, "btc"), coin(70, "eth")], rich); } #[test] fn simple_contract() { + // prepare user addresses + let owner_addr = addr_make("owner"); + // set personal balance - let owner = Addr::unchecked("owner"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; - let mut app = App::new(|router, _, storage| { router .bank - .init_balance(storage, &owner, init_funds) + .init_balance(storage, &owner_addr, init_funds) .unwrap(); }); @@ -253,7 +260,7 @@ fn simple_contract() { let contract_addr = app .instantiate_contract( code_id, - owner.clone(), + owner_addr.clone(), &msg, &coins(23, "eth"), "Payout", @@ -266,7 +273,7 @@ fn simple_contract() { contract_data, ContractData { code_id, - creator: owner.clone(), + creator: owner_addr.clone(), admin: None, label: "Payout".to_owned(), created: app.block_info().height @@ -274,20 +281,20 @@ fn simple_contract() { ); // sender funds deducted - let sender = get_balance(&app, &owner); + let sender = get_balance(&app, &owner_addr); assert_eq!(sender, vec![coin(20, "btc"), coin(77, "eth")]); // get contract address, has funds let funds = get_balance(&app, &contract_addr); assert_eq!(funds, coins(23, "eth")); // create empty account - let random = Addr::unchecked("random"); - let funds = get_balance(&app, &random); + let random_addr = app.api().addr_make("random"); + let funds = get_balance(&app, &random_addr); assert_eq!(funds, vec![]); // do one payout and see money coming in let res = app - .execute_contract(random.clone(), contract_addr.clone(), &Empty {}, &[]) + .execute_contract(random_addr.clone(), contract_addr.clone(), &Empty {}, &[]) .unwrap(); assert_eq!(3, res.events.len()); @@ -305,13 +312,13 @@ fn simple_contract() { // then the transfer event let expected_transfer = Event::new("transfer") - .add_attribute("recipient", "random") + .add_attribute("recipient", &random_addr) .add_attribute("sender", &contract_addr) .add_attribute("amount", "5eth"); assert_eq!(&expected_transfer, &res.events[2]); // random got cash - let funds = get_balance(&app, &random); + let funds = get_balance(&app, &random_addr); assert_eq!(funds, coins(5, "eth")); // contract lost it let funds = get_balance(&app, &contract_addr); @@ -320,14 +327,16 @@ fn simple_contract() { #[test] fn reflect_success() { + // prepare user addresses + let owner_addr = addr_make("owner"); + let random_addr = addr_make("random"); + // set personal balance - 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) + .init_balance(storage, &owner_addr, init_funds) .unwrap(); }); @@ -340,7 +349,7 @@ fn reflect_success() { let payout_addr = app .instantiate_contract( payout_id, - owner.clone(), + owner_addr.clone(), &msg, &coins(23, "eth"), "Payout", @@ -352,7 +361,7 @@ fn reflect_success() { let reflect_id = app.store_code(reflect::contract()); let reflect_addr = app - .instantiate_contract(reflect_id, owner, &Empty {}, &[], "Reflect", None) + .instantiate_contract(reflect_id, owner_addr, &Empty {}, &[], "Reflect", None) .unwrap(); // reflect account is empty @@ -375,7 +384,7 @@ fn reflect_success() { messages: vec![msg], }; let res = app - .execute_contract(Addr::unchecked("random"), reflect_addr.clone(), &msgs, &[]) + .execute_contract(random_addr, reflect_addr.clone(), &msgs, &[]) .unwrap(); // ensure the attributes were relayed from the sub-message @@ -426,11 +435,12 @@ fn reflect_success() { #[test] fn reflect_error() { + // prepare user addresses + let owner = addr_make("owner"); + // set personal balance - 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) @@ -454,18 +464,18 @@ fn reflect_error() { // reflect has 40 eth let funds = get_balance(&app, &reflect_addr); assert_eq!(funds, coins(40, "eth")); - let random = Addr::unchecked("random"); + let random_addr = app.api().addr_make("random"); // sending 7 eth works let msg = SubMsg::new(BankMsg::Send { - to_address: random.clone().into(), + to_address: random_addr.clone().into(), amount: coins(7, "eth"), }); let msgs = reflect::Message { messages: vec![msg], }; let res = app - .execute_contract(random.clone(), reflect_addr.clone(), &msgs, &[]) + .execute_contract(random_addr.clone(), reflect_addr.clone(), &msgs, &[]) .unwrap(); // no wasm events as no attributes assert_eq!(2, res.events.len()); @@ -478,7 +488,7 @@ fn reflect_error() { assert_eq!(transfer.ty.as_str(), "transfer"); // ensure random got paid - let funds = get_balance(&app, &random); + let funds = get_balance(&app, &random_addr); assert_eq!(funds, coins(7, "eth")); // reflect count should be updated to 1 @@ -490,26 +500,26 @@ fn reflect_error() { // sending 8 eth, then 3 btc should fail both let msg = SubMsg::new(BankMsg::Send { - to_address: random.clone().into(), + to_address: random_addr.clone().into(), amount: coins(8, "eth"), }); let msg2 = SubMsg::new(BankMsg::Send { - to_address: random.clone().into(), + to_address: random_addr.clone().into(), amount: coins(3, "btc"), }); let msgs = reflect::Message { messages: vec![msg, msg2], }; let err = app - .execute_contract(random.clone(), reflect_addr.clone(), &msgs, &[]) + .execute_contract(random_addr.clone(), reflect_addr.clone(), &msgs, &[]) .unwrap_err(); assert_eq!( - StdError::overflow(OverflowError::new(OverflowOperation::Sub, 0, 3)), + StdError::overflow(OverflowError::new(OverflowOperation::Sub)), err.downcast().unwrap() ); // first one should have been rolled-back on error (no second payment) - let funds = get_balance(&app, &random); + let funds = get_balance(&app, &random_addr); assert_eq!(funds, coins(7, "eth")); // failure should not update reflect count @@ -522,13 +532,15 @@ fn reflect_error() { #[test] fn sudo_works() { - let owner = Addr::unchecked("owner"); - let init_funds = vec![coin(100, "eth")]; + // prepare user addresses + let owner_addr = addr_make("owner"); + // set personal balance + let init_funds = vec![coin(100, "eth")]; let mut app = App::new(|router, _, storage| { router .bank - .init_balance(storage, &owner, init_funds) + .init_balance(storage, &owner_addr, init_funds) .unwrap(); }); @@ -538,7 +550,14 @@ fn sudo_works() { payout: coin(5, "eth"), }; let payout_addr = app - .instantiate_contract(payout_id, owner, &msg, &coins(23, "eth"), "Payout", None) + .instantiate_contract( + payout_id, + owner_addr, + &msg, + &coins(23, "eth"), + "Payout", + None, + ) .unwrap(); // count is 1 @@ -563,7 +582,7 @@ fn sudo_works() { let msg = payout::SudoMsg { set_count: 49 }; let sudo_msg = WasmSudo { contract_addr: payout_addr.clone(), - msg: to_json_binary(&msg).unwrap(), + message: to_json_binary(&msg).unwrap(), }; app.sudo(sudo_msg.into()).unwrap(); @@ -576,12 +595,13 @@ fn sudo_works() { #[test] fn reflect_sub_message_reply_works() { + // prepare user addresses + let owner = addr_make("owner"); + let random = addr_make("random"); + // set personal balance - let owner = Addr::unchecked("owner"); - 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) @@ -602,7 +622,7 @@ fn reflect_sub_message_reply_works() { ) .unwrap(); - // no reply writen beforehand + // no reply written beforehand let query = reflect::QueryMsg::Reply { id: 123 }; let res: StdResult = app.wrap().query_wasm_smart(&reflect_addr, &query); res.unwrap_err(); @@ -672,12 +692,12 @@ fn send_update_admin_works() { // update admin succeeds if admin // update admin fails if not (new) admin // check admin set properly - let owner = Addr::unchecked("owner"); - let owner2 = Addr::unchecked("owner2"); - let beneficiary = Addr::unchecked("beneficiary"); - let mut app = App::default(); + let owner = addr_make("owner"); + let owner2 = addr_make("owner2"); + let beneficiary = addr_make("beneficiary"); + // create a hackatom contract with some funds let code_id = app.store_code(hackatom::contract()); @@ -736,14 +756,18 @@ fn sent_wasm_migration_works() { // migrate fails if not admin // migrate succeeds if admin // check beneficiary updated - let owner = Addr::unchecked("owner"); - let beneficiary = Addr::unchecked("beneficiary"); - let init_funds = coins(30, "btc"); + // prepare user addresses + let owner_addr = addr_make("owner"); + let beneficiary_addr = addr_make("beneficiary"); + let random_addr = addr_make("random"); + + // set personal balance + let init_funds = coins(30, "btc"); let mut app = App::new(|router, _, storage| { router .bank - .init_balance(storage, &owner, init_funds) + .init_balance(storage, &owner_addr, init_funds) .unwrap(); }); @@ -753,40 +777,44 @@ fn sent_wasm_migration_works() { let contract = app .instantiate_contract( code_id, - owner.clone(), + owner_addr.clone(), &hackatom::InstantiateMsg { - beneficiary: beneficiary.as_str().to_owned(), + beneficiary: beneficiary_addr.as_str().to_owned(), }, &coins(20, "btc"), "Hackatom", - Some(owner.to_string()), + Some(owner_addr.to_string()), ) .unwrap(); // check admin set properly let info = app.contract_data(&contract).unwrap(); - assert_eq!(info.admin, Some(owner.clone())); + assert_eq!(info.admin, Some(owner_addr.clone())); // check beneficiary set properly let state: hackatom::InstantiateMsg = app .wrap() .query_wasm_smart(&contract, &hackatom::QueryMsg::Beneficiary {}) .unwrap(); - assert_eq!(state.beneficiary, beneficiary); + assert_eq!(state.beneficiary, beneficiary_addr.to_string()); // migrate fails if not admin - let random = Addr::unchecked("random"); let migrate_msg = hackatom::MigrateMsg { - new_guy: random.to_string(), + new_guy: random_addr.to_string(), }; - app.migrate_contract(beneficiary, contract.clone(), &migrate_msg, code_id) + app.migrate_contract(beneficiary_addr, contract.clone(), &migrate_msg, code_id) .unwrap_err(); // migrate fails if unregistered code id - app.migrate_contract(owner.clone(), contract.clone(), &migrate_msg, code_id + 7) - .unwrap_err(); + app.migrate_contract( + owner_addr.clone(), + contract.clone(), + &migrate_msg, + code_id + 7, + ) + .unwrap_err(); // migrate succeeds when the stars align - app.migrate_contract(owner, contract.clone(), &migrate_msg, code_id) + app.migrate_contract(owner_addr, contract.clone(), &migrate_msg, code_id) .unwrap(); // check beneficiary updated @@ -794,7 +822,7 @@ fn sent_wasm_migration_works() { .wrap() .query_wasm_smart(&contract, &hackatom::QueryMsg::Beneficiary {}) .unwrap(); - assert_eq!(state.beneficiary, random); + assert_eq!(state.beneficiary, random_addr.to_string()); } #[test] @@ -804,14 +832,17 @@ fn sent_funds_properly_visible_on_execution() { // additional 20btc. Then beneficiary balance is checked - expected 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 owner = Addr::unchecked("owner"); - let beneficiary = Addr::unchecked("beneficiary"); - let init_funds = coins(30, "btc"); + // prepare user addresses + let owner_addr = addr_make("owner"); + let beneficiary_addr = addr_make("beneficiary"); + + // set personal balance + let init_funds = coins(30, "btc"); let mut app = App::new(|router, _, storage| { router .bank - .init_balance(storage, &owner, init_funds) + .init_balance(storage, &owner_addr, init_funds) .unwrap(); }); @@ -820,9 +851,9 @@ fn sent_funds_properly_visible_on_execution() { let contract = app .instantiate_contract( code_id, - owner.clone(), + owner_addr.clone(), &hackatom::InstantiateMsg { - beneficiary: beneficiary.as_str().to_owned(), + beneficiary: beneficiary_addr.as_str().to_owned(), }, &coins(10, "btc"), "Hackatom", @@ -831,7 +862,7 @@ fn sent_funds_properly_visible_on_execution() { .unwrap(); app.execute_contract( - owner.clone(), + owner_addr.clone(), contract.clone(), &Empty {}, &coins(20, "btc"), @@ -840,32 +871,34 @@ fn sent_funds_properly_visible_on_execution() { // Check balance of all accounts to ensure no tokens where burned or created, and they are // in correct places - assert_eq!(get_balance(&app, &owner), &[]); + assert_eq!(get_balance(&app, &owner_addr), &[]); assert_eq!(get_balance(&app, &contract), &[]); - assert_eq!(get_balance(&app, &beneficiary), coins(30, "btc")); + assert_eq!(get_balance(&app, &beneficiary_addr), coins(30, "btc")); } /// Demonstrates that we can mint tokens and send from other accounts /// via a custom module, as an example of ability to do privileged actions. mod custom_handler { use super::*; - use crate::{BankSudo, BasicAppBuilder, CosmosRouter}; + use crate::{BankSudo, BasicAppBuilder}; const LOTTERY: Item = Item::new("lottery"); const PITY: Item = Item::new("pity"); #[derive(Clone, 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; @@ -879,7 +912,7 @@ mod custom_handler { msg: Self::ExecT, ) -> AnyResult where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { let lottery = LOTTERY.load(storage)?; @@ -912,7 +945,7 @@ mod custom_handler { _msg: Self::SudoT, ) -> AnyResult where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { bail!("sudo not implemented for CustomHandler") @@ -947,15 +980,12 @@ mod custom_handler { // let's call this custom handler #[test] fn dispatches_messages() { - let winner = "winner".to_string(); - let second = "second".to_string(); - // payments. note 54321 - 12321 = 42000 let denom = "tix"; 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 @@ -964,16 +994,20 @@ mod custom_handler { .unwrap(); }); + let winner = app.api().addr_make("winner"); + let second = app.api().addr_make("second"); + // query that balances are empty let start = app.wrap().query_balance(&winner, denom).unwrap(); assert_eq!(start, coin(0, denom)); // trigger the custom module - let msg = CosmosMsg::Custom(CustomMsg { - lucky_winner: winner.clone(), - runner_up: second.clone(), + let msg = CosmosMsg::Custom(CustomLotteryMsg { + lucky_winner: winner.to_string(), + runner_up: second.to_string(), }); - app.execute(Addr::unchecked("anyone"), msg).unwrap(); + let anyone = app.api().addr_make("anyone"); + app.execute(anyone, msg).unwrap(); // see if coins were properly added let big_win = app.wrap().query_balance(&winner, denom).unwrap(); @@ -985,9 +1019,6 @@ mod custom_handler { mod reply_data_overwrite { use super::*; - use cosmwasm_std::to_json_binary; - - use echo::EXECUTE_REPLY_BASE_ID; fn make_echo_submsg( contract: Addr, @@ -1033,7 +1064,7 @@ mod reply_data_overwrite { fn no_submsg() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1060,7 +1091,7 @@ mod reply_data_overwrite { fn single_submsg() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1093,7 +1124,7 @@ mod reply_data_overwrite { fn single_submsg_no_reply() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1121,7 +1152,7 @@ mod reply_data_overwrite { fn single_no_submsg_data() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1149,7 +1180,7 @@ mod reply_data_overwrite { fn single_no_top_level_data() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1179,11 +1210,12 @@ mod reply_data_overwrite { #[test] fn single_submsg_reply_returns_none() { + // prepare user addresses + let owner = addr_make("owner"); + // set personal balance - 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) @@ -1237,7 +1269,7 @@ mod reply_data_overwrite { fn multiple_submsg() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1280,7 +1312,7 @@ mod reply_data_overwrite { fn multiple_submsg_no_reply() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1313,7 +1345,7 @@ mod reply_data_overwrite { fn multiple_submsg_mixed() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1351,7 +1383,7 @@ mod reply_data_overwrite { fn nested_submsg() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1404,7 +1436,7 @@ mod response_validation { fn empty_attribute_key() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1432,18 +1464,17 @@ mod response_validation { } #[test] - fn empty_attribute_value() { + fn empty_attribute_value_should_work() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); - + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); let contract = app .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None) .unwrap(); - let err = app + assert!(app .execute_contract( owner, contract, @@ -1457,16 +1488,14 @@ mod response_validation { }, &[], ) - .unwrap_err(); - - assert_eq!(Error::empty_attribute_value("key"), err.downcast().unwrap()); + .is_ok()); } #[test] fn empty_event_attribute_key() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1493,18 +1522,17 @@ mod response_validation { } #[test] - fn empty_event_attribute_value() { + fn empty_event_attribute_value_should_work() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); - + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); let contract = app .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None) .unwrap(); - let err = app + assert!(app .execute_contract( owner, contract, @@ -1517,16 +1545,14 @@ mod response_validation { }, &[], ) - .unwrap_err(); - - assert_eq!(Error::empty_attribute_value("key"), err.downcast().unwrap()); + .is_ok()); } #[test] fn too_short_event_type() { let mut app = App::default(); - let owner = Addr::unchecked("owner"); + let owner = app.api().addr_make("owner"); let code_id = app.store_code(echo::contract()); @@ -1552,26 +1578,29 @@ mod response_validation { } mod contract_instantiation { + #[test] fn instantiate2_works() { use super::*; // prepare application and actors let mut app = App::default(); - let sender = Addr::unchecked("sender"); + let sender = app.api().addr_make("sender"); + let creator = app.api().addr_make("creator"); // store contract's code - let code_id = app.store_code_with_creator(Addr::unchecked("creator"), echo::contract()); + let code_id = app.store_code_with_creator(creator, echo::contract()); // initialize the contract let init_msg = to_json_binary(&Empty {}).unwrap(); + let salt = cosmwasm_std::HexBinary::from_hex("010203040506").unwrap(); let msg = WasmMsg::Instantiate2 { admin: None, code_id, msg: init_msg, funds: vec![], label: "label".into(), - salt: [1, 2, 3, 4, 5, 6].as_slice().into(), + salt: salt.into(), }; let res = app.execute(sender, msg.into()).unwrap(); @@ -1581,7 +1610,10 @@ mod contract_instantiation { // assert contract's address is exactly the predicted one, // in default address generator, this is like `contract` + salt in hex - assert_eq!(parsed.contract_address, "contract010203040506"); + assert_eq!( + parsed.contract_address, + "cosmwasm167g7x7auj3l00lhdcevusncx565ytz6a6xvmx2f5xuy84re9ddrqczpzkm", + ); } } @@ -1591,11 +1623,12 @@ mod wasm_queries { fn query_existing_code_info() { use super::*; let mut app = App::default(); - let code_id = app.store_code_with_creator(Addr::unchecked("creator"), echo::contract()); + let creator = app.api().addr_make("creator"); + let code_id = app.store_code_with_creator(creator.clone(), echo::contract()); let code_info_response = app.wrap().query_wasm_code_info(code_id).unwrap(); assert_eq!(code_id, code_info_response.code_id); - assert_eq!("creator", code_info_response.creator); - assert!(!code_info_response.checksum.is_empty()); + assert_eq!(creator.to_string(), code_info_response.creator.to_string()); + assert_eq!(32, code_info_response.checksum.as_slice().len()); } #[test] @@ -1618,15 +1651,15 @@ mod custom_messages { #[test] fn triggering_custom_msg() { - let custom_handler = CachingCustomHandler::::new(); + let custom_handler = CachingCustomHandler::::new(); let custom_handler_state = custom_handler.state(); let mut app = AppBuilder::new_custom() .with_custom(custom_handler) .build(no_init); - let sender = app.api().addr_validate("sender").unwrap(); - let owner = app.api().addr_validate("owner").unwrap(); + let sender = app.api().addr_make("sender"); + let owner = app.api().addr_make("owner"); let contract_id = app.store_code(echo::custom_contract()); @@ -1638,7 +1671,7 @@ mod custom_messages { 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() @@ -1649,7 +1682,7 @@ mod custom_messages { 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()); @@ -1662,11 +1695,12 @@ mod protobuf_wrapped_data { #[test] fn instantiate_wrapped_properly() { + // prepare user addresses + let owner = addr_make("owner"); + // set personal balance - let owner = Addr::unchecked("owner"); let init_funds = vec![coin(20, "btc")]; - - let mut app = custom_app::(|router, _, storage| { + let mut app = custom_app::(|router, _, storage| { router .bank .init_balance(storage, &owner, init_funds) @@ -1700,8 +1734,9 @@ mod protobuf_wrapped_data { #[test] fn instantiate_with_data_works() { - let owner = Addr::unchecked("owner"); - let mut app = BasicApp::new(|_, _, _| {}); + let mut app = BasicApp::new(no_init); + + let owner = app.api().addr_make("owner"); // set up echo contract let code_id = app.store_code(echo::contract()); @@ -1729,8 +1764,9 @@ mod protobuf_wrapped_data { #[test] fn instantiate_with_reply_works() { - let owner = Addr::unchecked("owner"); - let mut app = BasicApp::new(|_, _, _| {}); + let mut app = BasicApp::new(no_init); + + let owner = app.api().addr_make("owner"); // set up echo contract let code_id = app.store_code(echo::contract()); @@ -1781,8 +1817,9 @@ mod protobuf_wrapped_data { #[test] fn execute_wrapped_properly() { - let owner = Addr::unchecked("owner"); - let mut app = BasicApp::new(|_, _, _| {}); + let mut app = BasicApp::new(no_init); + + let owner = app.api().addr_make("owner"); // set up reflect contract let code_id = app.store_code(echo::contract()); @@ -1804,13 +1841,13 @@ mod protobuf_wrapped_data { mod errors { use super::*; - use cosmwasm_std::to_json_binary; #[test] fn simple_instantiation() { - let owner = Addr::unchecked("owner"); let mut app = App::default(); + let owner = app.api().addr_make("owner"); + // set up contract let code_id = app.store_code(error::contract(false)); @@ -1821,7 +1858,7 @@ mod errors { // we should be able to retrieve the original error by downcasting let source: &StdError = err.downcast_ref().unwrap(); - if let StdError::GenericErr { msg } = source { + if let StdError::GenericErr { msg, .. } = source { assert_eq!(msg, "Init failed"); } else { panic!("wrong StdError variant"); @@ -1834,9 +1871,11 @@ mod errors { #[test] fn simple_call() { - let owner = Addr::unchecked("owner"); let mut app = App::default(); + let owner = app.api().addr_make("owner"); + let random_addr = app.api().addr_make("random"); + // set up contract let code_id = app.store_code(error::contract(true)); @@ -1847,12 +1886,12 @@ mod errors { // execute should error let err = app - .execute_contract(Addr::unchecked("random"), contract_addr, &msg, &[]) + .execute_contract(random_addr, contract_addr, &msg, &[]) .unwrap_err(); // we should be able to retrieve the original error by downcasting let source: &StdError = err.downcast_ref().unwrap(); - if let StdError::GenericErr { msg } = source { + if let StdError::GenericErr { msg, .. } = source { assert_eq!(msg, "Handle failed"); } else { panic!("wrong StdError variant"); @@ -1865,9 +1904,11 @@ mod errors { #[test] fn nested_call() { - let owner = Addr::unchecked("owner"); let mut app = App::default(); + let owner = app.api().addr_make("owner"); + let random_addr = app.api().addr_make("random"); + let error_code_id = app.store_code(error::contract(true)); let caller_code_id = app.store_code(caller::contract()); @@ -1887,12 +1928,12 @@ mod errors { funds: vec![], }; let err = app - .execute_contract(Addr::unchecked("random"), caller_addr, &msg, &[]) + .execute_contract(random_addr, caller_addr, &msg, &[]) .unwrap_err(); - // we can downcast to get the original error + // we can get the original error by downcasting let source: &StdError = err.downcast_ref().unwrap(); - if let StdError::GenericErr { msg } = source { + if let StdError::GenericErr { msg, .. } = source { assert_eq!(msg, "Handle failed"); } else { panic!("wrong StdError variant"); @@ -1905,22 +1946,38 @@ mod errors { #[test] fn double_nested_call() { - let owner = Addr::unchecked("owner"); let mut app = App::default(); + let owner_addr = app.api().addr_make("owner"); + let random_addr = app.api().addr_make("random"); + let error_code_id = app.store_code(error::contract(true)); let caller_code_id = app.store_code(caller::contract()); // set up contract_helpers let msg = Empty {}; let caller_addr1 = app - .instantiate_contract(caller_code_id, owner.clone(), &msg, &[], "caller", None) + .instantiate_contract( + caller_code_id, + owner_addr.clone(), + &msg, + &[], + "caller", + None, + ) .unwrap(); let caller_addr2 = app - .instantiate_contract(caller_code_id, owner.clone(), &msg, &[], "caller", None) + .instantiate_contract( + caller_code_id, + owner_addr.clone(), + &msg, + &[], + "caller", + None, + ) .unwrap(); let error_addr = app - .instantiate_contract(error_code_id, owner, &msg, &[], "error", None) + .instantiate_contract(error_code_id, owner_addr, &msg, &[], "error", None) .unwrap(); // caller1 calls caller2, caller2 calls error @@ -1935,15 +1992,15 @@ mod errors { funds: vec![], }; let err = app - .execute_contract(Addr::unchecked("random"), caller_addr1, &msg, &[]) + .execute_contract(random_addr, caller_addr1, &msg, &[]) .unwrap_err(); // uncomment to have the test fail and see how the error stringifies // panic!("{:?}", err); - // we can downcast to get the original error + // we can get the original error by downcasting let source: &StdError = err.downcast_ref().unwrap(); - if let StdError::GenericErr { msg } = source { + if let StdError::GenericErr { msg, .. } = source { assert_eq!(msg, "Handle failed"); } else { panic!("wrong StdError variant"); @@ -1954,29 +2011,3 @@ mod errors { assert_eq!(err.chain().count(), 4); } } - -mod api { - use super::*; - - #[test] - fn api_addr_validate_should_work() { - let app = App::default(); - let addr = app.api().addr_validate("creator").unwrap(); - assert_eq!(addr.to_string(), "creator"); - } - - #[test] - #[cfg(not(feature = "cosmwasm_1_5"))] - fn api_addr_canonicalize_should_work() { - let app = App::default(); - let canonical = app.api().addr_canonicalize("creator").unwrap(); - assert_eq!(canonical.to_string(), "0000000000000000000000000000726F0000000000000000000000000000000000000000006572000000000000000000000000000000000000000000610000000000000000000000000000000000000000006374000000000000"); - } - - #[test] - fn api_addr_humanize_should_work() { - let app = App::default(); - let canonical = app.api().addr_canonicalize("creator").unwrap(); - assert_eq!(app.api().addr_humanize(&canonical).unwrap(), "creator"); - } -} diff --git a/src/tests/test_custom_handler.rs b/src/tests/test_custom_handler.rs index 834f1e73..5ba0d70e 100644 --- a/src/tests/test_custom_handler.rs +++ b/src/tests/test_custom_handler.rs @@ -1,9 +1,12 @@ use crate::custom_handler::CachingCustomHandler; -use crate::test_helpers::CustomMsg; +use crate::test_helpers::CustomHelperMsg; use crate::{App, Module}; use cosmwasm_std::testing::MockStorage; -use cosmwasm_std::{Addr, Empty}; +use cosmwasm_std::Empty; +///Custom handlers in CosmWasm allow developers to incorporate their own unique logic into tests. +///This feature is valuable for tailoring the testing environment to reflect specific +/// use-cases or behaviors in a CosmWasm-based smart contract. #[test] fn custom_handler_works() { // prepare needed tools @@ -11,7 +14,10 @@ fn custom_handler_works() { let mut storage = MockStorage::default(); // create custom handler - let custom_handler = CachingCustomHandler::::new(); + let custom_handler = CachingCustomHandler::::new(); + + // prepare user addresses + let sender_addr = app.api().addr_make("sender"); // run execute function let _ = custom_handler.execute( @@ -19,8 +25,8 @@ fn custom_handler_works() { &mut storage, app.router(), &app.block_info(), - Addr::unchecked("sender"), - CustomMsg::SetAge { age: 32 }, + sender_addr, + CustomHelperMsg::SetAge { age: 32 }, ); // run query function @@ -29,7 +35,7 @@ fn custom_handler_works() { &storage, &(*app.wrap()), &app.block_info(), - CustomMsg::SetName { + CustomHelperMsg::SetName { name: "John".to_string(), }, ); @@ -40,13 +46,13 @@ fn custom_handler_works() { // there should be one exec message assert_eq!( custom_handler_state.execs().to_owned(), - vec![CustomMsg::SetAge { age: 32 }] + vec![CustomHelperMsg::SetAge { age: 32 }] ); // there should be one query message assert_eq!( custom_handler_state.queries().to_owned(), - vec![CustomMsg::SetName { + vec![CustomHelperMsg::SetName { name: "John".to_string() }] ); @@ -64,11 +70,11 @@ fn custom_handler_has_no_sudo() { let mut storage = MockStorage::default(); // create custom handler - let custom_handler = CachingCustomHandler::::new(); + let custom_handler = CachingCustomHandler::::new(); // run sudo function assert_eq!( - "Unexpected sudo msg Empty", + "Unexpected custom sudo message Empty", custom_handler .sudo( app.api(), diff --git a/src/tests/test_error.rs b/src/tests/test_error.rs new file mode 100644 index 00000000..d3f16290 --- /dev/null +++ b/src/tests/test_error.rs @@ -0,0 +1,43 @@ +use crate::error::Error; +use cosmwasm_std::{WasmMsg, WasmQuery}; + +#[test] +fn instantiating_error_should_work() { + assert_eq!( + "Empty attribute key. Value: alpha", + Error::empty_attribute_key("alpha").to_string() + ); + assert_eq!( + "Attribute key starts with reserved prefix _: gamma", + Error::reserved_attribute_key("gamma").to_string() + ); + assert_eq!( + "Event type too short: event_type", + Error::event_type_too_short("event_type").to_string() + ); + assert_eq!( + r#"Unsupported wasm query: ContractInfo { contract_addr: "contract1984" }"#, + Error::unsupported_wasm_query(WasmQuery::ContractInfo { + contract_addr: "contract1984".to_string() + }) + .to_string() + ); + assert_eq!( + r#"Unsupported wasm message: Migrate { contract_addr: "contract1984", new_code_id: 1984, msg: }"#, + Error::unsupported_wasm_message(WasmMsg::Migrate { + contract_addr: "contract1984".to_string(), + new_code_id: 1984, + msg: Default::default(), + }) + .to_string() + ); + assert_eq!("code id: invalid", Error::invalid_code_id().to_string()); + assert_eq!( + "code id 53: no such code", + Error::unregistered_code_id(53).to_string() + ); + assert_eq!( + "Contract with this address already exists: contract1984", + Error::duplicated_contract_address("contract1984").to_string() + ); +} diff --git a/src/tests/test_gov.rs b/src/tests/test_gov.rs index e900c40f..68897735 100644 --- a/src/tests/test_gov.rs +++ b/src/tests/test_gov.rs @@ -1,99 +1,37 @@ -use crate::error::AnyResult; -use crate::test_helpers::{stargate, stargate::ExecMsg}; -use crate::{App, AppBuilder, AppResponse, CosmosRouter, Executor, Gov, Module}; -use cosmwasm_std::{Addr, Api, Binary, BlockInfo, CustomQuery, Empty, GovMsg, Querier, Storage}; -use schemars::JsonSchema; -use serde::de::DeserializeOwned; -use std::fmt::Debug; - -struct AcceptingModule; - -impl Module for AcceptingModule { - type ExecT = GovMsg; - type QueryT = Empty; - type SudoT = Empty; - - fn execute( - &self, - _api: &dyn Api, - _storage: &mut dyn Storage, - _router: &dyn CosmosRouter, - _block: &BlockInfo, - _sender: Addr, - _msg: Self::ExecT, - ) -> AnyResult - where - ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, - QueryC: CustomQuery + DeserializeOwned + 'static, - { - Ok(AppResponse::default()) - } - - fn sudo( - &self, - _api: &dyn Api, - _storage: &mut dyn Storage, - _router: &dyn CosmosRouter, - _block: &BlockInfo, - _msg: Self::SudoT, - ) -> AnyResult - where - ExecC: Debug + Clone + PartialEq + schemars::JsonSchema + DeserializeOwned + 'static, - QueryC: CustomQuery + DeserializeOwned + 'static, - { - Ok(AppResponse::default()) - } - - fn query( - &self, - _api: &dyn Api, - _storage: &dyn Storage, - _querier: &dyn Querier, - _block: &BlockInfo, - _request: Self::QueryT, - ) -> AnyResult { - Ok(Binary::default()) - } -} - -impl Gov for AcceptingModule {} +use crate::test_helpers::gov; +use crate::{no_init, App, AppBuilder, Executor, GovAcceptingModule}; +use cosmwasm_std::Empty; #[test] fn default_gov() { let mut app = App::default(); - let code = app.store_code(stargate::contract()); + + let creator_addr = app.api().addr_make("creator"); + let code = app.store_code_with_creator(creator_addr, gov::contract()); + + let owner_addr = app.api().addr_make("owner"); let contract = app - .instantiate_contract( - code, - Addr::unchecked("owner"), - &Empty {}, - &[], - "contract", - None, - ) + .instantiate_contract(code, owner_addr.clone(), &Empty {}, &[], "govenius", None) .unwrap(); - app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Gov {}, &[]) + app.execute_contract(owner_addr, contract, &Empty {}, &[]) .unwrap_err(); } #[test] -fn substituting_gov() { +fn accepting_gov() { let mut app = AppBuilder::new() - .with_gov(AcceptingModule) - .build(|_, _, _| ()); - let code = app.store_code(stargate::contract()); + .with_gov(GovAcceptingModule::new()) + .build(no_init); + + let creator_addr = app.api().addr_make("creator"); + let code = app.store_code_with_creator(creator_addr, gov::contract()); + + let owner_addr = app.api().addr_make("owner"); let contract = app - .instantiate_contract( - code, - Addr::unchecked("owner"), - &Empty {}, - &[], - "contract", - None, - ) + .instantiate_contract(code, owner_addr.clone(), &Empty {}, &[], "govenius", None) .unwrap(); - app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Gov {}, &[]) + app.execute_contract(owner_addr, contract, &Empty {}, &[]) .unwrap(); } diff --git a/src/tests/test_ibc.rs b/src/tests/test_ibc.rs index 2497478c..ed32377e 100644 --- a/src/tests/test_ibc.rs +++ b/src/tests/test_ibc.rs @@ -1,43 +1,37 @@ -use crate::test_helpers::{stargate, stargate::ExecMsg}; -use crate::{App, AppBuilder, Executor, IbcAcceptingModule}; -use cosmwasm_std::{Addr, Empty}; +use crate::test_helpers::ibc; +use crate::{no_init, App, AppBuilder, Executor, IbcAcceptingModule}; +use cosmwasm_std::Empty; #[test] fn default_ibc() { let mut app = App::default(); - let code = app.store_code(stargate::contract()); + + let creator_addr = app.api().addr_make("creator"); + let code = app.store_code_with_creator(creator_addr, ibc::contract()); + + let owner_addr = app.api().addr_make("owner"); let contract = app - .instantiate_contract( - code, - Addr::unchecked("owner"), - &Empty {}, - &[], - "contract", - None, - ) + .instantiate_contract(code, owner_addr.clone(), &Empty {}, &[], "ibanera", None) .unwrap(); - app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Ibc {}, &[]) + app.execute_contract(owner_addr, contract, &Empty {}, &[]) .unwrap_err(); } #[test] -fn substituting_ibc() { +fn accepting_ibc() { let mut app = AppBuilder::new() .with_ibc(IbcAcceptingModule::new()) - .build(|_, _, _| ()); - let code = app.store_code(stargate::contract()); + .build(no_init); + + let creator_addr = app.api().addr_make("creator"); + let code = app.store_code_with_creator(creator_addr, ibc::contract()); + + let owner_addr = app.api().addr_make("owner"); let contract = app - .instantiate_contract( - code, - Addr::unchecked("owner"), - &Empty {}, - &[], - "contract", - None, - ) + .instantiate_contract(code, owner_addr.clone(), &Empty {}, &[], "ibanera", None) .unwrap(); - app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Ibc {}, &[]) + app.execute_contract(owner_addr, contract, &Empty {}, &[]) .unwrap(); } diff --git a/src/tests/test_stargate.rs b/src/tests/test_stargate.rs new file mode 100644 index 00000000..01f2f975 --- /dev/null +++ b/src/tests/test_stargate.rs @@ -0,0 +1,54 @@ +use crate::test_helpers::stargate; +use crate::{no_init, App, AppBuilder, Executor, StargateAccepting}; +use cosmwasm_std::Empty; + +#[test] +fn default_failing_stargate_handler_should_work() { + let mut app = App::default(); + + // store the contract + let creator_addr = app.api().addr_make("creator"); + let code = app.store_code_with_creator(creator_addr, stargate::contract()); + + // instantiate contract + let owner_addr = app.api().addr_make("owner"); + let contract_addr = app + .instantiate_contract(code, owner_addr.clone(), &Empty {}, &[], "tauri", None) + .unwrap(); + + // execute empty message on the contract, this contract returns stargate message + // which is rejected by default failing stargate keeper + let err = app + .execute_contract(owner_addr, contract_addr, &Empty {}, &[]) + .unwrap_err(); + + // source error message comes from failing stargate keeper + assert!(err + .source() + .unwrap() + .to_string() + .starts_with("Unexpected stargate execute")); +} + +#[test] +fn accepting_stargate_handler_should_work() { + let mut app = AppBuilder::default() + .with_stargate(StargateAccepting) + .build(no_init); + + // store the contract + let creator_addr = app.api().addr_make("creator"); + let code = app.store_code_with_creator(creator_addr, stargate::contract()); + + // instantiate contract + let owner_addr = app.api().addr_make("owner"); + let contract_addr = app + .instantiate_contract(code, owner_addr.clone(), &Empty {}, &[], "tauri", None) + .unwrap(); + + // execute empty message on the contract, this contract returns stargate message + // which is just silently processed by accepting stargate keeper + assert!(app + .execute_contract(owner_addr, contract_addr, &Empty {}, &[]) + .is_ok()); +} diff --git a/src/transactions.rs b/src/transactions.rs index 4e8b2645..59ac0b0f 100644 --- a/src/transactions.rs +++ b/src/transactions.rs @@ -56,23 +56,9 @@ impl<'a> Storage for StorageTransaction<'a> { } } - fn set(&mut self, key: &[u8], value: &[u8]) { - let op = Op::Set { - key: key.to_vec(), - value: value.to_vec(), - }; - self.local_state.insert(key.to_vec(), op.to_delta()); - self.rep_log.append(op); - } - - fn remove(&mut self, key: &[u8]) { - let op = Op::Delete { key: key.to_vec() }; - self.local_state.insert(key.to_vec(), op.to_delta()); - self.rep_log.append(op); - } - - /// range allows iteration over a set of keys, either forwards or backwards - /// uses standard rust range notation, and eg db.range(b"foo"..b"bar") also works reverse + /// Range allows iteration over a set of keys, either forwards or backwards + /// uses standard Rust range notation, e.g. `db.range(b"foo"‥b"bar")`, + /// works also in reverse order. fn range<'b>( &'b self, start: Option<&[u8]>, @@ -101,6 +87,21 @@ impl<'a> Storage for StorageTransaction<'a> { let merged = MergeOverlay::new(local, base, order); Box::new(merged) } + + fn set(&mut self, key: &[u8], value: &[u8]) { + let op = Op::Set { + key: key.to_vec(), + value: value.to_vec(), + }; + self.local_state.insert(key.to_vec(), op.to_delta()); + self.rep_log.append(op); + } + + fn remove(&mut self, key: &[u8]) { + let op = Op::Delete { key: key.to_vec() }; + self.local_state.insert(key.to_vec(), op.to_delta()); + self.rep_log.append(op); + } } pub struct RepLog { @@ -127,7 +128,7 @@ impl RepLog { } /// Op is the user operation, which can be stored in the RepLog. -/// Currently Set or Delete. +/// Currently: `Set` or `Delete`. enum Op { /// represents the `Set` operation for setting a key-value pair in storage Set { @@ -544,17 +545,17 @@ mod test { let mut base = MemoryStorage::new(); base.set(b"foo", b"bar"); - let mut stxn1 = StorageTransaction::new(&base); + let mut stx1 = StorageTransaction::new(&base); - assert_eq!(stxn1.get(b"foo"), Some(b"bar".to_vec())); + assert_eq!(stx1.get(b"foo"), Some(b"bar".to_vec())); - stxn1.set(b"subtx", b"works"); - assert_eq!(stxn1.get(b"subtx"), Some(b"works".to_vec())); + stx1.set(b"subtx", b"works"); + assert_eq!(stx1.get(b"subtx"), Some(b"works".to_vec())); // Can still read from base, txn is not yet committed assert_eq!(base.get(b"subtx"), None); - stxn1.prepare().commit(&mut base); + stx1.prepare().commit(&mut base); assert_eq!(base.get(b"subtx"), Some(b"works".to_vec())); } diff --git a/src/wasm.rs b/src/wasm.rs index d7891f8a..5de0994a 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -28,31 +28,37 @@ use schemars::JsonSchema; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use std::cell::RefCell; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::fmt::Debug; -//TODO Make `CONTRACTS` private in version 1.0 when the function AddressGenerator::next_address will be removed. /// Contract state kept in storage, separate from the contracts themselves (contract code). -pub(crate) const CONTRACTS: Map<&Addr, ContractData> = Map::new("contracts"); +pub const CONTRACTS: Map<&Addr, ContractData> = Map::new("contracts"); -//TODO Make `NAMESPACE_WASM` private in version 1.0 when the function AddressGenerator::next_address will be removed. -pub(crate) const NAMESPACE_WASM: &[u8] = b"wasm"; -/// See +/// Wasm module namespace. +pub const NAMESPACE_WASM: &[u8] = b"wasm"; + +/// Contract [address namespace]. +/// +/// [address namespace]: https://github.com/CosmWasm/wasmd/blob/96e2b91144c9a371683555f3c696f882583cc6a2/x/wasm/types/events.go#L59 const CONTRACT_ATTR: &str = "_contract_address"; pub const LOCAL_WASM_CODE_OFFSET: usize = 5_000_000; pub const LOCAL_RUST_CODE_OFFSET: usize = 10_000_000; +/// A structure representing a privileged message. #[derive(Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct WasmSudo { + /// Address of a contract the privileged action will be sent to. pub contract_addr: Addr, - pub msg: Binary, + /// Message representing privileged action to be executed by contract `sudo` entry-point. + pub message: Binary, } impl WasmSudo { + /// Creates a new privileged message for specified contract address and action to be executed. pub fn new(contract_addr: &Addr, msg: &T) -> StdResult { Ok(WasmSudo { contract_addr: contract_addr.clone(), - msg: to_json_binary(msg)?, + message: to_json_binary(msg)?, }) } } @@ -80,18 +86,10 @@ pub struct CodeData { pub code_base_id: usize, } -pub trait Wasm: AllWasmQuerier { - /// Handles all WasmQuery requests - fn query( - &self, - api: &dyn Api, - storage: &dyn Storage, - router: &dyn CosmosRouter, - querier: &dyn Querier, - block: &BlockInfo, - request: WasmQuery, - ) -> AnyResult; - +/// Acts as the interface for interacting with WebAssembly (Wasm) modules. +/// This trait is crucial for testing smart contracts written in languages that compile to WebAssembly, +/// which is common in the Cosmos and CosmWasm ecosystems. +pub trait Wasm: AllWasmQuerier { /// Handles all `WasmMsg` messages. fn execute( &self, @@ -103,15 +101,25 @@ pub trait Wasm: AllWasmQuerier { msg: WasmMsg, ) -> AnyResult; + /// Handles all `WasmQuery` requests. + fn query( + &self, + api: &dyn Api, + storage: &dyn Storage, + router: &dyn CosmosRouter, + querier: &dyn Querier, + block: &BlockInfo, + request: WasmQuery, + ) -> AnyResult; + /// Handles all sudo messages, this is an admin interface and can not be called via `CosmosMsg`. fn sudo( &self, api: &dyn Api, - contract_addr: Addr, storage: &mut dyn Storage, router: &dyn CosmosRouter, block: &BlockInfo, - msg: Binary, + msg: WasmSudo, ) -> AnyResult; /// Stores the contract's code and returns an identifier of the stored contract's code. @@ -119,23 +127,68 @@ pub trait Wasm: AllWasmQuerier { /// Stores the contract's code and returns an identifier of the stored contract's code. fn store_wasm_code(&mut self, creator: Addr, code: Vec) -> u64; + /// Stores the contract's code under specified identifier, + /// returns the same code identifier when successful. + fn store_code_with_id( + &mut self, + creator: Addr, + code_id: u64, + code: Box>, + ) -> AnyResult; + + /// Duplicates the contract's code with specified identifier + /// and returns an identifier of the copy of the contract's code. + fn duplicate_code(&mut self, code_id: u64) -> AnyResult; /// Returns `ContractData` for the contract with specified address. fn contract_data(&self, storage: &dyn Storage, address: &Addr) -> AnyResult; /// Returns a raw state dump of all key-values held by a contract with specified address. fn dump_wasm_raw(&self, storage: &dyn Storage, address: &Addr) -> Vec; + + /// Returns the namespace of the contract storage. + fn contract_namespace(&self, contract: &Addr) -> Vec { + let mut name = b"contract_data/".to_vec(); + name.extend_from_slice(contract.as_bytes()); + name + } + + /// Returns **read-only** (not mutable) contract storage. + fn contract_storage<'a>( + &self, + storage: &'a dyn Storage, + address: &Addr, + ) -> Box { + // We double-namespace this, once from global storage -> wasm_storage + // then from wasm_storage -> the contracts subspace + let namespace = self.contract_namespace(address); + let storage = ReadonlyPrefixedStorage::multilevel(storage, &[NAMESPACE_WASM, &namespace]); + Box::new(storage) + } + + /// Returns **read-write** (mutable) contract storage. + fn contract_storage_mut<'a>( + &self, + storage: &'a mut dyn Storage, + address: &Addr, + ) -> Box { + // We double-namespace this, once from global storage -> wasm_storage + // then from wasm_storage -> the contracts subspace + let namespace = self.contract_namespace(address); + let storage = PrefixedStorage::multilevel(storage, &[NAMESPACE_WASM, &namespace]); + Box::new(storage) + } } pub type LocalRustContract = *mut dyn Contract; pub struct WasmKeeper { /// Contract codes that stand for wasm code in real-life blockchain. - pub code_base: RefCell>, + pub code_base: RefCell>, /// Contract codes that stand for rust code living in the current instance /// We also associate the queries to them to make sure we are able to use them with the vm instance pub rust_codes: HashMap>, /// Code data with code base identifier and additional attributes. - pub code_data: HashMap, + pub code_data: BTreeMap, /// Contract's address generator. address_generator: Box, /// Contract's code checksum generator. @@ -149,8 +202,8 @@ pub struct WasmKeeper { impl Default for WasmKeeper { fn default() -> WasmKeeper { Self { - code_base: HashMap::new().into(), - code_data: HashMap::new(), + code_base: BTreeMap::default().into(), + code_data: BTreeMap::default(), address_generator: Box::new(SimpleAddressGenerator), checksum_generator: Box::new(SimpleChecksumGenerator), _p: std::marker::PhantomData, @@ -165,6 +218,22 @@ where ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: CustomQuery + DeserializeOwned + 'static, { + fn execute( + &self, + api: &dyn Api, + storage: &mut dyn Storage, + router: &dyn CosmosRouter, + block: &BlockInfo, + sender: Addr, + msg: WasmMsg, + ) -> AnyResult { + self.execute_wasm(api, storage, router, block, sender.clone(), msg.clone()) + .context(format!( + "Error executing WasmMsg:\n sender: {}\n {:?}", + sender, msg + )) + } + fn query( &self, api: &dyn Api, @@ -212,50 +281,33 @@ where ); to_json_binary(&res).map_err(Into::into) } - other => bail!(Error::UnsupportedWasmQuery(other)), + _ => unimplemented!("{}", Error::unsupported_wasm_query(request)), } } - fn execute( - &self, - api: &dyn Api, - storage: &mut dyn Storage, - router: &dyn CosmosRouter, - block: &BlockInfo, - sender: Addr, - msg: WasmMsg, - ) -> AnyResult { - self.execute_wasm(api, storage, router, block, sender.clone(), msg.clone()) - .context(format!( - "Error executing WasmMsg:\n sender: {}\n {:?}", - sender, msg - )) - } - fn sudo( &self, api: &dyn Api, - contract: Addr, storage: &mut dyn Storage, router: &dyn CosmosRouter, block: &BlockInfo, - msg: Binary, + msg: WasmSudo, ) -> AnyResult { - let custom_event = Event::new("sudo").add_attribute(CONTRACT_ATTR, &contract); + let custom_event = Event::new("sudo").add_attribute(CONTRACT_ATTR, &msg.contract_addr); let querier_storage = router.get_querier_storage(storage)?; let res = self.call_sudo( - contract.clone(), + msg.contract_addr.clone(), api, storage, router, block, - msg.to_vec(), + msg.message.to_vec(), querier_storage, )?; - let (res, msgs) = self.build_app_response(&contract, custom_event, res); - self.process_response(api, router, storage, block, contract, res, msgs) + let (res, msgs) = self.build_app_response(&msg.contract_addr, custom_event, res); + self.process_response(api, router, storage, block, msg.contract_addr, res, msgs) } /// Stores the contract's code in the in-memory lookup table. @@ -268,38 +320,54 @@ where }); self.code_base.borrow_mut().insert(code_id, code); - let checksum = self.checksum_generator.checksum(&creator, code_id as u64); - self.code_data.insert( - code_id, - CodeData { - creator, - checksum, - code_base_id: code_id, - }, - ); - code_id as u64 + self.save_code_data(code_id as u64, creator) } /// Stores the contract's code in the in-memory lookup table. /// Returns an identifier of the stored contract code. fn store_code(&mut self, creator: Addr, code: Box>) -> u64 { let code_id = self.rust_codes.len() + 1 + LOCAL_RUST_CODE_OFFSET; - let checksum = code - .checksum() - .unwrap_or(self.checksum_generator.checksum(&creator, code_id as u64)); - let static_ref = Box::leak(code); + let static_ref = Box::leak(code); let raw_pointer = static_ref as *mut dyn Contract; self.rust_codes.insert(code_id, raw_pointer); + self.save_code_data(code_id as u64, creator) + } + + /// Stores the contract's code in the in-memory lookup table. + /// Returns an identifier of the stored contract code. + fn store_code_with_id( + &mut self, + creator: Addr, + code_id: u64, + code: Box>, + ) -> AnyResult { + // validate provided contract code identifier + if self.code_data.contains_key(&(code_id as usize)) { + bail!(Error::duplicated_code_id(code_id)); + } else if code_id == 0 { + bail!(Error::invalid_code_id()); + } + let static_ref = Box::leak(code); + let raw_pointer = static_ref as *mut dyn Contract; + self.rust_codes.insert(code_id as usize, raw_pointer); + Ok(self.save_code_data(code_id, creator)) + } + + /// Duplicates the contract's code with specified identifier. + /// Returns an identifier of the copy of the contract's code. + fn duplicate_code(&mut self, code_id: u64) -> AnyResult { + let code_data = self.code_data(code_id)?; + let new_code_id = self.code_base.borrow().len() + 1 + LOCAL_WASM_CODE_OFFSET; self.code_data.insert( - code_id, + new_code_id, CodeData { - creator, - checksum, - code_base_id: code_id, + creator: code_data.creator.clone(), + checksum: code_data.checksum, + code_base_id: code_data.code_base_id, }, ); - code_id as u64 + Ok(new_code_id as u64) } /// Returns `ContractData` for the contract with specified address. @@ -314,7 +382,7 @@ where /// Returns a raw state dump of all key-values held by a contract with specified address. fn dump_wasm_raw(&self, storage: &dyn Storage, address: &Addr) -> Vec { - let storage = self.contract_storage_readonly(storage, address); + let storage = self.contract_storage(storage, address); storage.range(None, None, Order::Ascending).collect() } } @@ -387,7 +455,7 @@ where /// Returns code data of the contract with specified code id. fn code_data(&self, code_id: u64) -> AnyResult { if code_id < 1 { - bail!(Error::InvalidCodeId); + bail!(Error::invalid_code_id()); } if let Some(code_data) = self.code_data.get(&(code_id as usize)) { Ok(code_data.clone()) @@ -403,82 +471,10 @@ where } pub fn dump_wasm_raw(&self, storage: &dyn Storage, address: &Addr) -> Vec { - let storage = self.contract_storage_readonly(storage, address); + let storage = self.contract_storage(storage, address); storage.range(None, None, Order::Ascending).collect() } - fn contract_namespace(&self, contract: &Addr) -> Vec { - contract_namespace(contract) - } - - fn contract_storage<'a>( - &self, - storage: &'a mut dyn Storage, - address: &Addr, - ) -> Box { - // We double-namespace this, once from global storage -> wasm_storage - // then from wasm_storage -> the contracts subspace - let namespace = self.contract_namespace(address); - let storage = PrefixedStorage::multilevel(storage, &[NAMESPACE_WASM, &namespace]); - - Box::new(storage) - } - - // fails RUNTIME if you try to write. please don't - fn contract_storage_readonly<'a>( - &self, - storage: &'a dyn Storage, - address: &Addr, - ) -> Box { - // We double-namespace this, once from global storage -> wasm_storage - // then from wasm_storage -> the contracts subspace - let namespace = self.contract_namespace(address); - let storage = ReadonlyPrefixedStorage::multilevel(storage, &[NAMESPACE_WASM, &namespace]); - Box::new(storage) - } -} -impl WasmKeeper -where - ExecC: CustomMsg + DeserializeOwned + 'static, - QueryC: CustomQuery + DeserializeOwned + 'static, -{ - pub fn new() -> Self { - Self::default() - } - - #[deprecated( - since = "0.18.0", - note = "use `WasmKeeper::new().with_address_generator` instead; will be removed in version 1.0.0" - )] - pub fn new_with_custom_address_generator( - address_generator: impl AddressGenerator + 'static, - ) -> Self { - Self { - address_generator: Box::new(address_generator), - ..Default::default() - } - } - - pub fn with_remote(mut self, remote: RemoteChannel) -> Self { - self.remote = Some(remote); - self - } - pub fn with_address_generator( - mut self, - address_generator: impl AddressGenerator + 'static, - ) -> Self { - self.address_generator = Box::new(address_generator); - self - } - - pub fn with_checksum_generator( - mut self, - checksum_generator: impl ChecksumGenerator + 'static, - ) -> Self { - self.checksum_generator = Box::new(checksum_generator); - self - } - /// Validates all attributes. /// /// In `wasmd`, before version v0.45.0 empty attribute values were not allowed. @@ -515,7 +511,119 @@ where Ok(response) } - /// Executes the contract's `query` entry-point. + fn save_code_data(&mut self, code_id: u64, creator: Addr) -> u64 { + // calculate the checksum of the contract 'source' code based on code_id + let checksum = self.checksum_generator.checksum(&creator, code_id); + // store the additional code attributes like creator address and checksum + self.code_data.insert( + code_id as usize, + CodeData { + creator, + checksum, + code_base_id: code_id as usize, + }, + ); + code_id + } +} +impl WasmKeeper +where + ExecC: CustomMsg + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, +{ + /// Creates a wasm keeper with default settings. + /// + /// # Example + /// + /// ``` + /// use cw_multi_test::{AppBuilder, no_init, WasmKeeper}; + /// + /// // create wasm keeper + /// let wasm_keeper = WasmKeeper::new(); + /// + /// // create and use the application with newly created wasm keeper + /// let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init); + /// ``` + pub fn new() -> Self { + Self::default() + } + /// Populates an existing [WasmKeeper] with custom contract address generator. + /// + /// # Example + /// + /// ``` + /// use cosmwasm_std::{Addr, Api, Storage}; + /// use cw_multi_test::{AddressGenerator, AppBuilder, no_init, WasmKeeper}; + /// use cw_multi_test::error::AnyResult; + /// # use cosmwasm_std::testing::MockApi; + /// + /// struct CustomAddressGenerator; + /// + /// impl AddressGenerator for CustomAddressGenerator { + /// fn contract_address( + /// &self, + /// api: &dyn Api, + /// storage: &mut dyn Storage, + /// code_id: u64, + /// instance_id: u64, + /// ) -> AnyResult { + /// // here implement your address generation logic + /// # Ok(MockApi::default().addr_make("test_address")) + /// } + /// } + /// + /// // populate wasm with your custom address generator + /// let wasm_keeper = WasmKeeper::new().with_address_generator(CustomAddressGenerator); + /// + /// // create and use the application with customized wasm keeper + /// let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init); + /// ``` + pub fn with_address_generator( + mut self, + address_generator: impl AddressGenerator + 'static, + ) -> Self { + self.address_generator = Box::new(address_generator); + self + } + + /// Populates an existing [WasmKeeper] with custom checksum generator for the contract code. + /// + /// # Example + /// + /// ``` + /// use cosmwasm_std::{Addr, Checksum}; + /// use cw_multi_test::{AppBuilder, ChecksumGenerator, no_init, WasmKeeper}; + /// + /// struct MyChecksumGenerator; + /// + /// impl ChecksumGenerator for MyChecksumGenerator { + /// fn checksum(&self, creator: &Addr, code_id: u64) -> Checksum { + /// // here implement your custom checksum generator + /// # Checksum::from_hex("custom_checksum").unwrap() + /// } + /// } + /// + /// // populate wasm keeper with your custom checksum generator + /// let wasm_keeper = WasmKeeper::new().with_checksum_generator(MyChecksumGenerator); + /// + /// // create and use the application with customized wasm keeper + /// let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init); + /// ``` + pub fn with_checksum_generator( + mut self, + checksum_generator: impl ChecksumGenerator + 'static, + ) -> Self { + self.checksum_generator = Box::new(checksum_generator); + self + } + + /// Specify the remote location of this wasm + pub fn with_remote(mut self, remote: RemoteChannel) -> Self { + self.remote = Some(remote); + self + } + + /// Executes contract's `query` entry-point. pub fn query_smart( &self, address: Addr, @@ -549,8 +657,9 @@ where ) } + /// Returns the value stored under specified key in contracts storage. pub fn query_raw(&self, address: Addr, storage: &dyn Storage, key: &[u8]) -> Binary { - let local_key = self.contract_storage_readonly(storage, &address).get(key); + let local_key = self.contract_storage(storage, &address).get(key); if let Some(local_key) = local_key { local_key.into() } else { @@ -622,9 +731,9 @@ where router: &dyn CosmosRouter, block: &BlockInfo, sender: Addr, - wasm_msg: WasmMsg, + msg: WasmMsg, ) -> AnyResult { - match wasm_msg { + match msg { WasmMsg::Execute { contract_addr, msg, @@ -740,7 +849,7 @@ where WasmMsg::ClearAdmin { contract_addr } => { self.update_admin(api, storage, sender, &contract_addr, None) } - msg => bail!(Error::UnsupportedWasmMsg(msg)), + _ => unimplemented!("{}", Error::unsupported_wasm_message(msg)), } } @@ -850,6 +959,8 @@ where if matches!(reply_on, ReplyOn::Always | ReplyOn::Success) { let reply = Reply { id, + payload: Default::default(), + gas_used: 0, result: SubMsgResult::Ok( #[allow(deprecated)] SubMsgResponse { @@ -858,8 +969,6 @@ where msg_responses: vec![], }, ), - payload: Default::default(), - gas_used: 0, }; // do reply and combine it with the original response let reply_res = self.reply(api, router, storage, block, contract, reply)?; @@ -871,15 +980,14 @@ where // reply is not called, no data should be returned r.data = None; } - Ok(r) } else if let Err(e) = res { if matches!(reply_on, ReplyOn::Always | ReplyOn::Error) { let reply = Reply { id, - result: SubMsgResult::Err(format!("{:?}", e)), payload: Default::default(), gas_used: 0, + result: SubMsgResult::Err(format!("{:?}", e)), }; self.reply(api, router, storage, block, contract, reply) } else { @@ -1036,6 +1144,7 @@ where Ok(addr) } + /// Executes contract's `execute` entry-point. pub fn call_execute( &self, api: &dyn Api, @@ -1072,6 +1181,7 @@ where )?) } + /// Executes contract's `instantiate` entry-point. pub fn call_instantiate( &self, address: Addr, @@ -1108,6 +1218,7 @@ where )?) } + /// Executes contract's `reply` entry-point. pub fn call_reply( &self, address: Addr, @@ -1141,6 +1252,7 @@ where )?) } + /// Executes contract's `sudo` entry-point. pub fn call_sudo( &self, address: Addr, @@ -1174,6 +1286,7 @@ where )?) } + /// Executes contract's `migrate` entry-point. pub fn call_migrate( &self, address: Addr, @@ -1232,7 +1345,7 @@ where { let contract = self.contract_data(storage, &address)?; let handler = self.contract_code::<'a, 'b>(contract.code_id)?; - let storage = self.contract_storage_readonly(storage, &address); + let storage = self.contract_storage(storage, &address); let env = self.get_env(address, block); let deps = Deps { @@ -1265,7 +1378,7 @@ where // However, we need to get write and read access to the same storage in two different objects, // and this is the only way I know how to do so. transactional(storage, |write_cache, read_store| { - let mut contract_storage = self.contract_storage(write_cache, &address); + let mut contract_storage = self.contract_storage_mut(write_cache, &address); let querier = RouterQuerier::new(router, api, read_store, block); let env = self.get_env(address, block); @@ -1278,6 +1391,7 @@ where }) } + /// Saves contract data in a storage under specified address. pub fn save_contract( &self, storage: &mut dyn Storage, @@ -1302,17 +1416,14 @@ where } } -// TODO: replace with code in utils - #[derive(Clone, PartialEq, Message)] struct InstantiateResponse { #[prost(string, tag = "1")] - pub address: ::prost::alloc::string::String, + pub address: String, #[prost(bytes, tag = "2")] - pub data: ::prost::alloc::vec::Vec, + pub data: Vec, } -// TODO: encode helpers in utils fn instantiate_response(data: Option, contact_address: &Addr) -> Binary { let data = data.unwrap_or_default().to_vec(); let init_data = InstantiateResponse { @@ -1328,7 +1439,7 @@ fn instantiate_response(data: Option, contact_address: &Addr) -> Binary #[derive(Clone, PartialEq, Message)] struct ExecuteResponse { #[prost(bytes, tag = "1")] - pub data: ::prost::alloc::vec::Vec, + pub data: Vec, } // empty return if no data present in original @@ -1341,3 +1452,890 @@ fn execute_response(data: Option) -> Option { new_data.into() }) } + +#[cfg(test)] +mod test { + use super::*; + use crate::app::Router; + use crate::bank::BankKeeper; + use crate::module::FailingModule; + use crate::staking::{DistributionKeeper, StakeKeeper}; + use crate::test_helpers::{caller, error, payout}; + use crate::transactions::StorageTransaction; + use crate::{GovFailingModule, IbcFailingModule, StargateFailing}; + use cosmwasm_std::testing::{message_info, mock_env, MockApi, MockQuerier, MockStorage}; + #[cfg(feature = "cosmwasm_1_2")] + use cosmwasm_std::CodeInfoResponse; + use cosmwasm_std::{ + coin, from_json, to_json_vec, CanonicalAddr, CosmosMsg, Empty, HexBinary, StdError, + }; + + /// Type alias for default build `Router` to make its reference in typical scenario + type BasicRouter = Router< + BankKeeper, + FailingModule, + WasmKeeper, + StakeKeeper, + DistributionKeeper, + IbcFailingModule, + GovFailingModule, + StargateFailing, + >; + + fn wasm_keeper() -> WasmKeeper { + WasmKeeper::new() + } + + fn mock_router() -> BasicRouter { + Router { + wasm: WasmKeeper::new(), + bank: BankKeeper::new(), + custom: FailingModule::new(), + staking: StakeKeeper::new(), + distribution: DistributionKeeper::new(), + ibc: IbcFailingModule::new(), + gov: GovFailingModule::new(), + stargate: StargateFailing, + } + } + + #[test] + fn register_contract() { + let api = MockApi::default(); + + // prepare user addresses + let creator_addr = api.addr_make("creator"); + let user_addr = api.addr_make("foobar"); + let admin_addr = api.addr_make("admin"); + let unregistered_addr = api.addr_make("unregistered"); + + let mut wasm_storage = MockStorage::new(); + let mut wasm_keeper = wasm_keeper(); + let block = mock_env().block; + let code_id = wasm_keeper.store_code(creator_addr, error::contract(false)); + + transactional(&mut wasm_storage, |cache, _| { + // cannot register contract with unregistered codeId + wasm_keeper.register_contract( + &api, + cache, + code_id + 1, + user_addr.clone(), + admin_addr.clone(), + "label".to_owned(), + 1000, + None, + ) + }) + .unwrap_err(); + + let contract_addr = transactional(&mut wasm_storage, |cache, _| { + // we can register a new instance of this code + wasm_keeper.register_contract( + &api, + cache, + code_id, + user_addr.clone(), + admin_addr.clone(), + "label".to_owned(), + 1000, + None, + ) + }) + .unwrap(); + + // verify contract data are as expected + let contract_data = wasm_keeper + .contract_data(&wasm_storage, &contract_addr) + .unwrap(); + + assert_eq!( + contract_data, + ContractData { + code_id, + creator: user_addr.clone(), + admin: admin_addr.into(), + label: "label".to_owned(), + created: 1000, + } + ); + + let err = transactional(&mut wasm_storage, |cache, _| { + // now, we call this contract and see the error message from the contract + let info = message_info(&user_addr, &[]); + wasm_keeper.call_instantiate( + contract_addr.clone(), + &api, + cache, + &mock_router(), + &block, + info, + b"{}".to_vec(), + ) + }) + .unwrap_err(); + + // StdError from contract_error auto-converted to string + assert_eq!( + StdError::generic_err("Init failed"), + err.downcast().unwrap() + ); + + let err = transactional(&mut wasm_storage, |cache, _| { + // and the error for calling an unregistered contract + let info = message_info(&user_addr, &[]); + wasm_keeper.call_instantiate( + unregistered_addr, + &api, + cache, + &mock_router(), + &block, + info, + b"{}".to_vec(), + ) + }) + .unwrap_err(); + + // Default error message from router when not found + assert!(matches!(err.downcast().unwrap(), StdError::NotFound { .. })); + } + + #[test] + fn query_contract_info() { + let api = MockApi::default(); + + // prepare user addresses + let creator_addr = api.addr_make("creator"); + let admin_addr = api.addr_make("admin"); + + let mut wasm_storage = MockStorage::new(); + let mut wasm_keeper = wasm_keeper(); + let block = mock_env().block; + let code_id = wasm_keeper.store_code(creator_addr.clone(), payout::contract()); + assert_eq!(1, code_id); + + let contract_addr = wasm_keeper + .register_contract( + &api, + &mut wasm_storage, + code_id, + creator_addr.clone(), + admin_addr.clone(), + "label".to_owned(), + 1000, + None, + ) + .unwrap(); + + let querier: MockQuerier = MockQuerier::new(&[]); + let query = WasmQuery::ContractInfo { + contract_addr: contract_addr.into(), + }; + + let contract_info = wasm_keeper + .query(&api, &wasm_storage, &querier, &block, query) + .unwrap(); + + let actual: ContractInfoResponse = from_json(contract_info).unwrap(); + let expected = + ContractInfoResponse::new(code_id, creator_addr, admin_addr.into(), false, None); + assert_eq!(expected, actual); + } + + #[test] + #[cfg(feature = "cosmwasm_1_2")] + fn query_code_info() { + let api = MockApi::default(); + let wasm_storage = MockStorage::new(); + let mut wasm_keeper = wasm_keeper(); + let block = mock_env().block; + let creator_addr = api.addr_make("creator"); + let code_id = wasm_keeper.store_code(creator_addr.clone(), payout::contract()); + let querier: MockQuerier = MockQuerier::new(&[]); + let query = WasmQuery::CodeInfo { code_id }; + let code_info = wasm_keeper + .query(&api, &wasm_storage, &querier, &block, query) + .unwrap(); + let actual: CodeInfoResponse = from_json(code_info).unwrap(); + assert_eq!(code_id, actual.code_id); + assert_eq!(creator_addr.as_str(), actual.creator.as_str()); + assert_eq!(32, actual.checksum.as_slice().len()); + } + + #[test] + #[cfg(feature = "cosmwasm_1_2")] + fn different_contracts_must_have_different_checksum() { + let api = MockApi::default(); + let creator_addr = api.addr_make("creator"); + let wasm_storage = MockStorage::new(); + let mut wasm_keeper = wasm_keeper(); + let block = mock_env().block; + let code_id_payout = wasm_keeper.store_code(creator_addr.clone(), payout::contract()); + let code_id_caller = wasm_keeper.store_code(creator_addr, caller::contract()); + let querier: MockQuerier = MockQuerier::new(&[]); + let query_payout = WasmQuery::CodeInfo { + code_id: code_id_payout, + }; + let query_caller = WasmQuery::CodeInfo { + code_id: code_id_caller, + }; + let code_info_payout = wasm_keeper + .query(&api, &wasm_storage, &querier, &block, query_payout) + .unwrap(); + let code_info_caller = wasm_keeper + .query(&api, &wasm_storage, &querier, &block, query_caller) + .unwrap(); + let info_payout: CodeInfoResponse = from_json(code_info_payout).unwrap(); + let info_caller: CodeInfoResponse = from_json(code_info_caller).unwrap(); + assert_eq!(code_id_payout, info_payout.code_id); + assert_eq!(code_id_caller, info_caller.code_id); + assert_ne!(info_caller.code_id, info_payout.code_id); + assert_eq!(info_caller.creator, info_payout.creator); + assert_ne!(info_caller.checksum, info_payout.checksum); + } + + #[test] + #[cfg(feature = "cosmwasm_1_2")] + fn querying_invalid_code_info_must_fail() { + let api = MockApi::default(); + let wasm_storage = MockStorage::new(); + let wasm_keeper = wasm_keeper(); + let block = mock_env().block; + + let querier: MockQuerier = MockQuerier::new(&[]); + let query = WasmQuery::CodeInfo { code_id: 100 }; + + wasm_keeper + .query(&api, &wasm_storage, &querier, &block, query) + .unwrap_err(); + } + + #[test] + fn can_dump_raw_wasm_state() { + let api = MockApi::default(); + + // prepare user addresses + let creator_addr = api.addr_make("creator"); + let admin_addr = api.addr_make("admin"); + let user_addr = api.addr_make("foobar"); + + let mut wasm_keeper = wasm_keeper(); + let block = mock_env().block; + let code_id = wasm_keeper.store_code(creator_addr, payout::contract()); + + let mut wasm_storage = MockStorage::new(); + + let contract_addr = wasm_keeper + .register_contract( + &api, + &mut wasm_storage, + code_id, + user_addr.clone(), + admin_addr, + "label".to_owned(), + 1000, + None, + ) + .unwrap(); + + // make a contract with state + let payout = coin(1500, "mlg"); + let msg = payout::InstantiateMessage { + payout: payout.clone(), + }; + wasm_keeper + .call_instantiate( + contract_addr.clone(), + &api, + &mut wasm_storage, + &mock_router(), + &block, + message_info(&user_addr, &[]), + to_json_vec(&msg).unwrap(), + ) + .unwrap(); + + // dump state + let state = wasm_keeper.dump_wasm_raw(&wasm_storage, &contract_addr); + assert_eq!(state.len(), 2); + // check contents + let (k, v) = &state[0]; + assert_eq!(k.as_slice(), b"count"); + let count: u32 = from_json(v).unwrap(); + assert_eq!(count, 1); + let (k, v) = &state[1]; + assert_eq!(k.as_slice(), b"payout"); + let stored_pay: payout::InstantiateMessage = from_json(v).unwrap(); + assert_eq!(stored_pay.payout, payout); + } + + #[test] + fn contract_send_coins() { + let api = MockApi::default(); + + // prepare user addresses + let creator_addr = api.addr_make("creator"); + let user_addr = api.addr_make("foobar"); + + let mut wasm_keeper = wasm_keeper(); + let block = mock_env().block; + let code_id = wasm_keeper.store_code(creator_addr, payout::contract()); + + let mut wasm_storage = MockStorage::new(); + let mut cache = StorageTransaction::new(&wasm_storage); + + let contract_addr = wasm_keeper + .register_contract( + &api, + &mut cache, + code_id, + user_addr.clone(), + None, + "label".to_owned(), + 1000, + None, + ) + .unwrap(); + + let payout = coin(100, "TGD"); + + // init the contract + let info = message_info(&user_addr, &[]); + let init_msg = to_json_vec(&payout::InstantiateMessage { + payout: payout.clone(), + }) + .unwrap(); + let res = wasm_keeper + .call_instantiate( + contract_addr.clone(), + &api, + &mut cache, + &mock_router(), + &block, + info, + init_msg, + ) + .unwrap(); + assert_eq!(0, res.messages.len()); + + // execute the contract + let info = message_info(&user_addr, &[]); + let res = wasm_keeper + .call_execute( + &api, + &mut cache, + contract_addr.clone(), + &mock_router(), + &block, + info, + b"{}".to_vec(), + ) + .unwrap(); + assert_eq!(1, res.messages.len()); + match &res.messages[0].msg { + CosmosMsg::Bank(BankMsg::Send { to_address, amount }) => { + assert_eq!(to_address.as_str(), user_addr.as_str()); + assert_eq!(amount.as_slice(), &[payout.clone()]); + } + m => panic!("Unexpected message {:?}", m), + } + + // and flush before query + cache.prepare().commit(&mut wasm_storage); + + // query the contract + let query = to_json_vec(&payout::QueryMsg::Payout {}).unwrap(); + let querier: MockQuerier = MockQuerier::new(&[]); + let data = wasm_keeper + .query_smart(contract_addr, &api, &wasm_storage, &querier, &block, query) + .unwrap(); + let res: payout::InstantiateMessage = from_json(data).unwrap(); + assert_eq!(res.payout, payout); + } + + fn assert_payout( + router: &WasmKeeper, + storage: &mut dyn Storage, + contract_addr: &Addr, + payout: &Coin, + ) { + let api = MockApi::default(); + let user_addr = api.addr_make("silly"); + let info = message_info(&user_addr, &[]); + let res = router + .call_execute( + &api, + storage, + contract_addr.clone(), + &mock_router(), + &mock_env().block, + info, + b"{}".to_vec(), + ) + .unwrap(); + assert_eq!(1, res.messages.len()); + match &res.messages[0].msg { + CosmosMsg::Bank(BankMsg::Send { to_address, amount }) => { + assert_eq!(to_address.as_str(), user_addr.as_str()); + assert_eq!(amount.as_slice(), &[payout.clone()]); + } + m => panic!("Unexpected message {:?}", m), + } + } + + fn assert_no_contract(storage: &dyn Storage, contract_addr: &Addr) { + let contract = CONTRACTS.may_load(storage, contract_addr).unwrap(); + assert!(contract.is_none(), "{:?}", contract_addr); + } + + #[test] + fn multi_level_wasm_cache() { + let api = MockApi::default(); + + // prepare user addresses + let creator_addr = api.addr_make("creator"); + let user_addr = api.addr_make("foobar"); + let user_addr_1 = api.addr_make("johnny"); + + let mut wasm_keeper = wasm_keeper(); + let block = mock_env().block; + let code_id = wasm_keeper.store_code(creator_addr, payout::contract()); + + let mut wasm_storage = MockStorage::new(); + + let payout1 = coin(100, "TGD"); + + // set contract 1 and commit (on router) + let contract1 = transactional(&mut wasm_storage, |cache, _| { + let contract = wasm_keeper + .register_contract( + &api, + cache, + code_id, + user_addr.clone(), + None, + "".to_string(), + 1000, + None, + ) + .unwrap(); + let info = message_info(&user_addr, &[]); + let init_msg = to_json_vec(&payout::InstantiateMessage { + payout: payout1.clone(), + }) + .unwrap(); + wasm_keeper + .call_instantiate( + contract.clone(), + &api, + cache, + &mock_router(), + &block, + info, + init_msg, + ) + .unwrap(); + + Ok(contract) + }) + .unwrap(); + + let payout2 = coin(50, "BTC"); + let payout3 = coin(1234, "ATOM"); + + // create a new cache and check we can use contract 1 + let (contract2, contract3) = transactional(&mut wasm_storage, |cache, wasm_reader| { + assert_payout(&wasm_keeper, cache, &contract1, &payout1); + + // create contract 2 and use it + let contract2 = wasm_keeper + .register_contract( + &api, + cache, + code_id, + user_addr.clone(), + None, + "".to_owned(), + 1000, + None, + ) + .unwrap(); + let info = message_info(&user_addr, &[]); + let init_msg = to_json_vec(&payout::InstantiateMessage { + payout: payout2.clone(), + }) + .unwrap(); + let _res = wasm_keeper + .call_instantiate( + contract2.clone(), + &api, + cache, + &mock_router(), + &block, + info, + init_msg, + ) + .unwrap(); + assert_payout(&wasm_keeper, cache, &contract2, &payout2); + + // create a level2 cache and check we can use contract 1 and contract 2 + let contract3 = transactional(cache, |cache2, read| { + assert_payout(&wasm_keeper, cache2, &contract1, &payout1); + assert_payout(&wasm_keeper, cache2, &contract2, &payout2); + + // create a contract on level 2 + let contract3 = wasm_keeper + .register_contract( + &api, + cache2, + code_id, + user_addr, + None, + "".to_owned(), + 1000, + None, + ) + .unwrap(); + let info = message_info(&user_addr_1, &[]); + let init_msg = to_json_vec(&payout::InstantiateMessage { + payout: payout3.clone(), + }) + .unwrap(); + let _res = wasm_keeper + .call_instantiate( + contract3.clone(), + &api, + cache2, + &mock_router(), + &block, + info, + init_msg, + ) + .unwrap(); + assert_payout(&wasm_keeper, cache2, &contract3, &payout3); + + // ensure first cache still doesn't see this contract + assert_no_contract(read, &contract3); + Ok(contract3) + }) + .unwrap(); + + // after applying transaction, all contracts present on cache + assert_payout(&wasm_keeper, cache, &contract1, &payout1); + assert_payout(&wasm_keeper, cache, &contract2, &payout2); + assert_payout(&wasm_keeper, cache, &contract3, &payout3); + + // but not yet the root router + assert_no_contract(wasm_reader, &contract1); + assert_no_contract(wasm_reader, &contract2); + assert_no_contract(wasm_reader, &contract3); + + Ok((contract2, contract3)) + }) + .unwrap(); + + // ensure that it is now applied to the router + assert_payout(&wasm_keeper, &mut wasm_storage, &contract1, &payout1); + assert_payout(&wasm_keeper, &mut wasm_storage, &contract2, &payout2); + assert_payout(&wasm_keeper, &mut wasm_storage, &contract3, &payout3); + } + + fn assert_admin( + storage: &dyn Storage, + wasm_keeper: &WasmKeeper, + contract_addr: &impl ToString, + admin: Option, + ) { + let api = MockApi::default(); + let querier: MockQuerier = MockQuerier::new(&[]); + // query + let data = wasm_keeper + .query( + &api, + storage, + &querier, + &mock_env().block, + WasmQuery::ContractInfo { + contract_addr: contract_addr.to_string(), + }, + ) + .unwrap(); + let res: ContractInfoResponse = from_json(data).unwrap(); + assert_eq!(res.admin, admin); + } + + #[test] + fn update_clear_admin_works() { + let api = MockApi::default(); + let mut wasm_keeper = wasm_keeper(); + let block = mock_env().block; + let creator = api.addr_make("creator"); + let code_id = wasm_keeper.store_code(creator.clone(), caller::contract()); + + let mut wasm_storage = MockStorage::new(); + + let admin = api.addr_make("admin"); + let new_admin = api.addr_make("new_admin"); + let normal_user = api.addr_make("normal_user"); + + let contract_addr = wasm_keeper + .register_contract( + &api, + &mut wasm_storage, + code_id, + creator, + admin.clone(), + "label".to_owned(), + 1000, + None, + ) + .unwrap(); + + // init the contract + let info = message_info(&admin, &[]); + let init_msg = to_json_vec(&Empty {}).unwrap(); + let res = wasm_keeper + .call_instantiate( + contract_addr.clone(), + &api, + &mut wasm_storage, + &mock_router(), + &block, + info, + init_msg, + ) + .unwrap(); + assert_eq!(0, res.messages.len()); + + assert_admin( + &wasm_storage, + &wasm_keeper, + &contract_addr, + Some(admin.clone()), + ); + + // non-admin should not be allowed to become admin on their own + wasm_keeper + .execute_wasm( + &api, + &mut wasm_storage, + &mock_router(), + &block, + normal_user.clone(), + WasmMsg::UpdateAdmin { + contract_addr: contract_addr.to_string(), + admin: normal_user.to_string(), + }, + ) + .unwrap_err(); + + // should still be admin + assert_admin( + &wasm_storage, + &wasm_keeper, + &contract_addr, + Some(admin.clone()), + ); + + // admin should be allowed to transfer administration permissions + let res = wasm_keeper + .execute_wasm( + &api, + &mut wasm_storage, + &mock_router(), + &block, + admin, + WasmMsg::UpdateAdmin { + contract_addr: contract_addr.to_string(), + admin: new_admin.to_string(), + }, + ) + .unwrap(); + assert_eq!(res.events.len(), 0); + + // new_admin should now be admin + assert_admin( + &wasm_storage, + &wasm_keeper, + &contract_addr, + Some(new_admin.clone()), + ); + + // new_admin should now be able to clear to admin + let res = wasm_keeper + .execute_wasm( + &api, + &mut wasm_storage, + &mock_router(), + &block, + new_admin, + WasmMsg::ClearAdmin { + contract_addr: contract_addr.to_string(), + }, + ) + .unwrap(); + assert_eq!(res.events.len(), 0); + + // should have no admin now + assert_admin(&wasm_storage, &wasm_keeper, &contract_addr, None); + } + + #[test] + fn uses_simple_address_generator_by_default() { + let api = MockApi::default(); + let mut wasm_keeper = wasm_keeper(); + let creator_addr = api.addr_make("creator"); + let code_id = wasm_keeper.store_code(creator_addr.clone(), payout::contract()); + assert_eq!(1, code_id); + + let mut wasm_storage = MockStorage::new(); + + let admin = api.addr_make("admin"); + let contract_addr = wasm_keeper + .register_contract( + &api, + &mut wasm_storage, + code_id, + creator_addr.clone(), + admin.clone(), + "label".to_owned(), + 1000, + None, + ) + .unwrap(); + + assert_eq!( + contract_addr.as_str(), + "cosmwasm1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsgn6fq2", + "default address generator returned incorrect address" + ); + + let salt = HexBinary::from_hex("c0ffee").unwrap(); + + let contract_addr = wasm_keeper + .register_contract( + &api, + &mut wasm_storage, + code_id, + creator_addr.clone(), + admin.clone(), + "label".to_owned(), + 1000, + Binary::from(salt.clone()), + ) + .unwrap(); + + assert_eq!( + contract_addr.as_str(), + "cosmwasm1drhu6t78wacgm5qjzs4hvkv9fd9awa9henw7fh6vmzrhf7k2nkjsg3flns", + "default address generator returned incorrect address" + ); + + let code_id = wasm_keeper.store_code(creator_addr, payout::contract()); + assert_eq!(2, code_id); + + let user_addr = api.addr_make("boobaz"); + + let contract_addr = wasm_keeper + .register_contract( + &api, + &mut wasm_storage, + code_id, + user_addr, + admin, + "label".to_owned(), + 1000, + Binary::from(salt), + ) + .unwrap(); + + assert_eq!( + contract_addr.as_str(), + "cosmwasm13cfeertf2gny0rzp5jwqzst8crmfgvcd2lq5su0c9z66yxa45qdsdd0uxc", + "default address generator returned incorrect address" + ); + } + + struct TestAddressGenerator { + address: Addr, + predictable_address: Addr, + } + + impl AddressGenerator for TestAddressGenerator { + fn contract_address( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _code_id: u64, + _instance_id: u64, + ) -> AnyResult { + Ok(self.address.clone()) + } + + fn predictable_contract_address( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _code_id: u64, + _instance_id: u64, + _checksum: &[u8], + _creator: &CanonicalAddr, + _salt: &[u8], + ) -> AnyResult { + Ok(self.predictable_address.clone()) + } + } + + #[test] + fn can_use_custom_address_generator() { + let api = MockApi::default(); + let expected_addr = api.addr_make("address"); + let expected_predictable_addr = api.addr_make("predictable_address"); + let mut wasm_keeper: WasmKeeper = + WasmKeeper::new().with_address_generator(TestAddressGenerator { + address: expected_addr.clone(), + predictable_address: expected_predictable_addr.clone(), + }); + let creator = api.addr_make("creator"); + let code_id = wasm_keeper.store_code(creator.clone(), payout::contract()); + + let mut wasm_storage = MockStorage::new(); + + let admin = api.addr_make("admin"); + let contract_addr = wasm_keeper + .register_contract( + &api, + &mut wasm_storage, + code_id, + creator.clone(), + admin.clone(), + "label".to_owned(), + 1000, + None, + ) + .unwrap(); + + assert_eq!( + contract_addr, expected_addr, + "custom address generator returned incorrect address" + ); + + let contract_addr = wasm_keeper + .register_contract( + &api, + &mut wasm_storage, + code_id, + creator, + admin, + "label".to_owned(), + 1000, + Binary::from(HexBinary::from_hex("23A74B8C").unwrap()), + ) + .unwrap(); + + assert_eq!( + contract_addr, expected_predictable_addr, + "custom address generator returned incorrect address" + ); + } +} diff --git a/src/wasm_emulation/api/mod.rs b/src/wasm_emulation/api/mod.rs index 6e786427..707dea7f 100644 --- a/src/wasm_emulation/api/mod.rs +++ b/src/wasm_emulation/api/mod.rs @@ -1,5 +1,5 @@ use crate::wasm_emulation::query::gas::{GAS_COST_CANONICALIZE, GAS_COST_HUMANIZE}; -use bech32::{FromBase32, ToBase32, Variant}; +use bech32::{Bech32, Hrp}; use cosmwasm_std::Addr; use cosmwasm_vm::{BackendApi, BackendError, GasInfo}; use std::ops::AddAssign; @@ -7,23 +7,23 @@ use std::ops::AddAssign; const SHORT_CANON_LEN: usize = 20; const LONG_CANON_LEN: usize = 32; -pub fn bytes_from_bech32(address: &str, prefix: &str) -> Result, BackendError> { +pub fn bytes_from_bech32(address: &str, prefix: &Hrp) -> Result, BackendError> { if address.is_empty() { return Err(BackendError::Unknown { msg: "empty address string is not allowed".to_string(), }); } - let (hrp, data, _variant) = bech32::decode(address).map_err(|e| BackendError::Unknown { + let (hrp, data) = bech32::decode(address).map_err(|e| BackendError::Unknown { msg: format!("Invalid Bech32 address : Err {}", e), })?; - if hrp != prefix { + if hrp.ne(prefix) { return Err(BackendError::Unknown { msg: format!("invalid Bech32 prefix; expected {}, got {}", prefix, hrp), }); } - Ok(Vec::::from_base32(&data).unwrap()) + Ok(data) } pub const MAX_PREFIX_CHARS: usize = 10; @@ -47,7 +47,7 @@ impl RealApi { Self { prefix: api_prefix } } - pub fn get_prefix(&self) -> String { + pub fn get_prefix(&self) -> Result { let mut prefix = Vec::new(); for &c in self.prefix.iter() { @@ -55,7 +55,8 @@ impl RealApi { prefix.push(c); } } - prefix.iter().collect() + let prefix_string: String = prefix.into_iter().collect(); + Hrp::parse(&prefix_string).map_err(|e| BackendError::Unknown { msg: e.to_string() }) } pub fn next_address(&self, count: usize) -> Addr { @@ -112,7 +113,11 @@ impl BackendApi for RealApi { ); } - (bytes_from_bech32(human, &self.get_prefix()), gas_cost) + ( + self.get_prefix() + .and_then(|prefix| bytes_from_bech32(human, &prefix)), + gas_cost, + ) } fn addr_humanize(&self, canonical: &[u8]) -> cosmwasm_vm::BackendResult { @@ -131,8 +136,10 @@ impl BackendApi for RealApi { return (Ok("".to_string()), gas_cost); } - let human = bech32::encode(&self.get_prefix(), canonical.to_base32(), Variant::Bech32) - .map_err(|e| BackendError::Unknown { msg: e.to_string() }); + let human = self.get_prefix().and_then(|prefix| { + bech32::encode::(prefix, canonical) + .map_err(|e| BackendError::Unknown { msg: e.to_string() }) + }); (human, gas_cost) } @@ -149,7 +156,7 @@ mod test { let api = RealApi::new(prefix); let final_prefix = api.get_prefix(); - assert_eq!(prefix, final_prefix); + assert_eq!(prefix, final_prefix.unwrap().as_str()); } #[test] diff --git a/src/wasm_emulation/input.rs b/src/wasm_emulation/input.rs index 2580b591..3babf5ab 100644 --- a/src/wasm_emulation/input.rs +++ b/src/wasm_emulation/input.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use cosmwasm_std::Addr; use cosmwasm_std::{Env, MessageInfo, Reply}; @@ -13,8 +13,8 @@ use super::contract::WasmContract; #[derive(Debug, Clone, Default)] pub struct WasmStorage { pub contracts: HashMap, - pub codes: HashMap, - pub code_data: HashMap, + pub codes: BTreeMap, + pub code_data: BTreeMap, pub storage: Vec<(Vec, Vec)>, } diff --git a/src/wasm_emulation/query/wasm.rs b/src/wasm_emulation/query/wasm.rs index 1ad075fa..6d0e53a6 100644 --- a/src/wasm_emulation/query/wasm.rs +++ b/src/wasm_emulation/query/wasm.rs @@ -1,6 +1,5 @@ use std::marker::PhantomData; -use crate::addons::MockApiBech32; use crate::prefixed_storage::get_full_contract_storage_namespace; use crate::queries::wasm::WasmRemoteQuerier; use crate::wasm_emulation::query::gas::{ @@ -8,7 +7,7 @@ use crate::wasm_emulation::query::gas::{ }; use crate::wasm_emulation::query::mock_querier::QueryResultWithGas; use crate::wasm_emulation::query::MockQuerier; -use crate::Contract; +use crate::{Contract, MockApiBech32}; use crate::wasm_emulation::contract::WasmContract; use cosmwasm_std::testing::MockStorage; From a68fa131ad935b0f090d4864b01464ffc9accdae Mon Sep 17 00:00:00 2001 From: Kayanski Date: Tue, 1 Oct 2024 15:59:55 +0000 Subject: [PATCH 247/250] Less diff and better trait structure --- Cargo.toml | 8 +-- examples/cavern_test_app.rs | 13 +---- examples/counter/contract.rs | 6 +- examples/counter/msg.rs | 6 +- examples/counter/query.rs | 2 +- examples/cousin_test.rs | 10 ++-- examples/test_app.rs | 1 + src/app.rs | 53 ++++++----------- src/app_builder.rs | 47 +++++----------- src/bank.rs | 24 ++++---- src/contracts.rs | 11 ++-- src/error.rs | 3 - src/executor.rs | 1 + src/lib.rs | 10 ++-- src/module.rs | 6 +- src/tests/mod.rs | 6 +- src/tests/test_app.rs | 1 + src/wasm.rs | 72 ++++++++++++------------ src/wasm_emulation/query/mod.rs | 11 +++- tests/test_app_builder/test_with_bank.rs | 13 ++++- tests/test_app_builder/test_with_wasm.rs | 11 ++++ 21 files changed, 154 insertions(+), 161 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d3d9c781..419e7b5e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,15 +1,15 @@ [package] -repository = "https://github.com/CosmWasm/cw-multi-test" +name = "clone-cw-multi-test" version = "0.6.2" authors = [ "Ethan Frey ", "Dariusz Depta ", ] -edition = "2021" description = "Testing tools for multi-contract interactions. Helps simulating chain behavior with on-chain storage locally" -license = "Apache-2.0" -name = "clone-cw-multi-test" +repository = "https://github.com/CosmWasm/cw-multi-test" homepage = "https://cosmwasm.com" +license = "Apache-2.0" +edition = "2021" [package.metadata.docs.rs] all-features = true diff --git a/examples/cavern_test_app.rs b/examples/cavern_test_app.rs index 8c3dfe92..4a852c81 100644 --- a/examples/cavern_test_app.rs +++ b/examples/cavern_test_app.rs @@ -1,8 +1,6 @@ use clone_cw_multi_test::{ - wasm_emulation::{ - channel::RemoteChannel, contract::WasmContract, storage::analyzer::StorageAnalyzer, - }, - AppBuilder, BankKeeper, Executor, MockApiBech32, WasmKeeper, + wasm_emulation::{channel::RemoteChannel, storage::analyzer::StorageAnalyzer}, + AppBuilder, Executor, MockApiBech32, }; use cosmwasm_schema::{cw_serde, QueryResponses}; use cosmwasm_std::{coins, Addr, BlockInfo, ContractInfoResponse, QueryRequest, WasmQuery}; @@ -64,9 +62,6 @@ pub fn test() -> anyhow::Result<()> { chain.network_info.pub_address_prefix, )?; - let wasm = WasmKeeper::::new().with_remote(remote_channel.clone()); - let bank = BankKeeper::new().with_remote(remote_channel.clone()); - let block = runtime.block_on( Node { channel: remote_channel.channel.clone(), @@ -76,8 +71,6 @@ pub fn test() -> anyhow::Result<()> { )?; // First we instantiate a new app let app = AppBuilder::default() - .with_wasm(wasm) - .with_bank(bank) .with_remote(remote_channel.clone()) .with_block(BlockInfo { height: block.height, @@ -125,7 +118,7 @@ pub fn test() -> anyhow::Result<()> { let code = std::fs::read( Path::new(env!("CARGO_MANIFEST_DIR")) .join("artifacts") - .join("counter_contract.wasm"), + .join("counter_contract_with_cousin.wasm"), ) .unwrap(); diff --git a/examples/counter/contract.rs b/examples/counter/contract.rs index d60a1065..3df53e71 100644 --- a/examples/counter/contract.rs +++ b/examples/counter/contract.rs @@ -48,9 +48,9 @@ pub fn execute( #[cfg_attr(feature = "export", entry_point)] pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { match msg { - QueryMsg::Count {} => to_json_binary(&query::count(deps)?), - QueryMsg::CousinCount {} => to_json_binary(&query::cousin_count(deps)?), - QueryMsg::RawCousinCount {} => to_json_binary(&query::raw_cousin_count(deps)?), + QueryMsg::GetCount {} => to_json_binary(&query::count(deps)?), + QueryMsg::GetCousinCount {} => to_json_binary(&query::cousin_count(deps)?), + QueryMsg::GetRawCousinCount {} => to_json_binary(&query::raw_cousin_count(deps)?), } } diff --git a/examples/counter/msg.rs b/examples/counter/msg.rs index 5b8d7dd3..bfd81a99 100644 --- a/examples/counter/msg.rs +++ b/examples/counter/msg.rs @@ -36,13 +36,13 @@ pub enum ExecuteMsg { pub enum QueryMsg { /// GetCount returns the current count as a json-encoded number #[returns(GetCountResponse)] - Count {}, + GetCount {}, /// GetCount returns the current count as a json-encoded number #[returns(GetCountResponse)] - CousinCount {}, + GetCousinCount {}, /// GetCount returns the current count as a json-encoded number #[returns(GetCountResponse)] - RawCousinCount {}, + GetRawCousinCount {}, } // Custom response for the query diff --git a/examples/counter/query.rs b/examples/counter/query.rs index ee237c59..31a1d585 100644 --- a/examples/counter/query.rs +++ b/examples/counter/query.rs @@ -15,7 +15,7 @@ pub fn cousin_count(deps: Deps) -> StdResult { let cousin_count: GetCountResponse = deps.querier.query(&QueryRequest::Wasm(WasmQuery::Smart { contract_addr: state.cousin.unwrap().to_string(), - msg: to_json_binary(&QueryMsg::Count {})?, + msg: to_json_binary(&QueryMsg::GetCount {})?, }))?; Ok(cousin_count) } diff --git a/examples/cousin_test.rs b/examples/cousin_test.rs index 71806ebb..e592dc38 100644 --- a/examples/cousin_test.rs +++ b/examples/cousin_test.rs @@ -5,8 +5,8 @@ use std::path::Path; use anyhow::Result as AnyResult; use clone_cw_multi_test::{ - wasm_emulation::channel::RemoteChannel, App, AppBuilder, BankKeeper, ContractWrapper, Executor, - MockApiBech32, WasmKeeper, + wasm_emulation::{channel::RemoteChannel, query::ContainsRemote}, + App, AppBuilder, BankKeeper, ContractWrapper, Executor, MockApiBech32, WasmKeeper, }; use cosmwasm_std::{Addr, Empty}; use counter::msg::{ExecuteMsg, GetCountResponse, QueryMsg}; @@ -30,7 +30,7 @@ fn increment(app: &mut App, contract: Addr) -> AnyRes fn count(app: &App, contract: Addr) -> AnyResult { Ok(app .wrap() - .query_wasm_smart(contract.clone(), &QueryMsg::Count {})?) + .query_wasm_smart(contract.clone(), &QueryMsg::GetCount {})?) } fn raw_cousin_count( @@ -39,7 +39,7 @@ fn raw_cousin_count( ) -> AnyResult { Ok(app .wrap() - .query_wasm_smart(contract.clone(), &QueryMsg::RawCousinCount {})?) + .query_wasm_smart(contract.clone(), &QueryMsg::GetRawCousinCount {})?) } fn cousin_count( @@ -48,7 +48,7 @@ fn cousin_count( ) -> AnyResult { Ok(app .wrap() - .query_wasm_smart(contract.clone(), &QueryMsg::CousinCount {})?) + .query_wasm_smart(contract.clone(), &QueryMsg::GetCousinCount {})?) } fn test() -> AnyResult<()> { diff --git a/examples/test_app.rs b/examples/test_app.rs index d3f92cd3..7e46b5c4 100644 --- a/examples/test_app.rs +++ b/examples/test_app.rs @@ -1,3 +1,4 @@ +use clone_cw_multi_test::wasm_emulation::query::ContainsRemote; use clone_cw_multi_test::{ wasm_emulation::channel::RemoteChannel, AppBuilder, BankKeeper, Executor, WasmKeeper, }; diff --git a/src/app.rs b/src/app.rs index e001bd1f..82c88ee1 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,8 +1,6 @@ -use crate::wasm_emulation::api::RealApi; use crate::wasm_emulation::channel::RemoteChannel; use crate::wasm_emulation::input::QuerierStorage; use cosmwasm_std::CustomMsg; -use cw_storage_plus::Item; use crate::bank::{Bank, BankKeeper, BankSudo}; use crate::error::{bail, AnyResult}; @@ -29,8 +27,6 @@ use serde::{de::DeserializeOwned, Serialize}; use std::fmt::Debug; use std::marker::PhantomData; -const ADDRESSES: Item> = Item::new("addresses"); - /// Advances the blockchain environment to the next block in tests, enabling developers to simulate /// time-dependent contract behaviors and block-related triggers efficiently. pub fn next_block(block: &mut BlockInfo) { @@ -258,17 +254,6 @@ where CustomT::ExecT: CustomMsg + DeserializeOwned + 'static, CustomT::QueryT: CustomQuery + DeserializeOwned + 'static, { - /// Registers contract code (like uploading wasm bytecode on a chain), - /// so it can later be used to instantiate a contract. - /// Only for wasm codes - pub fn store_wasm_code(&mut self, code: Vec) -> u64 { - self.init_modules(|router, _, _| { - router - .wasm - .store_wasm_code(Addr::unchecked("code-creator"), code) - }) - } - /// 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 { @@ -277,12 +262,6 @@ where .store_code(MockApi::default().addr_make("creator"), code) } - /// Registers contract code (like [store_code](Self::store_code)), - /// but takes the address of the code creator as an additional argument. - pub fn store_wasm_code_with_creator(&mut self, creator: Addr, code: Vec) -> u64 { - self.init_modules(|router, _, _| router.wasm.store_wasm_code(creator, code)) - } - /// Registers contract code (like [store_code](Self::store_code)), /// but takes the address of the code creator as an additional argument. pub fn store_code_with_creator( @@ -293,6 +272,22 @@ where self.router.wasm.store_code(creator, code) } + /// Registers contract code (like uploading wasm bytecode on a chain), + /// so it can later be used to instantiate a contract. + /// Only for wasm codes + pub fn store_wasm_code(&mut self, code: Vec) -> u64 { + self.init_modules(|router, _, _| { + router + .wasm + .store_wasm_code(Addr::unchecked("code-creator"), code) + }) + } + /// Registers contract code (like [store_code](Self::store_code)), + /// but takes the address of the code creator as an additional argument. + pub fn store_wasm_code_with_creator(&mut self, creator: Addr, code: Vec) -> u64 { + self.init_modules(|router, _, _| router.wasm.store_wasm_code(creator, code)) + } + /// Registers contract code (like [store_code_with_creator](Self::store_code_with_creator)), /// but takes the code identifier as an additional argument. pub fn store_code_with_id( @@ -447,22 +442,6 @@ where self.block.clone() } - /// Returns a new account address - pub fn next_address(&mut self) -> Addr { - let Self { - storage, remote, .. - } = self; - - let mut addresses = ADDRESSES.may_load(storage).unwrap().unwrap_or_default(); - - let new_address = - RealApi::new(&remote.pub_address_prefix.clone()).next_address(addresses.len()); - addresses.push(new_address.clone()); - ADDRESSES.save(storage, &addresses).unwrap(); - - new_address - } - /// Simple helper so we get access to all the QuerierWrapper helpers, /// e.g. wrap().query_wasm_smart, query_all_balances, ... pub fn wrap(&self) -> QuerierWrapper { diff --git a/src/app_builder.rs b/src/app_builder.rs index 3c14131a..94929310 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -152,6 +152,7 @@ impl, + BankT: Bank, CustomT::QueryT: CustomQuery, { /// Overwrites the default wasm executor. @@ -161,7 +162,7 @@ where /// done on final building. pub fn with_wasm>( self, - wasm: NewWasm, + mut wasm: NewWasm, ) -> AppBuilder { let AppBuilder { @@ -178,7 +179,9 @@ where stargate, .. } = self; - + if let Some(remote) = remote.as_ref() { + wasm.set_remote(remote.clone()); + } AppBuilder { api, block, @@ -198,7 +201,7 @@ where /// Overwrites the default bank interface. pub fn with_bank( self, - bank: NewBank, + mut bank: NewBank, ) -> AppBuilder { let AppBuilder { @@ -216,6 +219,9 @@ where .. } = self; + if let Some(remote) = remote.as_ref() { + bank.set_remote(remote.clone()); + } AppBuilder { api, block, @@ -513,39 +519,14 @@ where /// Sets the chain of the app pub fn with_remote( - self, + mut self, remote: RemoteChannel, ) -> AppBuilder { - let AppBuilder { - wasm, - api, - storage, - custom, - block, - staking, - bank, - distribution, - ibc, - gov, - stargate, - .. - } = self; - - AppBuilder { - api, - block, - storage, - bank, - wasm, - custom, - staking, - distribution, - ibc, - gov, - stargate, - remote: Some(remote), - } + self.remote = Some(remote.clone()); + self.wasm.set_remote(remote.clone()); + self.bank.set_remote(remote.clone()); + self } /// Overwrites the default stargate interface. diff --git a/src/bank.rs b/src/bank.rs index 18a5a95a..14f8781f 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -5,7 +5,7 @@ use crate::module::Module; use crate::prefixed_storage::{prefixed, prefixed_read}; use crate::queries::bank::BankRemoteQuerier; use crate::wasm_emulation::channel::RemoteChannel; -use crate::wasm_emulation::query::AllBankQuerier; +use crate::wasm_emulation::query::{AllBankQuerier, ContainsRemote}; use cosmwasm_std::{ coin, to_json_binary, Addr, AllBalanceResponse, Api, BalanceResponse, BankMsg, BankQuery, Binary, BlockInfo, Coin, DenomMetadata, Event, Querier, Storage, @@ -46,7 +46,7 @@ pub enum BankSudo { /// like transfers and balance checks, within your smart contracts. /// This trait implements all of these functionalities. pub trait Bank: - Module + AllBankQuerier + Module + AllBankQuerier + ContainsRemote { } @@ -66,15 +66,6 @@ impl BankKeeper { Self::default() } - pub fn with_remote(mut self, remote: RemoteChannel) -> Self { - self.remote = Some(remote); - self - } - - pub fn set_remote(&mut self, remote: RemoteChannel) { - self.remote = Some(remote); - } - /// Administration function for adjusting bank accounts in genesis. pub fn init_balance( &self, @@ -186,6 +177,17 @@ impl BankKeeper { } } +impl ContainsRemote for BankKeeper { + fn with_remote(mut self, remote: RemoteChannel) -> Self { + self.set_remote(remote); + self + } + + fn set_remote(&mut self, remote: RemoteChannel) { + self.remote = Some(remote) + } +} + fn coins_to_string(coins: &[Coin]) -> String { coins .iter() diff --git a/src/contracts.rs b/src/contracts.rs index 6f5202b4..868c3146 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -5,9 +5,10 @@ use crate::wasm_emulation::query::mock_querier::ForkState; use crate::wasm_emulation::query::MockQuerier; use crate::wasm_emulation::storage::dual_std_storage::DualStorage; use crate::wasm_emulation::storage::storage_wrappers::{ReadonlyStorageWrapper, StorageWrapper}; +use anyhow::Error as AnyError; use cosmwasm_std::{ from_json, Binary, Checksum, CosmosMsg, CustomMsg, CustomQuery, Deps, DepsMut, Empty, Env, - MessageInfo, QuerierWrapper, Reply, Response, StdError, SubMsg, + MessageInfo, QuerierWrapper, Reply, Response, SubMsg, }; use serde::de::DeserializeOwned; use std::fmt::{Debug, Display}; @@ -177,10 +178,10 @@ pub struct ContractWrapper< C = Empty, Q = Empty, T4 = Empty, - E4 = StdError, - E5 = StdError, + E4 = AnyError, + E5 = AnyError, T6 = Empty, - E6 = StdError, + E6 = AnyError, > where T1: DeserializeOwned, // Type of message passed to `execute` entry-point. T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point. @@ -198,7 +199,7 @@ pub struct ContractWrapper< { execute_fn: ContractClosure, instantiate_fn: ContractClosure, - pub query_fn: QueryClosure, + query_fn: QueryClosure, sudo_fn: Option>, reply_fn: Option>, migrate_fn: Option>, diff --git a/src/error.rs b/src/error.rs index b6c26c8a..b5c3c09a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -51,9 +51,6 @@ pub enum Error { /// Error variant for reporting duplicated contract addresses. #[error("Contract with this address already exists: {0}")] DuplicatedContractAddress(String), - - #[error("Unregistered contract address, not present locally or on-chain")] - UnregisteredContractAddress(String), } impl Error { diff --git a/src/executor.rs b/src/executor.rs index ed2a5fad..5269276b 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -107,6 +107,7 @@ where /// Instantiates a new contract and returns its predictable address. /// This is a helper function around [execute][Self::execute] function /// with `WasmMsg::Instantiate2` message. + #[cfg(feature = "cosmwasm_1_2")] fn instantiate2_contract( &mut self, code_id: u64, diff --git a/src/lib.rs b/src/lib.rs index fe6b3533..4923842b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -139,7 +139,6 @@ mod gov; mod ibc; mod module; pub(crate) mod prefixed_storage; -pub mod queries; #[cfg(feature = "staking")] mod staking; mod stargate; @@ -147,7 +146,11 @@ mod test_helpers; pub(crate) mod tests; mod transactions; mod wasm; + +// --- Clone Testing Modules --- // +pub mod queries; pub mod wasm_emulation; +// --- End --- // pub use crate::addresses::{ AddressGenerator, IntoAddr, IntoBech32, IntoBech32m, SimpleAddressGenerator, @@ -169,6 +172,5 @@ pub use crate::staking::{ Distribution, DistributionKeeper, StakeKeeper, Staking, StakingInfo, StakingSudo, }; pub use crate::stargate::{Stargate, StargateAccepting, StargateFailing}; -pub use crate::wasm::{ - ContractData, Wasm, WasmKeeper, WasmSudo, LOCAL_RUST_CODE_OFFSET, LOCAL_WASM_CODE_OFFSET, -}; +pub use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; +pub use crate::wasm::{LOCAL_RUST_CODE_OFFSET, LOCAL_WASM_CODE_OFFSET}; diff --git a/src/module.rs b/src/module.rs index 7b0dc9d1..cc73a4d6 100644 --- a/src/module.rs +++ b/src/module.rs @@ -103,7 +103,7 @@ where sender: Addr, msg: Self::ExecT, ) -> AnyResult { - bail!("Unexpected exec msg {:?} from {:?}", msg, sender,) + bail!("Unexpected exec msg {:?} from {:?}", msg, sender) } /// Runs any [QueryT](Self::QueryT) message, always returns an error. @@ -115,7 +115,7 @@ where _block: &BlockInfo, request: Self::QueryT, ) -> AnyResult { - bail!("Unexpected custom query {:?}", request,) + bail!("Unexpected custom query {:?}", request) } /// Runs any [SudoT](Self::SudoT) privileged action, always returns an error. @@ -127,7 +127,7 @@ where _block: &BlockInfo, msg: Self::SudoT, ) -> AnyResult { - bail!("Unexpected sudo msg {:?}", msg,) + bail!("Unexpected sudo msg {:?}", msg) } } /// # Always accepting module diff --git a/src/tests/mod.rs b/src/tests/mod.rs index c7a06491..a313b471 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -6,7 +6,11 @@ use cw_orch::{ prelude::ChainInfo, }; -use crate::{no_init, wasm_emulation::channel::RemoteChannel, App, AppBuilder, WasmKeeper}; +use crate::{ + no_init, + wasm_emulation::{channel::RemoteChannel, query::ContainsRemote}, + App, AppBuilder, WasmKeeper, +}; pub const CHAIN: ChainInfo = XION_TESTNET_1; pub fn remote_channel() -> RemoteChannel { RemoteChannel::new( diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index f6cc7290..c501d232 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -7,6 +7,7 @@ use crate::tests::{default_app, remote_channel}; use crate::transactions::{transactional, StorageTransaction}; use crate::wasm::ContractData; use crate::wasm_emulation::channel::RemoteChannel; +use crate::wasm_emulation::query::ContainsRemote; use crate::{ custom_app, next_block, no_init, App, AppResponse, Bank, CosmosRouter, Executor, Module, Router, Wasm, WasmKeeper, WasmSudo, diff --git a/src/wasm.rs b/src/wasm.rs index fa1b56ab..371f4056 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -12,7 +12,7 @@ use crate::wasm_emulation::contract::{LocalWasmContract, WasmContract}; use crate::wasm_emulation::input::QuerierStorage; use crate::wasm_emulation::instance::create_module; use crate::wasm_emulation::query::mock_querier::{ForkState, LocalForkedState}; -use crate::wasm_emulation::query::AllWasmQuerier; +use crate::wasm_emulation::query::{AllWasmQuerier, ContainsRemote}; use cosmwasm_std::testing::mock_wasmd_attr; use cosmwasm_std::{ to_json_binary, Addr, Api, Attribute, BankMsg, Binary, BlockInfo, Checksum, Coin, ContractInfo, @@ -89,7 +89,7 @@ pub struct CodeData { pub source_id: usize, } /// This trait implements the interface of the Wasm module. -pub trait Wasm: AllWasmQuerier { +pub trait Wasm: AllWasmQuerier + ContainsRemote { /// Handles all `WasmMsg` messages. fn execute( &self, @@ -196,7 +196,7 @@ pub struct WasmKeeper { // chain on which the contract should be queried/tested against remote: Option, /// 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 { @@ -277,7 +277,7 @@ where let code_data = self.code_data(code_id)?; let res = cosmwasm_std::CodeInfoResponse::new( code_id, - code_data.creator, + code_data.creator.clone(), code_data.checksum, ); to_json_binary(&res).map_err(Into::into) @@ -342,7 +342,6 @@ where let code_id = self .next_code_id() .unwrap_or_else(|| panic!("{}", Error::NoMoreCodeIdAvailable)); - self.save_code(code_id, creator, code) } @@ -383,12 +382,12 @@ where /// Returns `ContractData` for the contract with specified address. fn contract_data(&self, storage: &dyn Storage, address: &Addr) -> AnyResult { - let contract = CONTRACTS.load(&prefixed_read(storage, NAMESPACE_WASM), address); - if let Ok(local_contract) = contract { - Ok(local_contract) - } else { - WasmRemoteQuerier::load_distant_contract(self.remote.clone().unwrap(), address) - } + CONTRACTS + .load(&prefixed_read(storage, NAMESPACE_WASM), address) + .or_else(|_| { + WasmRemoteQuerier::load_distant_contract(self.remote.clone().unwrap(), address) + }) + .map_err(Into::into) } /// Returns a raw state dump of all key-values held by a contract with specified address. @@ -514,17 +513,6 @@ where self } - /// Specify the remote location of this wasm - pub fn with_remote(mut self, remote: RemoteChannel) -> Self { - self.remote = Some(remote); - self - } - - /// Specify the remote location of this wasm - pub fn set_remote(&mut self, remote: RemoteChannel) { - self.remote = Some(remote); - } - /// Returns a handler to code of the contract with specified code id. pub fn contract_code<'a, 'b>( &'a self, @@ -684,14 +672,14 @@ where /// Returns the value stored under specified key in contracts storage. pub fn query_raw(&self, address: Addr, storage: &dyn Storage, key: &[u8]) -> Binary { let storage = self.contract_storage(storage, &address); - let local_key = storage.get(key); - if let Some(local_key) = local_key { - local_key.into() - } else { - WasmRemoteQuerier::raw_query(self.remote.clone().unwrap(), &address, key.into()) - .unwrap_or_default() - .into() - } + let data = storage + .get(key) + .or_else(|| { + WasmRemoteQuerier::raw_query(self.remote.clone().unwrap(), &address, key.into()) + .ok() + }) + .unwrap_or_default(); + data.into() } fn send( @@ -795,7 +783,6 @@ where Event::new("execute").add_attribute(CONTRACT_ATTR, &contract_addr); let (res, msgs) = self.build_app_response(&contract_addr, custom_event, res); - let mut res = self.process_response(api, router, storage, block, contract_addr, res, msgs)?; res.data = execute_response(res.data); @@ -938,7 +925,6 @@ where .add_attribute("code_id", code_id.to_string()); let (res, msgs) = self.build_app_response(&contract_addr, custom_event, res); - let mut res = self.process_response( api, router, @@ -1383,8 +1369,8 @@ where action(handler, deps, env) } - fn with_storage<'a, 'b, F, T>( - &'a self, + fn with_storage( + &self, api: &dyn Api, storage: &mut dyn Storage, router: &dyn CosmosRouter, @@ -1393,8 +1379,7 @@ where action: F, ) -> AnyResult where - F: FnOnce(ContractBox<'b, ExecC, QueryC>, DepsMut, Env) -> AnyResult, - 'a: 'b, + F: FnOnce(ContractBox, DepsMut, Env) -> AnyResult, ExecC: DeserializeOwned, { let contract = self.contract_data(storage, &address)?; @@ -1443,6 +1428,21 @@ where } } +impl ContainsRemote for WasmKeeper +where + ExecC: CustomMsg + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, +{ + fn with_remote(mut self, remote: RemoteChannel) -> Self { + self.set_remote(remote); + self + } + + fn set_remote(&mut self, remote: RemoteChannel) { + self.remote = Some(remote) + } +} + #[derive(Clone, PartialEq, Message)] struct InstantiateResponse { #[prost(string, tag = "1")] diff --git a/src/wasm_emulation/query/mod.rs b/src/wasm_emulation/query/mod.rs index 258bc0b7..d483e656 100644 --- a/src/wasm_emulation/query/mod.rs +++ b/src/wasm_emulation/query/mod.rs @@ -9,7 +9,16 @@ pub mod gas; use anyhow::Result as AnyResult; -use super::input::{BankStorage, WasmStorage}; +use super::{ + channel::RemoteChannel, + input::{BankStorage, WasmStorage}, +}; + +pub trait ContainsRemote { + fn with_remote(self, remote: RemoteChannel) -> Self; + + fn set_remote(&mut self, remote: RemoteChannel); +} pub trait AllWasmQuerier { fn query_all(&self, storage: &dyn Storage) -> AnyResult; diff --git a/tests/test_app_builder/test_with_bank.rs b/tests/test_app_builder/test_with_bank.rs index 95944247..b17906bc 100644 --- a/tests/test_app_builder/test_with_bank.rs +++ b/tests/test_app_builder/test_with_bank.rs @@ -2,7 +2,9 @@ use crate::test_app_builder::MyKeeper; use anyhow::bail; use cosmwasm_std::{coins, BankMsg, BankQuery}; use cw_multi_test::{ - no_init, wasm_emulation::query::AllBankQuerier, AppBuilder, Bank, BankSudo, Executor, + no_init, + wasm_emulation::query::{AllBankQuerier, ContainsRemote}, + AppBuilder, Bank, BankSudo, Executor, }; type MyBankKeeper = MyKeeper; @@ -16,6 +18,15 @@ impl AllBankQuerier for MyBankKeeper { bail!(self.1) } } +impl ContainsRemote for MyBankKeeper { + fn with_remote(self, _remote: cw_multi_test::wasm_emulation::channel::RemoteChannel) -> Self { + todo!() + } + + fn set_remote(&mut self, _remote: cw_multi_test::wasm_emulation::channel::RemoteChannel) { + todo!() + } +} const EXECUTE_MSG: &str = "bank execute called"; const QUERY_MSG: &str = "bank query called"; diff --git a/tests/test_app_builder/test_with_wasm.rs b/tests/test_app_builder/test_with_wasm.rs index 24326395..aa6fdc79 100644 --- a/tests/test_app_builder/test_with_wasm.rs +++ b/tests/test_app_builder/test_with_wasm.rs @@ -1,5 +1,6 @@ use crate::cw_multi_test::wasm_emulation::input::WasmStorage; use crate::cw_multi_test::wasm_emulation::query::AllWasmQuerier; +use crate::cw_multi_test::wasm_emulation::query::ContainsRemote; use crate::test_app_builder::MyKeeper; use crate::test_contracts; use cosmwasm_std::{ @@ -26,6 +27,16 @@ static WASM_RAW: Lazy> = Lazy::new(|| vec![(vec![154u8], vec![155u8] // when custom wasm keeper implements also Module trait (although it is not needed). type MyWasmKeeper = MyKeeper; +impl ContainsRemote for MyWasmKeeper { + fn with_remote(self, _remote: cw_multi_test::wasm_emulation::channel::RemoteChannel) -> Self { + todo!() + } + + fn set_remote(&mut self, _remote: cw_multi_test::wasm_emulation::channel::RemoteChannel) { + todo!() + } +} + impl Wasm for MyWasmKeeper { fn execute( &self, From 405c9e32b72e0f21504163952dce0c6ec59c1ad9 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Wed, 2 Oct 2024 07:09:31 +0000 Subject: [PATCH 248/250] Less diff even --- src/tests/test_app.rs | 3 ++- src/tests/test_gov.rs | 2 +- src/tests/test_ibc.rs | 2 +- src/tests/test_stargate.rs | 2 +- src/wasm.rs | 23 +++++++++++++---------- 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index c501d232..a05bcd76 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -3,7 +3,8 @@ use crate::error::{bail, AnyResult}; use crate::featured::staking::{Distribution, Staking}; use crate::test_helpers::echo::EXECUTE_REPLY_BASE_ID; use crate::test_helpers::{caller, echo, error, hackatom, payout, reflect, CustomHelperMsg}; -use crate::tests::{default_app, remote_channel}; +use crate::tests::default_app; +use crate::tests::remote_channel; use crate::transactions::{transactional, StorageTransaction}; use crate::wasm::ContractData; use crate::wasm_emulation::channel::RemoteChannel; diff --git a/src/tests/test_gov.rs b/src/tests/test_gov.rs index 8e621d46..60dd5b7d 100644 --- a/src/tests/test_gov.rs +++ b/src/tests/test_gov.rs @@ -1,7 +1,7 @@ #![cfg(feature = "stargate")] use crate::test_helpers::gov; -use crate::tests::test_app::default_app; +use crate::tests::default_app; use crate::{no_init, App, AppBuilder, Executor, GovAcceptingModule}; use cosmwasm_std::Empty; #[test] diff --git a/src/tests/test_ibc.rs b/src/tests/test_ibc.rs index 175c012d..295ced67 100644 --- a/src/tests/test_ibc.rs +++ b/src/tests/test_ibc.rs @@ -1,7 +1,7 @@ #![cfg(feature = "stargate")] use crate::test_helpers::ibc; -use crate::tests::test_app::default_app; +use crate::tests::default_app; use crate::{no_init, App, AppBuilder, Executor, IbcAcceptingModule}; use cosmwasm_std::Empty; #[test] diff --git a/src/tests/test_stargate.rs b/src/tests/test_stargate.rs index 4667a03f..2e667d38 100644 --- a/src/tests/test_stargate.rs +++ b/src/tests/test_stargate.rs @@ -1,7 +1,7 @@ #![cfg(feature = "stargate")] use crate::test_helpers::stargate; -use crate::tests::test_app::default_app; +use crate::tests::default_app; use crate::{no_init, App, AppBuilder, Executor, StargateAccepting}; use cosmwasm_std::Empty; #[test] diff --git a/src/wasm.rs b/src/wasm.rs index 371f4056..1071a93f 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -548,17 +548,20 @@ where if code_id < 1 { bail!(Error::invalid_code_id()); } - if let Some(code_data) = self.code_data.get(&code_id) { - Ok(code_data.clone()) - } else { - let code_info_response = - WasmRemoteQuerier::code_info(self.remote.clone().unwrap(), code_id)?; - Ok(CodeData { - creator: Addr::unchecked(code_info_response.creator), - checksum: code_info_response.checksum, - source_id: code_id as usize, + Ok(self + .code_data + .get(&code_id) + .cloned() + .ok_or_else(|| { + let code_info_response = + WasmRemoteQuerier::code_info(self.remote.clone().unwrap(), code_id)?; + Ok::<_, anyhow::Error>(CodeData { + creator: Addr::unchecked(code_info_response.creator), + checksum: code_info_response.checksum, + source_id: code_id as usize, + }) }) - } + .map_err(|_| Error::unregistered_code_id(code_id))?) } pub fn dump_wasm_raw(&self, storage: &dyn Storage, address: &Addr) -> Vec { From f209adf9b378d5e0361cb33e95e31198d2267912 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Wed, 2 Oct 2024 07:11:15 +0000 Subject: [PATCH 249/250] Removed useless lifetimes --- src/wasm.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/wasm.rs b/src/wasm.rs index 1071a93f..e96137f9 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -514,13 +514,7 @@ where } /// Returns a handler to code of the contract with specified code id. - pub fn contract_code<'a, 'b>( - &'a self, - code_id: u64, - ) -> AnyResult> - where - 'a: 'b, - { + pub fn contract_code(&self, code_id: u64) -> AnyResult> { let code = self.code_base.borrow().get(&code_id).cloned(); if let Some(code) = code { Ok(ContractBox::Owned(Box::new(code))) @@ -1346,8 +1340,8 @@ where } } - fn with_storage_readonly<'a, 'b, F, T>( - &'a self, + fn with_storage_readonly( + &self, api: &dyn Api, storage: &dyn Storage, querier: &dyn Querier, @@ -1356,11 +1350,10 @@ where action: F, ) -> AnyResult where - F: FnOnce(ContractBox<'b, ExecC, QueryC>, Deps, Env) -> AnyResult, - 'a: 'b, + F: FnOnce(ContractBox, Deps, Env) -> AnyResult, { let contract = self.contract_data(storage, &address)?; - let handler = self.contract_code::<'a, 'b>(contract.code_id)?; + let handler = self.contract_code(contract.code_id)?; let storage = self.contract_storage(storage, &address); let env = self.get_env(address, block); From de8605811db326ca37ca46125cbeda3e3e92cb6d Mon Sep 17 00:00:00 2001 From: Kayanski Date: Tue, 14 Jan 2025 18:10:29 +0100 Subject: [PATCH 250/250] Less diff --- Cargo.lock | 4 +- Cargo.toml | 2 +- src/addresses.rs | 2 +- src/app.rs | 34 ++++++++++-- src/tests/test_app.rs | 125 +++++++++++++++++++++--------------------- src/wasm.rs | 1 + 6 files changed, 99 insertions(+), 69 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53e48811..17a01b41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "abstract-cw-multi-test" @@ -670,7 +670,7 @@ dependencies = [ [[package]] name = "clone-cw-multi-test" -version = "0.6.2" +version = "0.7.0" dependencies = [ "anyhow", "bech32 0.11.0", diff --git a/Cargo.toml b/Cargo.toml index 419e7b5e..b33813e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clone-cw-multi-test" -version = "0.6.2" +version = "0.7.0" authors = [ "Ethan Frey ", "Dariusz Depta ", diff --git a/src/addresses.rs b/src/addresses.rs index f4edc837..43d49341 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -7,7 +7,7 @@ use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage}; use sha2::digest::Update; use sha2::{Digest, Sha256}; -const DEFAULT_PREFIX: &str = "xion"; +const DEFAULT_PREFIX: &str = "cosmwasm"; /// Defines conversions to [Addr], this conversion is format agnostic /// and should be aligned with the format generated by [MockApi]. diff --git a/src/app.rs b/src/app.rs index 82c88ee1..8bf0c2c2 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,5 +1,6 @@ use crate::wasm_emulation::channel::RemoteChannel; use crate::wasm_emulation::input::QuerierStorage; +use crate::wasm_emulation::query::ContainsRemote; use cosmwasm_std::CustomMsg; use crate::bank::{Bank, BankKeeper, BankSudo}; @@ -72,6 +73,31 @@ pub struct App< pub(crate) remote: RemoteChannel, } +impl ContainsRemote + for App +{ + fn with_remote(self, remote: RemoteChannel) -> Self { + let Self { + router, + api, + storage, + block, + .. + } = self; + Self { + router, + api, + storage, + block, + remote, + } + } + + fn set_remote(&mut self, remote: RemoteChannel) { + self.remote = remote; + } +} + /// No-op application initialization function. pub fn no_init( router: &mut Router, @@ -83,7 +109,7 @@ pub fn no_init(remote: RemoteChannel, init_fn: F) -> Self + pub fn new(init_fn: F) -> Self where F: FnOnce( &mut Router< @@ -100,13 +126,13 @@ impl BasicApp { &mut dyn Storage, ), { - AppBuilder::new().with_remote(remote).build(init_fn) + AppBuilder::new().build(init_fn) } } /// Creates new default `App` implementation working with customized exec and query messages. /// Outside the `App` implementation to make type elision better. -pub fn custom_app(remote: RemoteChannel, init_fn: F) -> BasicApp +pub fn custom_app(init_fn: F) -> BasicApp where ExecC: CustomMsg + DeserializeOwned + 'static, QueryC: Debug + CustomQuery + DeserializeOwned + 'static, @@ -125,7 +151,7 @@ where &mut dyn Storage, ), { - AppBuilder::new_custom().with_remote(remote).build(init_fn) + AppBuilder::new_custom().build(init_fn) } impl Querier diff --git a/src/tests/test_app.rs b/src/tests/test_app.rs index a05bcd76..757e5dd2 100644 --- a/src/tests/test_app.rs +++ b/src/tests/test_app.rs @@ -7,11 +7,10 @@ use crate::tests::default_app; use crate::tests::remote_channel; use crate::transactions::{transactional, StorageTransaction}; use crate::wasm::ContractData; -use crate::wasm_emulation::channel::RemoteChannel; use crate::wasm_emulation::query::ContainsRemote; use crate::{ custom_app, next_block, no_init, App, AppResponse, Bank, CosmosRouter, Executor, Module, - Router, Wasm, WasmKeeper, WasmSudo, + Router, Wasm, WasmSudo, }; use crate::{AppBuilder, IntoAddr}; use cosmwasm_std::testing::{mock_env, MockQuerier}; @@ -21,7 +20,6 @@ use cosmwasm_std::{ OverflowError, OverflowOperation, Querier, Reply, StdError, StdResult, Storage, SubMsg, WasmMsg, }; -use cw_orch::daemon::RUNTIME; use cw_storage_plus::Item; use cw_utils::parse_instantiate_response_data; use schemars::JsonSchema; @@ -119,12 +117,13 @@ fn multi_level_bank_cache() { // set personal balance let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; - let mut app = App::new(remote_channel(), |router, _, storage| { + let mut app = App::new(|router, _, storage| { router .bank .init_balance(storage, &owner_addr, init_funds) .unwrap(); - }); + }) + .with_remote(remote_channel()); // cache 1 - send some tokens let mut cache = StorageTransaction::new(app.storage()); @@ -203,7 +202,7 @@ fn send_tokens() { // set personal balance let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let rcpt_funds = vec![coin(5, "btc")]; - let mut app = App::new(remote_channel(), |router, _, storage| { + let mut app = App::new(|router, _, storage| { // initialization moved to App construction router .bank @@ -213,7 +212,8 @@ fn send_tokens() { .bank .init_balance(storage, &recipient_addr, rcpt_funds) .unwrap(); - }); + }) + .with_remote(remote_channel()); // send both tokens let to_send = vec![coin(30, "eth"), coin(5, "btc")]; @@ -250,12 +250,13 @@ fn simple_contract() { // set personal balance let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; - let mut app = App::new(remote_channel(), |router, _, storage| { + let mut app = App::new(|router, _, storage| { router .bank .init_balance(storage, &owner_addr, init_funds) .unwrap(); - }); + }) + .with_remote(remote_channel()); // set up contract let code_id = app.store_code(payout::contract()); @@ -339,15 +340,15 @@ fn reflect_success() { // set personal balance let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; - let mut app = - custom_app::(remote_channel(), |router, _, storage| { - router - .bank - .init_balance(storage, &owner_addr, init_funds) - .unwrap(); - router.bank.set_remote(remote_channel()); - router.wasm.set_remote(remote_channel()); - }); + let mut app = custom_app::(|router, _, storage| { + router + .bank + .init_balance(storage, &owner_addr, init_funds) + .unwrap(); + router.bank.set_remote(remote_channel()); + router.wasm.set_remote(remote_channel()); + }) + .with_remote(remote_channel()); // set up payout contract let payout_id = app.store_code(payout::contract()); @@ -449,15 +450,15 @@ fn reflect_error() { // set personal balance let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; - let mut app = - custom_app::(remote_channel(), |router, _, storage| { - router - .bank - .init_balance(storage, &owner, init_funds) - .unwrap(); - router.bank.set_remote(remote_channel()); - router.wasm.set_remote(remote_channel()); - }); + let mut app = custom_app::(|router, _, storage| { + router + .bank + .init_balance(storage, &owner, init_funds) + .unwrap(); + router.bank.set_remote(remote_channel()); + router.wasm.set_remote(remote_channel()); + }) + .with_remote(remote_channel()); // set up reflect contract let reflect_id = app.store_code(reflect::contract()); @@ -549,12 +550,13 @@ fn sudo_works() { // set personal balance let init_funds = vec![coin(100, "eth")]; - let mut app = App::new(remote_channel(), |router, _, storage| { + let mut app = App::new(|router, _, storage| { router .bank .init_balance(storage, &owner_addr, init_funds) .unwrap(); - }); + }) + .with_remote(remote_channel()); let payout_id = app.store_code(payout::contract()); @@ -613,15 +615,15 @@ fn reflect_sub_message_reply_works() { // set personal balance let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; - let mut app = - custom_app::(remote_channel(), |router, _, storage| { - router - .bank - .init_balance(storage, &owner, init_funds) - .unwrap(); - router.bank.set_remote(remote_channel()); - router.wasm.set_remote(remote_channel()); - }); + let mut app = custom_app::(|router, _, storage| { + router + .bank + .init_balance(storage, &owner, init_funds) + .unwrap(); + router.bank.set_remote(remote_channel()); + router.wasm.set_remote(remote_channel()); + }) + .with_remote(remote_channel()); // set up reflect contract let reflect_id = app.store_code(reflect::contract()); @@ -779,12 +781,13 @@ fn sent_wasm_migration_works() { // set personal balance let init_funds = coins(30, "btc"); - let mut app = App::new(remote_channel(), |router, _, storage| { + let mut app = App::new(|router, _, storage| { router .bank .init_balance(storage, &owner_addr, init_funds) .unwrap(); - }); + }) + .with_remote(remote_channel()); // create a hackatom contract with some funds let code_id = app.store_code(hackatom::contract()); @@ -854,12 +857,13 @@ fn sent_funds_properly_visible_on_execution() { // set personal balance let init_funds = coins(30, "btc"); - let mut app = App::new(remote_channel(), |router, _, storage| { + let mut app = App::new(|router, _, storage| { router .bank .init_balance(storage, &owner_addr, init_funds) .unwrap(); - }); + }) + .with_remote(remote_channel()); let code_id = app.store_code(hackatom::contract()); @@ -1230,15 +1234,15 @@ mod reply_data_overwrite { // set personal balance let init_funds = coins(100, "tgd"); - let mut app = - custom_app::(remote_channel(), |router, _, storage| { - router - .bank - .init_balance(storage, &owner, init_funds) - .unwrap(); - router.bank.set_remote(remote_channel()); - router.wasm.set_remote(remote_channel()); - }); + let mut app = custom_app::(|router, _, storage| { + router + .bank + .init_balance(storage, &owner, init_funds) + .unwrap(); + router.bank.set_remote(remote_channel()); + router.wasm.set_remote(remote_channel()); + }) + .with_remote(remote_channel()); // set up reflect contract let reflect_id = app.store_code(reflect::contract()); @@ -1710,7 +1714,6 @@ mod custom_messages { mod protobuf_wrapped_data { use super::*; - use crate::BasicApp; #[test] fn instantiate_wrapped_properly() { @@ -1719,15 +1722,15 @@ mod protobuf_wrapped_data { // set personal balance let init_funds = vec![coin(20, "btc")]; - let mut app = - custom_app::(remote_channel(), |router, _, storage| { - router - .bank - .init_balance(storage, &owner, init_funds) - .unwrap(); - router.bank.set_remote(remote_channel()); - router.wasm.set_remote(remote_channel()); - }); + let mut app = custom_app::(|router, _, storage| { + router + .bank + .init_balance(storage, &owner, init_funds) + .unwrap(); + router.bank.set_remote(remote_channel()); + router.wasm.set_remote(remote_channel()); + }) + .with_remote(remote_channel()); // set up reflect contract let code_id = app.store_code(reflect::contract()); diff --git a/src/wasm.rs b/src/wasm.rs index e96137f9..487f5405 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -181,6 +181,7 @@ pub trait Wasm: AllWasmQuerier + ContainsRemote { } pub type LocalRustContract = *mut dyn Contract; +/// A structure representing a default wasm keeper. pub struct WasmKeeper { /// Contract codes that stand for wasm code in real-life blockchain. pub code_base: RefCell>,