From 0e50b350f6bf5850b9ba052da828bedb000adbff Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 9 Oct 2023 15:11:58 +0200 Subject: [PATCH 1/6] Extended Api trait. --- src/api.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++++ src/app.rs | 3 +- src/app_builder.rs | 3 +- src/lib.rs | 1 + 4 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 src/api.rs diff --git a/src/api.rs b/src/api.rs new file mode 100644 index 00000000..0bb18c02 --- /dev/null +++ b/src/api.rs @@ -0,0 +1,75 @@ +use cosmwasm_std::{Addr, Api, CanonicalAddr, RecoverPubkeyError, StdResult, VerificationError}; + +pub trait TestApi: Api { + fn addr_make(&self, input: &str) -> Addr; +} + +#[derive(Default)] +pub struct MockApi(cosmwasm_std::testing::MockApi); + +impl Api for MockApi { + fn addr_validate(&self, input: &str) -> StdResult { + self.0.addr_validate(input) + } + + fn addr_canonicalize(&self, input: &str) -> StdResult { + self.0.addr_canonicalize(input) + } + + 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 TestApi for MockApi { + #[cfg(not(feature = "cosmwasm_1_5"))] + fn addr_make(&self, input: &str) -> Addr { + Addr::unchecked(input) + } + #[cfg(feature = "cosmwasm_1_5")] + fn addr_make(&self, input: &str) -> Addr { + self.0.addr_make(input) + } +} diff --git a/src/app.rs b/src/app.rs index 7f6d1804..072ea69a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,3 +1,4 @@ +use crate::api::MockApi; use crate::bank::{Bank, BankKeeper, BankSudo}; use crate::contracts::Contract; use crate::error::{bail, AnyResult}; @@ -9,7 +10,7 @@ use crate::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking, Sta use crate::transactions::transactional; use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; use crate::AppBuilder; -use cosmwasm_std::testing::{MockApi, MockStorage}; +use cosmwasm_std::testing::MockStorage; use cosmwasm_std::{ from_slice, to_binary, Addr, Api, Binary, BlockInfo, ContractResult, CosmosMsg, CustomQuery, Empty, GovMsg, IbcMsg, IbcQuery, Querier, QuerierResult, QuerierWrapper, QueryRequest, Record, diff --git a/src/app_builder.rs b/src/app_builder.rs index e59579bb..818e9b5a 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -1,10 +1,11 @@ //! Implementation of the builder for [App]. +use crate::api::MockApi; use crate::{ App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingModule, Gov, Ibc, Module, Router, StakeKeeper, Staking, Wasm, WasmKeeper, }; -use cosmwasm_std::testing::{mock_env, MockApi, MockStorage}; +use cosmwasm_std::testing::{mock_env, MockStorage}; use cosmwasm_std::{Api, BlockInfo, CustomQuery, Empty, GovMsg, IbcMsg, IbcQuery, Storage}; use schemars::JsonSchema; use serde::de::DeserializeOwned; diff --git a/src/lib.rs b/src/lib.rs index 1d90986c..d468210a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ //! //! To understand the design of this module, please refer to `../DESIGN.md` +mod api; mod app; mod app_builder; mod bank; From d9fb3fc3150384b4e095a190ecb23c04143d78a8 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 9 Oct 2023 15:45:04 +0200 Subject: [PATCH 2/6] Refactoring. --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index a180c73b..0121d042 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,9 @@ 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"] +# enable the below feature when the cosmwams 1.5 is published +# update also the dependency version to 1.5.0 +#cosmwasm_1_5 = ["cosmwasm_1_4", "cosmwasm-std/cosmwasm_1_5"] [dependencies] cw-utils = "1.0.2" From eea2d5859b8aa75a8d8a2676e8e451d368b2c49f Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 9 Oct 2023 17:07:43 +0200 Subject: [PATCH 3/6] Working example with extended Api trait. --- Cargo.toml | 12 +- src/api.rs | 4 +- src/app.rs | 6 +- src/app_builder.rs | 4 +- src/lib.rs | 1 + src/tests/app.rs | 56 +++++++- tests/app_builder/mod.rs | 1 + tests/app_builder/with_api.rs | 253 ++++++++++++++++++++++++++++++++++ 8 files changed, 317 insertions(+), 20 deletions(-) create mode 100644 tests/app_builder/with_api.rs diff --git a/Cargo.toml b/Cargo.toml index 0121d042..0422ec2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,17 +23,17 @@ cosmwasm_1_4 = ["cosmwasm_1_3", "cosmwasm-std/cosmwasm_1_4"] #cosmwasm_1_5 = ["cosmwasm_1_4", "cosmwasm-std/cosmwasm_1_5"] [dependencies] -cw-utils = "1.0.2" -cw-storage-plus = "1.1.0" +anyhow = "1.0.75" cosmwasm-std = { version = "1.4.0", features = ["staking", "stargate"] } +cw-storage-plus = "1.1.0" +cw-utils = "1.0.2" +derivative = "2.2.0" itertools = "0.11.0" +prost = "0.12.1" schemars = "0.8.15" serde = { version = "1.0.188", default-features = false, features = ["derive"] } -prost = "0.12.1" -anyhow = "1.0.75" -thiserror = "1.0.49" -derivative = "2.2.0" sha2 = "0.10.8" +thiserror = "1.0.49" [dev-dependencies] once_cell = "1.18.0" diff --git a/src/api.rs b/src/api.rs index 0bb18c02..204edc4d 100644 --- a/src/api.rs +++ b/src/api.rs @@ -65,8 +65,8 @@ impl Api for MockApi { impl TestApi for MockApi { #[cfg(not(feature = "cosmwasm_1_5"))] - fn addr_make(&self, input: &str) -> Addr { - Addr::unchecked(input) + fn addr_make(&self, _input: &str) -> Addr { + unimplemented!() } #[cfg(feature = "cosmwasm_1_5")] fn addr_make(&self, input: &str) -> Addr { diff --git a/src/app.rs b/src/app.rs index 072ea69a..656e4a9c 100644 --- a/src/app.rs +++ b/src/app.rs @@ -9,7 +9,7 @@ use crate::module::{FailingModule, Module}; use crate::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking, StakingSudo}; use crate::transactions::transactional; use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; -use crate::AppBuilder; +use crate::{AppBuilder, TestApi}; use cosmwasm_std::testing::MockStorage; use cosmwasm_std::{ from_slice, to_binary, Addr, Api, Binary, BlockInfo, ContractResult, CosmosMsg, CustomQuery, @@ -166,7 +166,7 @@ impl where WasmT: Wasm, BankT: Bank, - ApiT: Api, + ApiT: TestApi, StorageT: Storage, CustomT: Module, StakingT: Staking, @@ -223,7 +223,7 @@ impl App where BankT: Bank, - ApiT: Api, + ApiT: TestApi, StorageT: Storage, CustomT: Module, WasmT: Wasm, diff --git a/src/app_builder.rs b/src/app_builder.rs index 818e9b5a..d4d7e112 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -3,7 +3,7 @@ use crate::api::MockApi; use crate::{ App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingModule, Gov, Ibc, Module, - Router, StakeKeeper, Staking, Wasm, WasmKeeper, + Router, StakeKeeper, Staking, TestApi, Wasm, WasmKeeper, }; use cosmwasm_std::testing::{mock_env, MockStorage}; use cosmwasm_std::{Api, BlockInfo, CustomQuery, Empty, GovMsg, IbcMsg, IbcQuery, Storage}; @@ -446,7 +446,7 @@ where ) -> App where BankT: Bank, - ApiT: Api, + ApiT: TestApi, StorageT: Storage, CustomT: Module, WasmT: Wasm, diff --git a/src/lib.rs b/src/lib.rs index d468210a..c81fa5b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,6 +25,7 @@ mod tests; mod transactions; mod wasm; +pub use crate::api::TestApi; pub use crate::app::{custom_app, next_block, App, BasicApp, CosmosRouter, Router, SudoMsg}; pub use crate::app_builder::{AppBuilder, BasicAppBuilder}; pub use crate::bank::{Bank, BankKeeper, BankSudo}; diff --git a/src/tests/app.rs b/src/tests/app.rs index a22b9415..68d59cd2 100644 --- a/src/tests/app.rs +++ b/src/tests/app.rs @@ -1,3 +1,4 @@ +use crate::api::TestApi; use crate::app::no_init; use crate::custom_handler::CachingCustomHandler; use crate::error::{bail, AnyResult}; @@ -5,11 +6,12 @@ use crate::test_helpers::echo::EXECUTE_REPLY_BASE_ID; use crate::test_helpers::{caller, echo, error, hackatom, payout, reflect, CustomMsg}; 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, }; -use cosmwasm_std::testing::{mock_env, MockApi, MockQuerier}; +use cosmwasm_std::testing::{mock_env, MockQuerier}; use cosmwasm_std::{ coin, coins, from_slice, to_binary, Addr, AllBalanceResponse, Api, Attribute, BankMsg, BankQuery, Binary, BlockInfo, Coin, CosmosMsg, CustomQuery, Empty, Event, OverflowError, @@ -1631,22 +1633,19 @@ mod wasm_queries { mod custom_messages { use super::*; - use crate::AppBuilder; #[test] fn triggering_custom_msg() { - let api = MockApi::default(); - let sender = api.addr_validate("sender").unwrap(); - let owner = api.addr_validate("owner").unwrap(); - let custom_handler = CachingCustomHandler::::new(); let custom_handler_state = custom_handler.state(); let mut app = AppBuilder::new_custom() - .with_api(api) .with_custom(custom_handler) .build(no_init); + let sender = app.api().addr_validate("sender").unwrap(); + let owner = app.api().addr_validate("owner").unwrap(); + let contract_id = app.store_code(echo::custom_contract()); let contract = app @@ -1972,3 +1971,46 @@ 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] + fn api_addr_canonicalize_should_work() { + let app = App::default(); + let canonical = app.api().addr_canonicalize("creator").unwrap(); + assert!(!canonical.to_string().is_empty()); + } + + #[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"); + } + + #[test] + #[cfg(not(feature = "cosmwasm_1_5"))] + #[should_panic(expected = "not implemented")] + fn api_addr_make_should_panic() { + let app = App::default(); + app.api().addr_make("creator"); + } + + #[test] + #[cfg(feature = "cosmwasm_1_5")] + fn api_addr_make_should_panic() { + let app = App::default(); + assert_eq!( + app.api().addr_make("creator"), + "cosmwasm1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqs8s7vcp" + ); + } +} diff --git a/tests/app_builder/mod.rs b/tests/app_builder/mod.rs index 2aba8b89..74cc55a8 100644 --- a/tests/app_builder/mod.rs +++ b/tests/app_builder/mod.rs @@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize}; use std::fmt::Debug; use std::marker::PhantomData; +mod with_api; mod with_bank; mod with_block; mod with_distribution; diff --git a/tests/app_builder/with_api.rs b/tests/app_builder/with_api.rs new file mode 100644 index 00000000..c1d9e06e --- /dev/null +++ b/tests/app_builder/with_api.rs @@ -0,0 +1,253 @@ +use cosmwasm_std::{Addr, Api, CanonicalAddr, RecoverPubkeyError, StdResult, VerificationError}; +use cw_multi_test::{AppBuilder, TestApi}; + +struct MyApi {} + +impl Api for MyApi { + fn addr_validate(&self, _human: &str) -> StdResult { + Ok(Addr::unchecked("custom-validate")) + } + + fn addr_canonicalize(&self, _human: &str) -> StdResult { + Ok(CanonicalAddr::from(b"custom-canonicalize")) + } + + fn addr_humanize(&self, _canonical: &CanonicalAddr) -> StdResult { + Ok(Addr::unchecked("custom-humanize")) + } + + fn secp256k1_verify( + &self, + _message_hash: &[u8], + _signature: &[u8], + _public_key: &[u8], + ) -> Result { + unimplemented!() + } + + fn secp256k1_recover_pubkey( + &self, + _message_hash: &[u8], + _signature: &[u8], + _recovery_param: u8, + ) -> Result, RecoverPubkeyError> { + unimplemented!() + } + + fn ed25519_verify( + &self, + _message: &[u8], + _signature: &[u8], + _public_key: &[u8], + ) -> Result { + unimplemented!() + } + + fn ed25519_batch_verify( + &self, + _messages: &[&[u8]], + _signatures: &[&[u8]], + _public_keys: &[&[u8]], + ) -> Result { + unimplemented!() + } + + fn debug(&self, message: &str) { + println!("{}", message) + } +} + +impl TestApi for MyApi { + fn addr_make(&self, input: &str) -> Addr { + Addr::unchecked(input) + } +} + +#[test] +fn building_app_with_custom_api_should_work() { + let app = AppBuilder::default().with_api(MyApi {}).build(|_, _, _| {}); + assert_eq!( + app.api().addr_validate("creator").unwrap(), + Addr::unchecked("custom-validate") + ); + assert_eq!( + app.api().addr_canonicalize("creator").unwrap(), + CanonicalAddr::from(b"custom-canonicalize") + ); + assert_eq!( + app.api().addr_humanize(&CanonicalAddr::from(&[1])).unwrap(), + Addr::unchecked("custom-humanize") + ) +} + +struct MyTestApi {} + +impl Api for MyTestApi { + fn addr_validate(&self, _human: &str) -> StdResult { + Ok(Addr::unchecked("custom-validate-test-api")) + } + + fn addr_canonicalize(&self, _human: &str) -> StdResult { + Ok(CanonicalAddr::from(b"custom-canonicalize-test-api")) + } + + fn addr_humanize(&self, _canonical: &CanonicalAddr) -> StdResult { + Ok(Addr::unchecked("custom-humanize-test-api")) + } + + fn secp256k1_verify( + &self, + _message_hash: &[u8], + _signature: &[u8], + _public_key: &[u8], + ) -> Result { + unimplemented!() + } + + fn secp256k1_recover_pubkey( + &self, + _message_hash: &[u8], + _signature: &[u8], + _recovery_param: u8, + ) -> Result, RecoverPubkeyError> { + unimplemented!() + } + + fn ed25519_verify( + &self, + _message: &[u8], + _signature: &[u8], + _public_key: &[u8], + ) -> Result { + unimplemented!() + } + + fn ed25519_batch_verify( + &self, + _messages: &[&[u8]], + _signatures: &[&[u8]], + _public_keys: &[&[u8]], + ) -> Result { + unimplemented!() + } + + fn debug(&self, message: &str) { + println!("{}", message) + } +} + +impl TestApi for MyTestApi { + fn addr_make(&self, input: &str) -> Addr { + Addr::unchecked(input) + } +} + +#[test] +fn building_app_with_custom_test_api_should_work() { + let app = AppBuilder::default() + .with_api(MyTestApi {}) + .build(|_, _, _| {}); + assert_eq!( + app.api().addr_validate("creator").unwrap(), + Addr::unchecked("custom-validate-test-api") + ); + assert_eq!( + app.api().addr_canonicalize("creator").unwrap(), + CanonicalAddr::from(b"custom-canonicalize-test-api") + ); + assert_eq!( + app.api().addr_humanize(&CanonicalAddr::from(&[1])).unwrap(), + Addr::unchecked("custom-humanize-test-api") + ); + assert_eq!(app.api().addr_make("creator"), Addr::unchecked("creator")) +} + +struct MyExtendedApi {} + +impl MyExtendedApi { + fn my_extension(&self) -> &'static str { + "my-extension" + } +} + +impl Api for MyExtendedApi { + fn addr_validate(&self, _human: &str) -> StdResult { + Ok(Addr::unchecked("custom-validate-extended-api")) + } + + fn addr_canonicalize(&self, _human: &str) -> StdResult { + Ok(CanonicalAddr::from(b"custom-canonicalize-extended-api")) + } + + fn addr_humanize(&self, _canonical: &CanonicalAddr) -> StdResult { + Ok(Addr::unchecked("custom-humanize-extended-api")) + } + + fn secp256k1_verify( + &self, + _message_hash: &[u8], + _signature: &[u8], + _public_key: &[u8], + ) -> Result { + unimplemented!() + } + + fn secp256k1_recover_pubkey( + &self, + _message_hash: &[u8], + _signature: &[u8], + _recovery_param: u8, + ) -> Result, RecoverPubkeyError> { + unimplemented!() + } + + fn ed25519_verify( + &self, + _message: &[u8], + _signature: &[u8], + _public_key: &[u8], + ) -> Result { + unimplemented!() + } + + fn ed25519_batch_verify( + &self, + _messages: &[&[u8]], + _signatures: &[&[u8]], + _public_keys: &[&[u8]], + ) -> Result { + unimplemented!() + } + + fn debug(&self, message: &str) { + println!("{}", message) + } +} + +impl TestApi for MyExtendedApi { + fn addr_make(&self, input: &str) -> Addr { + Addr::unchecked(input) + } +} + +#[test] +fn building_app_with_custom_extended_api_should_work() { + let app = AppBuilder::default() + .with_api(MyExtendedApi {}) + .build(|_, _, _| {}); + assert_eq!( + app.api().addr_validate("creator").unwrap(), + Addr::unchecked("custom-validate-extended-api") + ); + assert_eq!( + app.api().addr_canonicalize("creator").unwrap(), + CanonicalAddr::from(b"custom-canonicalize-extended-api") + ); + assert_eq!( + app.api().addr_humanize(&CanonicalAddr::from(&[1])).unwrap(), + Addr::unchecked("custom-humanize-extended-api") + ); + assert_eq!(app.api().addr_make("creator"), Addr::unchecked("creator")); + + assert_eq!(app.api().my_extension(), "my-extension"); +} From 32c4a060cbbb17a63739efe4a2c7897e67fb0cd0 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Mon, 9 Oct 2023 17:55:42 +0200 Subject: [PATCH 4/6] Working example without extending Api trait. --- Cargo.lock | 28 +++--- Cargo.toml | 4 +- src/api.rs | 75 -------------- src/app.rs | 9 +- src/app_builder.rs | 7 +- src/lib.rs | 2 - src/tests/app.rs | 11 +-- tests/app_builder/with_api.rs | 181 +--------------------------------- 8 files changed, 29 insertions(+), 288 deletions(-) delete mode 100644 src/api.rs diff --git a/Cargo.lock b/Cargo.lock index 090cadc2..71c62fa9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -129,9 +129,9 @@ checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" [[package]] name = "cosmwasm-crypto" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca101fbf2f76723711a30ea3771ef312ec3ec254ad021b237871ed802f9f175" +checksum = "a6fb22494cf7d23d0c348740e06e5c742070b2991fd41db77bba0bcfbae1a723" dependencies = [ "digest 0.10.7", "ed25519-zebra", @@ -142,18 +142,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c73d2dd292f60e42849d2b07c03d809cf31e128a4299a805abd6d24553bcaaf5" +checksum = "6e199424486ea97d6b211db6387fd72e26b4a439d40cc23140b2d8305728055b" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce34a08020433989af5cc470104f6bd22134320fe0221bd8aeb919fd5ec92d5" +checksum = "fef683a9c1c4eabd6d31515719d0d2cc66952c4c87f7eb192bfc90384517dc34" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -164,9 +164,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96694ec781a7dd6dea1f968a2529ade009c21ad999c88b5f53d6cc495b3b96f7" +checksum = "9567025acbb4c0c008178393eb53b3ac3c2e492c25949d3bf415b9cbe80772d8" dependencies = [ "proc-macro2", "quote", @@ -175,9 +175,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a44d3f9c25b2f864737c6605a98f2e4675d53fd8bbc7cf4d7c02475661a793d" +checksum = "7d89d680fb60439b7c5947b15f9c84b961b88d1f8a3b20c4bd178a3f87db8bae" dependencies = [ "base64", "bnum", @@ -508,9 +508,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.148" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "memchr" @@ -560,9 +560,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b1106fec09662ec6dd98ccac0f81cef56984d0b49f75c92d8cbad76e20c005c" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] diff --git a/Cargo.toml b/Cargo.toml index 0422ec2c..03716de3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,12 +19,12 @@ 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"] # enable the below feature when the cosmwams 1.5 is published -# update also the dependency version to 1.5.0 #cosmwasm_1_5 = ["cosmwasm_1_4", "cosmwasm-std/cosmwasm_1_5"] [dependencies] anyhow = "1.0.75" -cosmwasm-std = { version = "1.4.0", features = ["staking", "stargate"] } +# update also the dependency version to 1.5.0 +cosmwasm-std = { version = "1.4.1", features = ["staking", "stargate"] } cw-storage-plus = "1.1.0" cw-utils = "1.0.2" derivative = "2.2.0" diff --git a/src/api.rs b/src/api.rs deleted file mode 100644 index 204edc4d..00000000 --- a/src/api.rs +++ /dev/null @@ -1,75 +0,0 @@ -use cosmwasm_std::{Addr, Api, CanonicalAddr, RecoverPubkeyError, StdResult, VerificationError}; - -pub trait TestApi: Api { - fn addr_make(&self, input: &str) -> Addr; -} - -#[derive(Default)] -pub struct MockApi(cosmwasm_std::testing::MockApi); - -impl Api for MockApi { - fn addr_validate(&self, input: &str) -> StdResult { - self.0.addr_validate(input) - } - - fn addr_canonicalize(&self, input: &str) -> StdResult { - self.0.addr_canonicalize(input) - } - - 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 TestApi for MockApi { - #[cfg(not(feature = "cosmwasm_1_5"))] - fn addr_make(&self, _input: &str) -> Addr { - unimplemented!() - } - #[cfg(feature = "cosmwasm_1_5")] - fn addr_make(&self, input: &str) -> Addr { - self.0.addr_make(input) - } -} diff --git a/src/app.rs b/src/app.rs index 656e4a9c..7f6d1804 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,4 +1,3 @@ -use crate::api::MockApi; use crate::bank::{Bank, BankKeeper, BankSudo}; use crate::contracts::Contract; use crate::error::{bail, AnyResult}; @@ -9,8 +8,8 @@ use crate::module::{FailingModule, Module}; use crate::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking, StakingSudo}; use crate::transactions::transactional; use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo}; -use crate::{AppBuilder, TestApi}; -use cosmwasm_std::testing::MockStorage; +use crate::AppBuilder; +use cosmwasm_std::testing::{MockApi, MockStorage}; use cosmwasm_std::{ from_slice, to_binary, Addr, Api, Binary, BlockInfo, ContractResult, CosmosMsg, CustomQuery, Empty, GovMsg, IbcMsg, IbcQuery, Querier, QuerierResult, QuerierWrapper, QueryRequest, Record, @@ -166,7 +165,7 @@ impl where WasmT: Wasm, BankT: Bank, - ApiT: TestApi, + ApiT: Api, StorageT: Storage, CustomT: Module, StakingT: Staking, @@ -223,7 +222,7 @@ impl App where BankT: Bank, - ApiT: TestApi, + ApiT: Api, StorageT: Storage, CustomT: Module, WasmT: Wasm, diff --git a/src/app_builder.rs b/src/app_builder.rs index d4d7e112..e59579bb 100644 --- a/src/app_builder.rs +++ b/src/app_builder.rs @@ -1,11 +1,10 @@ //! Implementation of the builder for [App]. -use crate::api::MockApi; use crate::{ App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingModule, Gov, Ibc, Module, - Router, StakeKeeper, Staking, TestApi, Wasm, WasmKeeper, + Router, StakeKeeper, Staking, Wasm, WasmKeeper, }; -use cosmwasm_std::testing::{mock_env, MockStorage}; +use cosmwasm_std::testing::{mock_env, MockApi, MockStorage}; use cosmwasm_std::{Api, BlockInfo, CustomQuery, Empty, GovMsg, IbcMsg, IbcQuery, Storage}; use schemars::JsonSchema; use serde::de::DeserializeOwned; @@ -446,7 +445,7 @@ where ) -> App where BankT: Bank, - ApiT: TestApi, + ApiT: Api, StorageT: Storage, CustomT: Module, WasmT: Wasm, diff --git a/src/lib.rs b/src/lib.rs index c81fa5b3..1d90986c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,6 @@ //! //! To understand the design of this module, please refer to `../DESIGN.md` -mod api; mod app; mod app_builder; mod bank; @@ -25,7 +24,6 @@ mod tests; mod transactions; mod wasm; -pub use crate::api::TestApi; pub use crate::app::{custom_app, next_block, App, BasicApp, CosmosRouter, Router, SudoMsg}; pub use crate::app_builder::{AppBuilder, BasicAppBuilder}; pub use crate::bank::{Bank, BankKeeper, BankSudo}; diff --git a/src/tests/app.rs b/src/tests/app.rs index 68d59cd2..a2317e44 100644 --- a/src/tests/app.rs +++ b/src/tests/app.rs @@ -1,4 +1,3 @@ -use crate::api::TestApi; use crate::app::no_init; use crate::custom_handler::CachingCustomHandler; use crate::error::{bail, AnyResult}; @@ -1996,17 +1995,9 @@ mod api { assert_eq!(app.api().addr_humanize(&canonical).unwrap(), "creator"); } - #[test] - #[cfg(not(feature = "cosmwasm_1_5"))] - #[should_panic(expected = "not implemented")] - fn api_addr_make_should_panic() { - let app = App::default(); - app.api().addr_make("creator"); - } - #[test] #[cfg(feature = "cosmwasm_1_5")] - fn api_addr_make_should_panic() { + fn api_addr_make_should_work() { let app = App::default(); assert_eq!( app.api().addr_make("creator"), diff --git a/tests/app_builder/with_api.rs b/tests/app_builder/with_api.rs index c1d9e06e..e9afc0af 100644 --- a/tests/app_builder/with_api.rs +++ b/tests/app_builder/with_api.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{Addr, Api, CanonicalAddr, RecoverPubkeyError, StdResult, VerificationError}; -use cw_multi_test::{AppBuilder, TestApi}; +use cw_multi_test::AppBuilder; struct MyApi {} @@ -57,9 +57,9 @@ impl Api for MyApi { } } -impl TestApi for MyApi { - fn addr_make(&self, input: &str) -> Addr { - Addr::unchecked(input) +impl MyApi { + fn my_api_extension(&self) -> &'static str { + "my-api-extension" } } @@ -77,177 +77,6 @@ fn building_app_with_custom_api_should_work() { assert_eq!( app.api().addr_humanize(&CanonicalAddr::from(&[1])).unwrap(), Addr::unchecked("custom-humanize") - ) -} - -struct MyTestApi {} - -impl Api for MyTestApi { - fn addr_validate(&self, _human: &str) -> StdResult { - Ok(Addr::unchecked("custom-validate-test-api")) - } - - fn addr_canonicalize(&self, _human: &str) -> StdResult { - Ok(CanonicalAddr::from(b"custom-canonicalize-test-api")) - } - - fn addr_humanize(&self, _canonical: &CanonicalAddr) -> StdResult { - Ok(Addr::unchecked("custom-humanize-test-api")) - } - - fn secp256k1_verify( - &self, - _message_hash: &[u8], - _signature: &[u8], - _public_key: &[u8], - ) -> Result { - unimplemented!() - } - - fn secp256k1_recover_pubkey( - &self, - _message_hash: &[u8], - _signature: &[u8], - _recovery_param: u8, - ) -> Result, RecoverPubkeyError> { - unimplemented!() - } - - fn ed25519_verify( - &self, - _message: &[u8], - _signature: &[u8], - _public_key: &[u8], - ) -> Result { - unimplemented!() - } - - fn ed25519_batch_verify( - &self, - _messages: &[&[u8]], - _signatures: &[&[u8]], - _public_keys: &[&[u8]], - ) -> Result { - unimplemented!() - } - - fn debug(&self, message: &str) { - println!("{}", message) - } -} - -impl TestApi for MyTestApi { - fn addr_make(&self, input: &str) -> Addr { - Addr::unchecked(input) - } -} - -#[test] -fn building_app_with_custom_test_api_should_work() { - let app = AppBuilder::default() - .with_api(MyTestApi {}) - .build(|_, _, _| {}); - assert_eq!( - app.api().addr_validate("creator").unwrap(), - Addr::unchecked("custom-validate-test-api") ); - assert_eq!( - app.api().addr_canonicalize("creator").unwrap(), - CanonicalAddr::from(b"custom-canonicalize-test-api") - ); - assert_eq!( - app.api().addr_humanize(&CanonicalAddr::from(&[1])).unwrap(), - Addr::unchecked("custom-humanize-test-api") - ); - assert_eq!(app.api().addr_make("creator"), Addr::unchecked("creator")) -} - -struct MyExtendedApi {} - -impl MyExtendedApi { - fn my_extension(&self) -> &'static str { - "my-extension" - } -} - -impl Api for MyExtendedApi { - fn addr_validate(&self, _human: &str) -> StdResult { - Ok(Addr::unchecked("custom-validate-extended-api")) - } - - fn addr_canonicalize(&self, _human: &str) -> StdResult { - Ok(CanonicalAddr::from(b"custom-canonicalize-extended-api")) - } - - fn addr_humanize(&self, _canonical: &CanonicalAddr) -> StdResult { - Ok(Addr::unchecked("custom-humanize-extended-api")) - } - - fn secp256k1_verify( - &self, - _message_hash: &[u8], - _signature: &[u8], - _public_key: &[u8], - ) -> Result { - unimplemented!() - } - - fn secp256k1_recover_pubkey( - &self, - _message_hash: &[u8], - _signature: &[u8], - _recovery_param: u8, - ) -> Result, RecoverPubkeyError> { - unimplemented!() - } - - fn ed25519_verify( - &self, - _message: &[u8], - _signature: &[u8], - _public_key: &[u8], - ) -> Result { - unimplemented!() - } - - fn ed25519_batch_verify( - &self, - _messages: &[&[u8]], - _signatures: &[&[u8]], - _public_keys: &[&[u8]], - ) -> Result { - unimplemented!() - } - - fn debug(&self, message: &str) { - println!("{}", message) - } -} - -impl TestApi for MyExtendedApi { - fn addr_make(&self, input: &str) -> Addr { - Addr::unchecked(input) - } -} - -#[test] -fn building_app_with_custom_extended_api_should_work() { - let app = AppBuilder::default() - .with_api(MyExtendedApi {}) - .build(|_, _, _| {}); - assert_eq!( - app.api().addr_validate("creator").unwrap(), - Addr::unchecked("custom-validate-extended-api") - ); - assert_eq!( - app.api().addr_canonicalize("creator").unwrap(), - CanonicalAddr::from(b"custom-canonicalize-extended-api") - ); - assert_eq!( - app.api().addr_humanize(&CanonicalAddr::from(&[1])).unwrap(), - Addr::unchecked("custom-humanize-extended-api") - ); - assert_eq!(app.api().addr_make("creator"), Addr::unchecked("creator")); - - assert_eq!(app.api().my_extension(), "my-extension"); + assert_eq!(app.api().my_api_extension(), "my-api-extension"); } From c8681a07a75202269fe805d10eaeb594eb1d9a63 Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 10 Oct 2023 09:26:56 +0200 Subject: [PATCH 5/6] Refactoring. --- Cargo.toml | 4 ++-- src/tests/app.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 03716de3..25abdf09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,12 +18,12 @@ 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"] -# enable the below feature when the cosmwams 1.5 is published +# enable the feature below when the cosmwams 1.5 is published #cosmwasm_1_5 = ["cosmwasm_1_4", "cosmwasm-std/cosmwasm_1_5"] [dependencies] anyhow = "1.0.75" -# update also the dependency version to 1.5.0 +# update also the dependency version to 1.5.0 when published cosmwasm-std = { version = "1.4.1", features = ["staking", "stargate"] } cw-storage-plus = "1.1.0" cw-utils = "1.0.2" diff --git a/src/tests/app.rs b/src/tests/app.rs index a2317e44..b5c19d38 100644 --- a/src/tests/app.rs +++ b/src/tests/app.rs @@ -1982,10 +1982,11 @@ mod api { } #[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!(!canonical.to_string().is_empty()); + assert_eq!(canonical.to_string(), "0000000000000000000000000000726F0000000000000000000000000000000000000000006572000000000000000000000000000000000000000000610000000000000000000000000000000000000000006374000000000000"); } #[test] From 6d1984b8332c491cbf98dc4673958fb224f4c03b Mon Sep 17 00:00:00 2001 From: Dariusz Depta Date: Tue, 10 Oct 2023 11:14:52 +0200 Subject: [PATCH 6/6] Prepared custom Api test with Bech32. --- Cargo.lock | 7 +++ Cargo.toml | 6 +-- src/tests/app.rs | 10 ---- tests/app_builder/with_api.rs | 97 +++++++++++++++++++++++++++-------- 4 files changed, 87 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 71c62fa9..41738198 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,6 +70,12 @@ version = "1.6.0" 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" + [[package]] name = "block-buffer" version = "0.9.0" @@ -242,6 +248,7 @@ name = "cw-multi-test" version = "0.17.0" dependencies = [ "anyhow", + "bech32", "cosmwasm-std", "cw-storage-plus", "cw-utils", diff --git a/Cargo.toml b/Cargo.toml index 25abdf09..b60962db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,12 +18,9 @@ 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"] -# enable the feature below when the cosmwams 1.5 is published -#cosmwasm_1_5 = ["cosmwasm_1_4", "cosmwasm-std/cosmwasm_1_5"] [dependencies] anyhow = "1.0.75" -# update also the dependency version to 1.5.0 when published cosmwasm-std = { version = "1.4.1", features = ["staking", "stargate"] } cw-storage-plus = "1.1.0" cw-utils = "1.0.2" @@ -36,7 +33,10 @@ sha2 = "0.10.8" thiserror = "1.0.49" [dev-dependencies] +bech32 = "0.9.1" once_cell = "1.18.0" +sha2 = "0.10.8" + # We don't use these dependencies directly, # we tighten versions that builds with `-Zminimal-versions` work. ecdsa = "0.16.8" diff --git a/src/tests/app.rs b/src/tests/app.rs index b5c19d38..4043bacb 100644 --- a/src/tests/app.rs +++ b/src/tests/app.rs @@ -1995,14 +1995,4 @@ mod api { let canonical = app.api().addr_canonicalize("creator").unwrap(); assert_eq!(app.api().addr_humanize(&canonical).unwrap(), "creator"); } - - #[test] - #[cfg(feature = "cosmwasm_1_5")] - fn api_addr_make_should_work() { - let app = App::default(); - assert_eq!( - app.api().addr_make("creator"), - "cosmwasm1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqs8s7vcp" - ); - } } diff --git a/tests/app_builder/with_api.rs b/tests/app_builder/with_api.rs index e9afc0af..ed8a2502 100644 --- a/tests/app_builder/with_api.rs +++ b/tests/app_builder/with_api.rs @@ -1,19 +1,54 @@ -use cosmwasm_std::{Addr, Api, CanonicalAddr, RecoverPubkeyError, StdResult, VerificationError}; +use bech32::{decode, encode, FromBase32, ToBase32, Variant}; +use cosmwasm_std::{ + Addr, Api, CanonicalAddr, HexBinary, RecoverPubkeyError, StdError, StdResult, VerificationError, +}; use cw_multi_test::AppBuilder; +use sha2::{Digest, Sha256}; -struct MyApi {} +struct MyApi { + prefix: &'static str, +} + +impl MyApi { + fn new(prefix: &'static str) -> Self { + Self { prefix } + } +} impl Api for MyApi { - fn addr_validate(&self, _human: &str) -> StdResult { - Ok(Addr::unchecked("custom-validate")) + fn addr_validate(&self, input: &str) -> StdResult { + let canonical = self.addr_canonicalize(input)?; + let normalized = self.addr_humanize(&canonical)?; + if input != normalized { + Err(StdError::generic_err( + "Invalid input: address not normalized", + )) + } else { + Ok(Addr::unchecked(input)) + } } - fn addr_canonicalize(&self, _human: &str) -> StdResult { - Ok(CanonicalAddr::from(b"custom-canonicalize")) + fn addr_canonicalize(&self, input: &str) -> StdResult { + if let Ok((prefix, decoded, Variant::Bech32)) = decode(input) { + if prefix == self.prefix { + if let Ok(bytes) = Vec::::from_base32(&decoded) { + return Ok(bytes.into()); + } + } + } + Err(StdError::generic_err("Invalid input")) } - fn addr_humanize(&self, _canonical: &CanonicalAddr) -> StdResult { - Ok(Addr::unchecked("custom-humanize")) + fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { + if let Ok(encoded) = encode( + self.prefix, + canonical.as_slice().to_base32(), + Variant::Bech32, + ) { + Ok(Addr::unchecked(encoded)) + } else { + Err(StdError::generic_err("Invalid canonical address")) + } } fn secp256k1_verify( @@ -52,31 +87,53 @@ impl Api for MyApi { unimplemented!() } - fn debug(&self, message: &str) { - println!("{}", message) + fn debug(&self, _message: &str) { + unimplemented!() } } impl MyApi { - fn my_api_extension(&self) -> &'static str { - "my-api-extension" + fn addr_make(&self, input: &str) -> Addr { + let digest = Sha256::digest(input).to_vec(); + match encode(self.prefix, digest.to_base32(), Variant::Bech32) { + Ok(address) => Addr::unchecked(address), + Err(reason) => panic!("Generating address failed with reason: {reason}"), + } } } #[test] fn building_app_with_custom_api_should_work() { - let app = AppBuilder::default().with_api(MyApi {}).build(|_, _, _| {}); + // prepare test data + let human = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp"; + let hex = "bc6bfd848ebd7819c9a82bf124d65e7f739d08e002601e23bb906aacd40a3d81"; + + // create application with custom api that implements + // Bech32 address encoding with 'juno' prefix + let app = AppBuilder::default() + .with_api(MyApi::new("juno")) + .build(|_, _, _| {}); + + // check address validation function assert_eq!( - app.api().addr_validate("creator").unwrap(), - Addr::unchecked("custom-validate") + app.api().addr_validate(human).unwrap(), + Addr::unchecked(human) ); + + // check if address can be canonicalized assert_eq!( - app.api().addr_canonicalize("creator").unwrap(), - CanonicalAddr::from(b"custom-canonicalize") + app.api().addr_canonicalize(human).unwrap(), + CanonicalAddr::from(HexBinary::from_hex(hex).unwrap()) ); + + // check if address can be humanized assert_eq!( - app.api().addr_humanize(&CanonicalAddr::from(&[1])).unwrap(), - Addr::unchecked("custom-humanize") + app.api() + .addr_humanize(&app.api().addr_canonicalize(human).unwrap()) + .unwrap(), + Addr::unchecked(human) ); - assert_eq!(app.api().my_api_extension(), "my-api-extension"); + + // check extension function for creating Bech32 encoded addresses + assert_eq!(app.api().addr_make("creator"), Addr::unchecked(human)); }